2009-07-26 54 views
8

Giả sử tôi có hai lớp, InputOutput, được thiết kế để kết nối với nhau. Output tạo ra các giá trị của một số loại và Input tiêu thụ chúng.Tại sao Scala không thể suy ra tham số kiểu trong ví dụ này?

class Input[T] { 
    var output: Option[Output[_ <: T]] = None 
} 
class Output[T] { 
    var input: Option[Input[_ >: T]] = None 
} 

Không sao đâu nếu một InputOutput cặp không hoạt động trên cùng một loại giá trị càng lâu càng kiểu tham số Input là một siêu kiểu của tham số Output loại. Lưu ý rằng tham số kiểu trong cả hai lớp là bất biến; trong các phiên bản thực, nó được sử dụng ở cả hai vị trí đồng và contravariant.

Tôi có một phương pháp connect nơi khác mà thiết lập một mối liên hệ giữa một cặp Input/Output:

def connect[T](output: Output[T], input: Input[_ >: T]) = { 
    output.input = Some(input) 
    input.output = Some(output) 
} 

Nếu tôi gọi phương pháp này như sau, tôi nhận được một lỗi type:

val out = new Output[String] 
val in = new Input[AnyRef] 
connect(out, in) 

Lỗi này là:

test.scala:17: error: type mismatch; 
found : Output[String] 
required: Output[AnyRef] 
    connect(out, in) 
     ^

Tôi có thể giải quyết điều này bằng cách viết ra các tham số kiểu (trong trường hợp này, tôi sẽ viết connect[String], nhưng tôi nghĩ rằng trình biên dịch sẽ có thể tìm ra điều này cho tôi. Làm thế nào tôi có thể thay đổi phương thức connect để tham số kiểu được suy ra tự động?


Edit: Còn bây giờ, tôi đã thực hiện connect một phương pháp Output vì vậy nó được tham số kiểu tự động. Điều này cũng có thêm lợi ích mà tôi có thể sử dụng các ký hiệu infix out connect in, nhưng thiết kế cảm thấy một chút khó xử.

Tôi vẫn quan tâm đến lý do trình biên dịch thể hiện hành vi này. Tôi cảm thấy như nó sẽ có thể suy ra các tham số kiểu. Điều này có thực sự hoạt động như được chỉ định không?

+0

bạn có nghĩa là "không hoạt động * trên * cùng một loại giá trị" –

+0

bạn đã thử đặt câu hỏi vào danh sách gửi thư của Scala chưa? – GClaramunt

Trả lời

6

Đôi khi bạn sẽ nhận được kết quả tốt hơn nếu bạn sử dụng nhiều danh sách tham số:

def connect[T](output: Output[T])(input: Input[_ >: T]) = { 
    output.input = Some(input) 
    input.output = Some(output) 
} 

connect(out)(in) 

... và thực sự trong trường hợp này, nó hoạt động.

+3

Bạn có thể mở rộng vì lý do này không? * "đôi khi có được kết quả tốt hơn" * không âm thanh rất xác định! –

+6

Đáng buồn thay, loại inferencer không phải là spec'ed, và đôi khi không phải là xác định hoặc. –

0

Tôi có thể hoàn toàn sai, nhưng tôi nghĩ vấn đề là khi bạn kết hợp đầu vào và đầu ra: đầu vào có đầu ra bị giới hạn ở một loại phụ T, nhưng đầu ra có đầu vào bị hạn chế với siêu kiểu T, loại duy nhất có thể thỏa mãn cả hai điều kiện là T.

Input[T] -> Output[ _ <: T ] 
Output[Q] -> Input[ _ >: Q ] 

Khi bạn tạo các đầu vào với đầu ra (thay thế Q với _ <: T) bạn nhận được:

Input[T]->Input[ _ >: [_ <: T] ] 

Giống như

Input [T] -> Input [_ <: T <: _]

Do đó loại không khớp

+0

Trong ví dụ của tôi, String và AnyRef đáp ứng các ràng buộc của tôi. Đầu ra tạo ra các chuỗi và yêu cầu một đầu vào tiêu thụ một số siêu kiểu chuỗi. Đầu vào tiêu thụ AnyRef và yêu cầu đầu ra tạo ra một số kiểu con của AnyRef. Vì String là một kiểu con của AnyRef, các ràng buộc được thỏa mãn. –

+0

Vấn đề là có chính xác một tham số kiểu thích hợp cho kết nối, và đó là tham số kiểu của đầu ra. Khi tôi xác định rõ ràng điều này, nó hoạt động tốt. Nếu tôi không, nó sẽ cố gắng sử dụng tham số kiểu của đầu vào, và tôi nhận được một lỗi kiểu trên đối số đầu ra. –

+0

Xin lỗi, tôi đã đọc sai mục nhập [_>: T] trong chữ ký của kết nối [T] ( – GClaramunt

0

Trên thực tế, loại inferene scala không thể xử lý "đệ quy" cho bây giờ. Vì vậy, nếu loại đối số có thể được suy luận chỉ trong sắp xếp thứ tự với scala đối số khác không suy luận. Nhưng nếu bạn sử dụng danh sách đối số differal scala f(a)(b)(c,d) sẽ suy ra danh sách các loại theo danh sách, vì vậy nó hoạt động tốt hơn.

PS Nó quá đơn giản, nhưng có thể giúp bạn có được một số đầu mối.

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