2012-05-15 29 views
23

Tôi tin rằng người ta có thể định nghĩa hiệp phương sai (ít nhất, đối với các đối tượng) là 'khả năng sử dụng giá trị của một loại hẹp hơn (phụ) thay cho một giá trị của một số loại (siêu) rộng hơn', và contravariance đó là chính xác ngược lại điều này. Rõ ràng, các hàm Scala là các thể hiện của hàm [-A1, ..., + B] cho các kiểu tham số contravariant A1, vv và kiểu trả về covariant, B. Trong khi điều này rất tiện lợi cho việc gõ phụ vào Hàm, không nên định nghĩa trên có nghĩa là tôi có thể truyền bất kỳ siêu kiểu nào làm tham số?Tại sao hàm [-A1, ..., + B] không cho phép bất kỳ siêu kiểu nào làm tham số?

Vui lòng cho biết nơi tôi bị nhầm lẫn.

Trả lời

56

Hiệp phương sai và đối nghịch là những phẩm chất của loại không phải là chất lượng của thông số. (Họ là những phẩm chất mà phụ thuộc vào các thông số, nhưng họ lập báo cáo về các lớp học.)

Vì vậy, Function1[-A,+B] nghĩa là một hàm rằng mất superclasses của A có thể được xem như là một lớp con của chức năng ban đầu.

Hãy xem này trong thực tế:

class A 
class B extends A 
val printB: B => Unit = { b => println("Blah blah") } 
val printA: A => Unit = { a => println("Blah blah blah") } 

Bây giờ giả sử bạn cần một chức năng mà biết làm thế nào để in một B:

def needsB(f: B => Unit, b: B) = f(b) 

Bạn có thể vượt qua trong printB. Nhưng bạn cũng có thể cũng chuyển vượt qua trong printA vì nó cũng biết cách in B s (và nhiều hơn nữa!), Giống như nếu A => Unit là một phân lớp của B => Unit. Đây là chính xác những gì contravariance có nghĩa là. Điều đó không có nghĩa là bạn có thể vượt qua Option[Double] vào printB và nhận bất kỳ điều gì ngoài lỗi biên dịch!

(Hiệp phương sai là trường hợp khác:. M[B] <: M[A] nếu B <: A)

+0

Cảm ơn bạn, điều đó rất rõ ràng. Cố gắng (lại) xác định: 'co/contra-variance là các thuộc tính quyết định mối quan hệ kiểu con giữa các kiểu, tùy thuộc vào bản chất của cùng quan hệ giữa các kiểu thành phần của chúng'. Tóm lại, tôi biết, nhưng tôi thích có một định nghĩa không có ví dụ (mặc dù bạn đã rất hữu ích). – bjt38

+0

cảm ơn cho -A, bạn có thể giải thích tại sao là + B trong hàm1 [-A, + B] – liango

+0

@liango - Anexplanation bằng ví dụ: nếu bạn trả về một 'Chuỗi' bạn chắc chắn trả về một' Object', vì vậy '. .. => String' phải là một lớp con của '... => Object'. Đó là những gì '+ B' biểu thị. –

4

Có hai ý tưởng riêng biệt tại nơi làm việc tại đây. Một là sử dụng subtyping để cho phép các đối số cụ thể hơn được chuyển đến một hàm (được gọi là subsumption). Khác là làm thế nào để kiểm tra subtyping về chức năng mình.

Để kiểm tra kiểu đối số cho hàm, bạn chỉ phải kiểm tra xem đối số đã cho là kiểu con của các loại đối số được khai báo. Kết quả cũng phải là một kiểu con của kiểu khai báo. Đây là nơi bạn thực sự kiểm tra subtyping.

Contra/co-variance của các tham số & kết quả chỉ yếu tố khi bạn muốn kiểm tra xem một loại hàm cho trước là một loại phụ của một loại hàm khác. Vì vậy, nếu tham số có loại Function[A1, ... ,B], thì đối số phải là loại hàm Function[C1, ..., D] trong đó A1 <: C1 ...D <: B.

