2016-11-25 35 views
2

這是一個學習的榜樣你一個Haskell,對高階函數一章:哈斯克爾,多類型的類一個參數

compareWithHundred :: (Num a, Ord a) => a -> Ordering 
compareWithHundred x = compare 100 x 

雖然功能的思路是清晰的對我來說,我不知道爲什麼類型簽名是(Num a,Ord a)。我們只傳遞要與Int類型的函數進行比較的整數。 Ord在這裏代表什麼,爲什麼在類型簽名中隱式傳遞參數?

回答

9

這不是簽名的唯一可能的簽名。它恰好是一個最通用的之一。 compareWithHundred :: Int -> Ordering實際上是一個可能的實例 - 多態a參數可以用任何數量的訂購類型,並果然包括Int,也IntegerRationalDouble被instatiated ...

Prelude> let compareWithHundred :: (Num a, Ord a) => a -> Ordering; compareWithHundred x = compare 100 x 
Prelude> compareWithHundred (99 :: Int) 
GT 
Prelude> compareWithHundred (100.3 :: Double) 
LT 

的所有數字類型允許你訂購 - 雖然比較它們 - 這是不可能的經典例子是複雜的數字(它有「多個方向」,你可以訂購它們)。

Prelude Data.Complex> compareWithHundred (100 :+ 30 :: Complex Double) 

<interactive>:10:1: 
    No instance for (Ord (Complex Double)) 
     arising from a use of ‘compareWithHundred’ 
    In the expression: compareWithHundred (100 :+ 30 :: Complex Double) 
    In an equation for ‘it’: 
     it = compareWithHundred (100 :+ 30 :: Complex Double) 

因此,您需要同時需要的參數是一個數字(所以存在一個值100,與比較),而取值Ord類。這個組合約束寫成(Num a, Ord a)

5

我有些事要補充,以防你無法從leftaroundabout的完整答案中收集一些東西。

類型簽名中=>左側的所有東西都是約束條件。閱讀類型是這樣的:

compareWithHundred :: (Num a, Ord a) => a -> Ordering 
         ^^^^^^^^^^^^^^ ^ ^^^^^^^^ 
         constraints  |   | 
           argument type | 
              result type 

所以,你只能傳遞一個函數參數,因爲只有在一個類型簽名,a說法。 a是一個類型變量,只要該類型滿足約束條件,可以用任何類型來替換。

Num a說,無論你更換a與必須是數字(所以可以IntIntegerDouble,...),以及Ord a說,它必須是可比的。 leftroundabout的答案更詳細地解釋了爲什麼你需要這兩個,我只是想確保你知道如何閱讀簽名。

因此,在某種意義上說compareWithHundred "foobar"是完全合法的,類型檢查器說這個表達式的類型是Ordering,但是當它試圖檢查是否存在Num String實例時會失敗。

我希望這會有所幫助。