2014-11-16 43 views
7

我剛開始學習Haskell,對我來說奇怪的事情之一是具有多個參數的函數類型的語法。爲什麼Haskell使用箭頭作爲函數的類型?

舉一個簡單的例子:

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

爲什麼我們需要在這裏所有的箭頭?寫下類似Num Num Num -> Num的東西不是更有意義嗎?

引擎蓋下的原因是什麼?我搜索了這個問題,但找不到任何真正有用的東西。

+0

如果你有'(Ord a,Num a)=> a - > a - > a',你會寫些什麼? – Squidly

回答

16

令人困惑的第一件事是Num a =>,所以我們現在完全忽略它。相反,讓我們考慮Int -> Int -> Int,這是您給出的類型簽名的一種可能的專業化。

Haskell中的函數幾乎總是curried。這意味着多參數函數實際上是一個參數的函數,它返回一個接受下一個參數的函數,依此類推。

->是正確的聯想,所以Int -> Int -> Int是與Int -> (Int -> Int)相同的東西。

這也意味着,這個定義

f :: Int -> Int -> Int 
f x y = x + y 

相同

f :: Int -> Int -> Int 
f x = \y -> x + y 

事實上,在Haskell所有函數都只有一個參數。元組也存在,但它們是一流的公民,所以它們不僅僅是一個參數列表。

Num a =>是類型系統的一個不同方面。它表示類型變量a必須是Num類型類的一個實例。作爲Num的實例的類型的常見示例包括IntDouble。所以Num本身不是一個類型,它是一個類型類。 Num a =>表示對類型變量a的約束,它不是該函數的另一個參數。

(+)方法是Num型類的成員,所以你必須要使用(+)以這種方式約束a。如果你試圖給f簽字a -> a -> a(沒有限制),它將不起作用,因爲a是完全無約束的,我們對它可以是什麼類型一無所知。因此,我們無法在其上使用(+)

+0

+1鏈接! – CSnerd

0

函數的類型簽名中的每個參數的類型都可以包含空格,因此非空白分隔符很可能是必需的,因此編譯器(和人類!)可以區分它們。

例如,可以有一個參數化的抽象數據類型:

data MyType a = MyValue a 

而這需要具體的類型的函數(從MyType類型構造構造):

myFunc :: MyType Int -> MyType Int -> String 

如果沒」 t之間有參數->,簽名看起來像

myFunc :: MyType Int MyType Int -> String -- Not valid code 

和一個編譯器在計算函數的實際參數意味着什麼時會遇到更多麻煩(我想知道在某些情況下甚至可能不可能?)。至少,這是不太容易理解的。

+0

我懷疑你已經理解了這個問題。他問爲什麼Haskell使用'A - > B - > C'而不是'A B - > C'。即:' - >'左邊是參數列表,右邊是返回類型。 – Shoe

+0

@傑弗裏你說得對,我錯過了。我已經稍微編輯了我的答案。 –

相關問題