2016-10-15 55 views
-2

不能真正遵循下面的類型推論,案例1工作但案例2失敗,爲什麼?如何關注Haskell中的類型推斷?

ghci> :t sqrt . maximum . map (+1) -- case 1 

(Floating c, Ord c) => [c] -> c 

ghci> :t sqrt . maximum . map length -- case 2 

Could not deduce (Floating Int) arising from a use of ‘sqrt’ 
from the context (Foldable t) 
bound by the inferred type of it :: Foldable t => [t a] -> Int 

@EDIT

在OOP,Num是後容易下界其所有subtypes例如IntFloat。因此,如果Num是合格類型,則Int將被推斷爲可接受,但反之亦然。

此外,在類似C的語言中,內置的數字轉換可以自動滿足從較低精度到較高精度的情況。從IntFloat。相比之下,在Haskell上HM type system,Num對於其所有instances例如是class。例如Intsubclasses,例如Floating。合格類型可以在祖先和後代之間進行雙向推理,例如,從NumInt,Floating或反之亦然,但不在IntFloating之間。

爲了補救殼體2,Int應首先被適配成通過NumfromIntegral施加Data.List.genericLength產生Num - 的推論限定類型爲Floatingsqrt需要。

讓我們將上述各點遵循以下類型推論,

ghci> :t (+) 
Num a => a -> a -> a 

ghci> :t 1.1 
Fractional a => a 

ghci> :i Fractional 
class Num a => Fractional a 
instance Fractional Float 
instance Fractional Double 

ghci> :t 1 
Num a => a 

ghci> :t length [1] 
Int 

ghci> :i Int 
instance Num Int  
instance Real Int 
instance Integral Int 

ghci> :t 1.1 + 1   -- case 1 
Fractional a => a 

ghci> :t 1.1 + length [1] -- case 2 
No instance for (Fractional Int) arising from the literal ‘1.1’ 
+1

'length'函數返回一個'Int',但'sqrt'需要一個帶有'Floating'實例的類型。嘗試使用'Data中的'genericLength'。而是使用'Num'實例來產生任何類型的List。 –

+0

你的摘要是不正確的。類型類不是類型。您不能將數值從Int轉換爲Int,或將Int轉換爲Floating。這些是蘋果和桔子。類型類約束一個類型。例如,您可能有'Floating a => a - > a - > a''這表示'a'必須有一個Floating實例。 '浮動'確實,'詮釋'不。 – erisco

+0

@erisco,這個觀點是'type inference',我的措詞可能會誤導你想'type class'和'type'之間的轉換等。 – sof

回答

4

1可以是任何類型的號碼和+可以與任何類型的號碼工作。 maximum也是如此。因此maximum . map (+1)是一個函數,它可以取任何類型的數字列表併產生與其結果相同類型的數字。這包括整數和浮點數。

但是length將特別產生Int。它不能產生任何其他類型的數字。因此maximum . map length可以採取任何列表併產生類型爲Int的結果,而不是任何其他數字類型。

現在sqrt需要它的參數爲浮點數。因此,在第一種情況下,類型推斷會指出您必須提供一個浮點數列表,因此maximum . map (+1)的結果將是一個浮點數,可以傳遞給sqrt

但是,第二種情況根本無法工作,因爲Int不是浮點類型,而maximum . map length不能產生除Int以外的任何內容。所以這會導致錯誤。

您可以使用fromIntegral函數將length的結果轉換爲任何數字類型以使第二個代碼生效。

+0

你可以看看我編輯的帖子,看看它是否被正確地總結了嗎?謝謝! – sof