Lý do này không cụ thể đối với Scala và áp dụng cho các ngôn ngữ được nhập tĩnh khác có loại phụ.

-1

hiệp biến có nghĩa là chuyển đổi từ rộng hơn (siêu) để hẹp (phụ).Ví dụ, chúng tôi có hai lớp: một là động vật (siêu) và một là mèo khác sau đó sử dụng biến đổi, chúng ta có thể chuyển đổi động vật cho mèo.

Contra-variant là đối diện của biến thể, có nghĩa là mèo với động vật.

Bất biến có nghĩa là không thể chuyển đổi.

18

Câu hỏi này là cũ, nhưng tôi nghĩ rằng một giải thích rõ ràng hơn là gọi Nguyên tắc thay thế Liskov: mọi thứ đúng về một siêu lớp phải đúng với tất cả các lớp con của nó. Bạn sẽ có thể làm với một SubFoo tất cả mọi thứ mà bạn có thể làm với một Foo, và có thể nhiều hơn nữa.

Giả sử chúng tôi có Calico <: Cat <: Động vật và Husky <: Chó <: Động vật. Hãy xem một số Function[Cat, Dog]. Những tuyên bố nào là đúng về điều này? Có hai:

(1) Bạn có thể vượt qua trong bất kỳ Cát (vì vậy bất kỳ lớp con của Cát)

(2) Bạn có thể gọi bất kỳ phương pháp Chó trên giá trị trả về

Vì vậy, hiện Function[Calico, Dog] <: Function[Cat, Dog] có ý nghĩa ? Không, các câu lệnh đúng với siêu lớp không đúng với lớp con, cụ thể là câu lệnh (1). Bạn không thể chuyển bất kỳ con mèo nào vào một chức năng mà chỉ có mèo Calico.

Nhưng không Function[Animal, Dog] <: Function[Cat, Dog] có ý nghĩa? Có, tất cả các câu lệnh về lớp cha đều đúng với lớp con. Tôi vẫn có thể vượt qua bất kỳ con mèo nào - trên thực tế tôi có thể làm nhiều hơn thế, tôi có thể vượt qua bất kỳ Động vật nào - và tôi có thể gọi tất cả các phương thức Dog trên giá trị trả về.

Vì vậy A <: B ngụ ý Function[B, _] <: Function[A, _]

Bây giờ, không Function[Cat, Husky] <: Function[Cat, Dog] có ý nghĩa? Có, tất cả các câu lệnh về lớp cha đều đúng với lớp con; Tôi vẫn có thể vượt qua trong một con mèo, và tôi vẫn có thể gọi tất cả các phương pháp Dog trên giá trị trả về - trên thực tế tôi có thể làm nhiều hơn thế, tôi có thể gọi tất cả các phương thức Husky trên giá trị trả về.

Nhưng không Function[Cat, Animal] <: Function[Cat, Dog] có ý nghĩa? Không, các câu lệnh đúng với siêu lớp không đúng với lớp con, cụ thể là câu lệnh (2). Tôi không thể gọi tất cả các phương thức có sẵn trên Dog trên giá trị trả về, chỉ có các phương thức có sẵn trên Animal.

Vì vậy, với Function[Animal, Husky] Tôi có thể làm mọi thứ tôi có thể làm với Function[Cat, Dog]: Tôi có thể chuyển vào bất kỳ Mèo nào và tôi có thể gọi tất cả các phương thức Dog trên giá trị trả lại. Và tôi có thể làm nhiều hơn nữa: Tôi có thể vượt qua những con vật khác, và tôi có thể gọi những phương pháp có sẵn trên Husky mà không có sẵn trên Chó. Vì vậy, nó có ý nghĩa: Function[Animal, Husky] <: Function[Cat, Dog]. Tham số kiểu đầu tiên có thể được thay thế bằng một siêu lớp, tham số thứ hai với một lớp con.

+0

Tôi làm cách nào để kiểm tra <: lập trình với các ví dụ bạn đã cung cấp? –

Các vấn đề liên quan