2015-07-05 42 views
1

我已經嘗試了無數谷歌搜索的答案,但是對哈斯克爾來說很新,我不明白我找到的一半東西,另一半隻是不太相關。Haskell不能推斷類型?

我的問題是這樣的,如果我跑了ghci這些語句

Prelude> let x = 5 :: (Num a) => a 
Prelude> sqrt x 

我得到了我期望

2.23606797749979 

但是,如果我把這個文件和編譯(當然是我「M這裏做的是相當瑣碎)

sqrtNum :: (Num a, Floating b) => a -> b 
sqrtNum x = sqrt x 

我得到這個

myfile.hs:2:18: 
    Could not deduce (a ~ b) 
    from the context (Num a, Floating b) 
     bound by the type signature for 
       sqrtNum :: (Num a, Floating b) => a -> b 
     at test2.hs:1:12-40 
     `a' is a rigid type variable bound by 
      the type signature for sqrtNum :: (Num a, Floating b) => a -> b 
      at test2.hs:1:12 
     `b' is a rigid type variable bound by 
      the type signature for sqrtNum :: (Num a, Floating b) => a -> b 
      at test2.hs:1:12 
    Relevant bindings include 
     x :: a (bound at test2.hs:2:9) 
     sqrtNum :: a -> b (bound at test2.hs:2:1) 
    In the first argument of `sqrt', namely `x' 
    In the expression: sqrt x 

該問題可能非常簡單,我只是監督它(因爲這是我遇到的每一個其他錯誤的經驗),但這只是不點擊。

在此先感謝!

+1

您的類型聲明可以將一種類型的數字「a」轉換爲另一種類型的「b」。但'sqrt'不這樣做。 –

回答

7

你說的是你有一個從數字a到浮動b的函數。 sqrt函數需要一個浮點類型作爲輸入,但你只能保證Num。這裏的開方類型:

Main> :t sqrt 
sqrt :: Floating a => a -> a 

所以,讓我們複製開方和浮動浮動使這個FTN:

sqrtNum :: (Num a, Floating a) => a -> a 
sqrtNum x = sqrt x 

我離開了民,雖然只需要浮動。 Floating is a Fractional, and Fractional is a Num.

3

如果這還不夠清楚,讓我們先看看「引擎蓋下」。類型類是一種語法糖的形式,Haskell在類型級別存儲函數庫。因此Typeclass約束可以簡單地作爲附加的參數來實現,這些參數可以隱式傳遞。例如,如果我寫:

class Truthy a where 
    truthy :: a -> Bool 

instance Truthy Integer where 
    truthy = (== 0) 

instance Truthy Bool where 
    truthy = id 

那麼我們可以這樣定義一個函數:

maybeTruthy :: Truthy x => x -> Maybe x 
maybeTruthy x | truthy x = Just x 
       | otherwise = Nothing 

這裏的關鍵是,我做的是完全一樣的,因爲這稍微令人費解的代碼:

data Truthifier x = Truthifier {truthify :: x -> Bool} 

boolTruthifier :: Truthifier Bool 
boolTruthifier = Truthifier id 

integerTruthifier :: Truthifier Integer 
integerTruthifier = Truthifier (== 0) 

maybeTruthified :: Truthifier x -> x -> Maybe x 
maybeTruthified lib x | truthify lib x = Just x 
         | otherwise  = Nothing 

唯一的區別是,Haskell有有效的約束,例如,boolTruthifierBool類型,所以我並不需要顯式傳遞給maybeTruthy,因爲它通過參數的類型Bool來「乘坐」。上面我可以很容易地定義notTruthifier = Truthifier not,我可以用maybeTruthified notTruthifier而不是maybeTruthified boolTruthifier開始做事。例如,爲什麼Haskell默認禁止instance (Num a) => Truthy a,而你必須改寫newtype TruthNum x = TruthNum x,然後instance (Num a) => Truthy (TruthNum a):Haskell必須有一個頂級類型來註冊該函數庫;如果你給它(Num a) => Truthy a那麼它有沒有更好的地方把它比a - 也就是說,所有的功能 - 而在後一種情況下,把它直接作用於TruthNum類型和只使用它時,x也有字典爲Num功能。

如何sqrt適合所有這一切:在GHCI你會發現的sqrt類型是:

Prelude> :t sqrt 
sqrt :: Floating a => a -> a 

換句話說,sqrt可以在任何類型的值來完成,如果該類型爲其定義了Floating字典。其sqrt返回相同類型的值,因爲簽名是a -> a

您試過寫(Num a, Floating b) => a -> b。這是比定義實際允許的更寬容的類型。