2016-01-18 67 views
2

代碼輸入奧祕。爲什麼要編譯這段代碼?

default() 
h :: Bool 
h = 1.0 == 1.0 --Error. Ambiguity. 

不能編譯。這是預料之中的,因爲有歧義。它可以是FloatDouble,Haskell不知道我們想要哪一個。

但代碼

default() 
foo :: (Fractional a, Eq a) => a -> Bool 
foo x = x == 1.0 

編譯成功。我不完全明白爲什麼。爲什麼這也不明確?

我有一種感覺,這是因爲每當我們稱之爲foo,我們都保證有回升代替a,即具體類型,我們都保證有固定aFloatDouble(或我們的定製型兩種在編譯時具有FractionalEq的實例),因此不存在歧義。

但這只是一種感覺,我不知道它是否100%準確。

+2

@Carsten兩者都不在'Eq'中;這是非法的,因爲選擇一個可以給出與其他結果不同的結果(當然,這個程序當然不會,但編譯器不會,也不應該知道這一點)。 –

+0

@AlexeyRomanov好後悔...... – Carsten

+6

你能說仔細爲什麼這不是一個重複的[您剛纔的問題(http://stackoverflow.com/q/34776282/791604)? –

回答

10

在此上下文歧義的定義在Section 4.3.4 of Haskell Report給出:

我們說一個表達式e具有一個不明確的類型,如果在它的類型forall us. cx => t,存在us可變u一種類型發生在cx但不在t。這種類型是無效的。

foo :: (Fractional a, Eq a) => a -> Bool,不存在這樣的變量(因爲發生在a -> Boola)。在1.0 == 1.0這個類型實際上是(Fractional a, Eq a) => Bool,所以有這樣一個變量。

原因這種不確定性的一個錯誤是因爲沒有辦法對編譯器的變量a的不同實例之間進行選擇,程序的結果可能取決於哪一個選擇。在這種情況下,1.0 == 1.0應始終爲True,對於任何合理的實例化,但1)編譯器不知道這一點; 2)並非所有實例都是合理的。

4

代碼的第二片編譯因爲

foo :: (Fractional a, Eq a) => a -> Bool 
foo x = x == 1.0 

(==) :: Eq a => a -> a 

所以編譯器將知道該浮點數字面1.0 :: Rational a => a具有相同的類型與x,其具有Eq實例即,在該所述的==「意義」函數對於每個調用都是確定性的。

在第一段代碼中,文字可以是任何類型(Rational a, Eq a) => a,因此==的「含義」是不明確的,h的值可以是True或False,取決於文字的類型,沒有提供。

0

Here'a另一個概念的方式把它:

這兩種情況都具有內在的不確定性,但第一個是死路一條 - 沒有希望編譯器來推斷它的出路的模糊性。

第二種情況是還明確,但模糊是開放 - 誰呼叫曖昧代碼,必須進一步解決的模糊性,或代表/氣泡它調用堆棧向上。

這一切就是這麼簡單 - 多態性控制歧義。第一種情況是不受控制的模糊性,所以它沒有用(即多態性相關)歧義。所以它被拒絕,直到它被註釋爲明確。