2013-04-02 66 views
2
object Test { 

    trait Foo 

    trait TC[A] 

    object TC { 
    implicit def tc1[F <: Foo] = new TC[F] {} 
    implicit def tc2[F1 <: Foo, F2 <: Foo] = new TC[(F1, F2)] {} 
    } 

    object Bar { 
    trait X 
    val c = new Foo with X 
    def bar[A](a: this.type => A)(implicit tc: TC[A]) = 1 
    } 

    Bar bar (_.c) 

    Bar bar (b => (b.c, b.c)) 
} 

最後一行給編譯器錯誤「無法找到參數tc ...的隱式值」。內在特徵突破隱含參數

現在:移動trait X以外的object Bar使它的工作。

接下來的最後一行適用於這兩種情況。

這是否有什麼好的理由,和/或是否有可能在不將物體移出物體的情況下工作?

回答

2

這不會是一個完整的答案(並且包含大量的猜測),但是鑑於你到現在爲止我沒有得到任何答案,我想它總比沒有好。

看來,問題在於,編譯器在new Foo with X對待X的路徑依賴型的,即使我們是在一個對象定義,而不是一類的事實。 因此,編譯器會在第二次調用bar時推斷出A = (Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }。 這需要編譯器找到TC[(Test.Foo with b.X, Test.Foo with b.X) forSome { val b: Test.Bar.type }]類型的隱式值,顯然tc2是不合適的(我對scala類型系統的角落案例不夠熟悉,以確定是否存在真正的不兼容性,或者編譯器只是沒有線索)

[投機模式]

與相關的路徑型裝卸的問題聞起來像我(或至少一個尚未得以異類)中的錯誤。我認爲罪魁禍首是一個對象的主體編譯沒有不同於一個類,並且然後以某種方式被製成一個單例對象,這意味着new Foo with X真的被看作爲new Foo with this.X而不是new Foo with Bar.X,因此被視爲一個路徑依賴類型(即使他們應該恕我直言,在這種情況下表示同樣的事情)。

[/投機模式]

現在的怪異的一部分(這也是工作都是圍繞你的要求):打開此:

val c = new Foo with X 

成這樣:

val c = new Foo with Bar.X 

實際上修復了編譯。據我瞭解,這是因爲通過明確指定Bar我們強制編譯器認識到Bar.X是一個穩定的路徑,它清除了路徑相關類型的問題。

現在,真正的解決方法當然是按照您的建議,在Bar之外真正地移動X。它工作並且無痛,所以爲什麼不這樣做呢?

+0

謝謝,有趣的猜測。對於你的最後一個問題,不幸的是,在我的非最小化版本中,保持內在特徵是至關重要的。 :) –