Để hiểu điều gì đang xảy ra, hãy xem các phiên bản đơn giản của TestA.test
và TestB.test
.
object TestA {
def test1(a: A[String]) = {
val s: String = a.find(0)
a.fill(s)
}
}
object TestB {
def test1(b: B[String]) = {
val r: b.R = b.find(0)
b.fill(r)
}
}
Chú ý cách loại giá trị trung gian s
đề cập đến String
, trong khi các loại giá trị trung gian r
không.
object TestA {
def test2(a: A[F] forSome {type F}) = {
val s: F forSome {type F} = a.find(0)
// type mismatch;
// found : s.type (with underlying type F forSome { type F })
// required: F
a.fill(s)
}
}
object TestB {
def test2(b: B[F] forSome {type F}) = {
val r: b.R = b.find(0)
b.fill(r)
}
}
Một khi chúng ta vứt trong existentials, chúng tôi kết thúc với một giá trị trung gian s
có loại tương đương với Any
, và do đó mà không phải là một đầu vào hợp lệ cho a.fill
. Tuy nhiên, loại trung gian cho r
vẫn là b.R
và do đó, nó vẫn là đầu vào thích hợp cho b.fill
. Lý do loại của nó vẫn còn là b.R
là vì b.R
không đề cập đến F
, và vì vậy theo the simplification rules for existential types, b.R forSome {type F}
tương đương với b.R
, trong cùng một cách mà Int forSome {type F}
tương đương với Int
.
Một trong hai lỗi này là gì?
Vâng, chắc chắn có lỗi ở đâu đó (như của scalac 2.11.7), vì sau đây không nhập kiểm tra.
object TestB {
def test3(b: B[F] forSome {type F}) = {
val r: b.R forSome {type F} = b.find(0)
// type mismatch;
// found : F
// required: b.R
// (which expands to) F
b.fill(r)
}
}
Vì vậy, hoặc tôi là sai lầm khi nghĩ rằng b.R
không đề cập đến F
, trong trường hợp b.R forSome {type F}
không tương đương với b.R
và TestB.test
bạn không nên gõ kiểm tra nhưng nó, hoặc b.R forSome {type F}
được equivalalent để b.R
, trong trường hợp này, TestB.test3
của tôi nên nhập séc nhưng không.
Tôi khá thuyết phục rằng lỗi là với sau này, bởi vì lỗi thậm chí xảy ra khi định lượng hiện tại không có gì để làm với b.R
, như trong ví dụ sau.
object TestB {
def test4(b: B[F] forSome {type F}) = {
val r: b.R forSome {val x: Int} = b.find(0)
// type mismatch;
// found : F
// required: b.R
// (which expands to) F
b.fill(r)
}
}