2013-08-23 44 views
8

對存在類型的混淆不大。Scala中的Existensial類型

這個工作對我來說:

def valueOf(c: Class[_], name: String) { 
    type C = Class[T] forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[C], name) 
} 

但這並不:

def valueOf(c: Class[_], name: String) { 
    type T = T forSome {type T <: Enum[T]} 
    Enum.valueOf(c.asInstanceOf[Class[T]], name) 
} 

在我的腦海裏兩個表達式等價於:

Enum.valueOf(z.asInstanceOf[Class[T] forSome {type T <: Enum[T]}], name) 

但是斯卡拉說,這是在我的心只:

inferred type arguments [T] do not conform to method valueOf's type parameter bounds [T <: Enum[T]] 
     Enum.valueOf(c.asInstanceOf[Class[T]], name) 
      ^

回答

5

考慮以下兩個表達式之間的區別:

Enum.valueOf(x.asInstanceOf[Class[X] forSome { type X <: Enum[X] }], name) 

和:

Enum.valueOf(x.asInstanceOf[Class[X forSome { type X <: Enum[X] }]], name) 

現在想想怎樣類型參數的valueOfT將在每種情況來推斷。在第一種情況下,我們得到了一個X,我們知道它是Enum[X]的一個子類型,並且我們都設置了。另一方面,在第二種情況下,T必須是X forSome { type X <: Enum[X] },並且關鍵的是這種類型不是Enum[X forSome { type X <: Enum[X] }]的子類型,所以我們還沒有滿足對T的限制。

問題是,你的第二個例子相當於後者。


作爲一個註腳,如果Enum在其類型參數進行了協變這會工作得很好。看看下面簡單的例子:

trait Foo[A] 
trait Bar[A] 

def foo[A <: Bar[A]](f: Foo[A]) = f 

def x: Foo[X] forSome { type X <: Bar[X] } = ??? 
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ??? 

現在foo(x)將編譯,但foo(y)不會,就像在你的代碼。但有點改變Bar

trait Foo[A] 
trait Bar[+A] 

def foo[A <: Bar[A]](f: Foo[A]) = f 

def x: Foo[X] forSome { type X <: Bar[X] } = ??? 
def y: Foo[Y forSome { type Y <: Bar[Y] }] = ??? 

現在他們都會編譯。我猜想這與我們對你的兩個例子具有如此強烈的直覺是相同的原因有關。


作爲另一個註腳(響應gzmocomment below),考慮以下因素:

scala> trait Foo[A <: Foo[A]] 
defined trait Foo 

scala> class MyFoo extends Foo[MyFoo] 
defined class MyFoo 

scala> val myFoo = new MyFoo 
myFoo: MyFoo = [email protected] 

scala> myFoo: (X forSome { type X <: Foo[X] }) 
res0: X forSome { type X <: Foo[X] } = [email protected] 

scala> myFoo: Foo[MyFoo] 
res1: Foo[MyFoo] = [email protected] 

讓我們假設X forSome { type X <: Foo[X] }Foo[X forSome { type X <: Foo[X] }](暫時忽略這樣一個事實:亞型後者甚至不是有效的類型)。然後我們就可以寫:

myFoo: Foo[X forSome { type X <: Foo[X] }] 

Foo是不變的,所以如果我們有一些東西,這既是Foo[A]Foo[B]的實例,那麼它必須是這樣的情況A =:= B。但絕對不是這種情況,MyFoo =:= (X forSome { type X <: Foo[X] })。不確定所有這一切都不那麼令人困惑,但是我確信編譯器知道它在這裏做了什麼。

+0

我不明白爲什麼'X forSome {X型<:枚舉[X]}'不是'枚舉亞型[X forSome {X型<:枚舉[X]}]'(在我的腦海,'X <:Enum [X]'並且遞歸地應用相同的約束)。你可以解釋嗎?我們是否遇到F結合多態性的奇怪限制之一? – gzm0

+0

@ gzm0:我的更新有幫助嗎? –