2017-05-14 81 views
3
trait foo[F] { 
    def test: F 
} 

class ah extends foo[(Int,Int) => Int] { 
    def test = (i: Int,j: Int) => i+j 
} 

所以問題是,爲什麼斯卡拉知道如此聰明的類型不能只是從test的類型推斷出(Int,Int) => Int類型,而是問我而不是指定它?或者它仍然有可能?或者,也許這是由我想不到的一些想法支持的。爲什麼Scala不會推斷特徵類型參數?

回答

7

你的問題基本上是「爲什麼斯卡拉只有本地類型推斷」或等價地「爲什麼斯卡拉不具有非本地類型推斷」。答案是:因爲設計師不想。

這有幾個原因。其中一個原因是對局部類型推斷最合理的選擇是全局類型推斷,但在Scala中這是不可能的:Scala具有單獨的編譯和模塊化類型檢查,因此編譯器無法全面瞭解整個程序。實際上,Scala具有動態代碼加載,這意味着在編譯時整個代碼甚至不需要存在!全球類型推斷在Scala中根本不可能。我們所能做的最好的是「整體編譯單元類型推斷」,但這也是不受歡迎的:這意味着您是否需要類型註釋取決於您是以多個單元還是僅以一個單元編譯代碼。

另一個重要的原因是模塊邊界處的類型註釋用作雙重檢查,有點像類型的複式簿記。請注意,即使在語言像Haskell這樣的全局類型推斷中,強烈建議在模塊邊界和公共接口上放置類型註釋。

第三個原因是,全球類型推斷有時會導致出現錯誤消息時,而不是類型檢查的類型註釋失敗,類型inferencer快樂地推斷越來越無意義的類型一班班,直到它最後放棄在遠離實際錯誤(這可能只是一個簡單的錯字)的位置,並且類型錯誤僅與錯誤網站的原始類型相切。例如,這有時可能發生在Haskell中。 Scala設計人員非常重視有用的錯誤消息,以至於他們願意犧牲語言功能,除非他們能夠弄清楚如何使用良好的錯誤消息來實現它們。 (請注意,即使Scala的非常有限的類型推斷,你可以得到的「預期Foo得到了Product with Serializable」這樣的「有用」的消息。)

然而,什麼Scala的局部類型推理可以在這個例子做,是爲了工作在另一個方向上,並且從返回類型的test推斷的參數類型的匿名函數:

trait foo[F] { 
    def test: F 
} 

class ah extends foo[(Int, Int) ⇒ Int] { 
    def test = (i, j) ⇒ i + j 
} 

(new ah) test(2, 3) //=> 5 
+0

因此,Hindley-Milner能夠從'test'推斷'foo'的類型嗎? – slouc

+0

斯卡拉有子類型,H-M不支持。 (與許多函數式語言不同,Scala的類型系統與HM很不相稱)。但是在假設的語言中,使用全局類型推斷並且沒有子類型和運算符重載,是的,應該可以用零註釋來推斷所有類型:推斷「i ''和'j'和匿名函數的返回類型是來自'+'運算符的整數(記住:沒有運算符重載),推斷'test'的類型是匿名函數的函數類型,推斷'F'成爲'test'的返回類型。我認爲。 –

+0

是的,我同意推斷'test',我只是想知道它是否可以使用這些信息來推斷'foo'。 TBH我甚至不知道在H-M中是否支持/允許使用標準類類結構(沒有子類型部分;只是一個簡單的類型參數化類,它有一個返回該類型的方法)。 – slouc

1

對於你特定示例中,推斷類型參數基於繼承可以是不明確的:

trait A 
trait B extends A 

trait Foo[T] { 
    val x: T 
} 

trait Bar extends Foo[?] { 
    val x: B 
} 

可以在?中輸入的類型可以是AB。這是Scala不會推斷可能不明確的類型的一般示例。

現在,你是正確的觀察,有

class Foo[T](x: T) 

trait Foo[T] { x: T } 

我已經看到了一些工作納入可能概括的相似性(但我似乎無法之間的相似性現在找到它)。理論上,這可以允許基於成員的類型參數的類型推斷。但我不知道它是否會達到這一點。

+0

難道那是在Dotty?我的意思是,Dotty沒有泛型,他們解析爲抽象類型成員。即特質Foo [T]; class IntFoo extends Foo [Int]'實際上是'trait Foo {type T};類IntFoo在Dotty中擴展Foo {override type T = Int}'。 –

+0

通過這個參數,它也不應該推斷'def x = new B'的返回類型:它的類型也可以是'A'或'B'(或者'Object'或者'Any')。 –

+0

@AlexeyRomanov你是對的。不同之處在於特徵可以隨後擴展,所以類型參數既是上限又是下限。這就是爲什麼推斷最合適的最窄類型並不安全。 – Owen

相關問題