2015-11-17 71 views
4

我是Haskell的新手,我對以下行爲感到困惑:爲什麼Haskell無法自動解析參數個數?

我有一個叫做dealWithIt的函數。它看起來像這樣:

dealWithIt :: (Show a) => [a] -> String 
dealWithIt = foldl f "" 
    where f memo x = memo ++ (show x) 

都好,它的工作如預期,它得到showables的列表,並將它們連接成一個字符串。

盡我所知,如果我明確指定收到的參數,只要它可以傳遞到底層的函數鏈,那並不重要。這意味着以下兩個定義應該是等效的:

dealWithIt xs = foldl f "" xs 
dealWithIt = foldl f "" 

到目前爲止這麼好。比方說,我想現在通過模式匹配添加一個特殊情況:

dealWithIt [] = "Empty list :(" 

這就是事情變得怪異。如果我沒有明確指定XS的說法,我得到以下錯誤:

Equations for ‘dealWithIt’ have different numbers of arguments 

我可以住在一起,但它真的很有趣,我爲什麼Haskell中無法檢測到發生了什麼事,甚至會報告錯誤當兩種變體都只有一個參數?

+0

'dealWithIt = foldl f「」'已經指定了所有可能參數的行爲。用另一個論點再次定義它有什麼意義? –

+0

添加特例與處理所有可能的參數無關。 – qwe

+1

編譯器拋出的錯誤消息說清楚了。這些是不同的功能。比較他們的簽名。如果您需要處理* special *參數,則可以使用參數模式匹配,但保留相同的類型。或者使用警衛,或者如果/情況條件。 – joanbm

回答

4

這只是一個規則。一個函數的定義如下:

f p0 p1 = e0 
f p2 p3 = e1 

必須在所有方程的左側的函數參數中具有相同數量的模式。

這部分是爲了簡化語言的定義; Haskell的標準定義在case表達的術語,其功能定義:

f x0 x1 = case (x0, x1) of 
    (p0, p1) -> e0 
    (p2, p3) -> e1 

現在考慮,如果你能說

f p0 p1 = e0 
f p2 = e1 -- `e1` is a function 

的語言標準將有專門處理這種情況會發生什麼,並將其定義爲類似於

f x0 x1 = case (x0, x1) of 
    (p0, p1) -> e0 
    (p2, _) -> e1 x1 -- Note that the argument to `e1` has to be supplied explicitly 

這是一個不必要的併發症,用於s這是通常不明智的做法。

此外,考慮foldr定義:

foldr f z [] = z 
foldr f z (x:xn) = f x (foldr f z xn) 

假設你正在鍵入它,你的第一個公式忘了f

foldr z [] = z 
foldr f z (x:xn) = f x (foldr f z xn) 

目前的規則允許錯別字像這樣被捕獲:編譯器可以抱怨你在不同的方程中有不同數量的參數。否則,你會得到一些令人困惑的類型錯誤,這可能很難調試。(可能你會得到一個錯誤,因爲第一個方程中的z必須與第二個方程中的f具有相同類型,並且第一個方程中的z必須與第二個方程中的f x (foldr f z xn)具有相同類型,所以第一個參數foldr必須具有無限類型。無限類型錯誤通常不適合調試。)

+0

即使'fxy = somethingWith xy'也是語法糖,用於'f = \ xy - > somethingWith xy',它自己的糖用於'f = \ x - >(\ y - > somethingWith xy)'等等。在某種程度上,Haskell只存在函數,應用程序,(飽和)構造函數調用和數據解構。 –

相關問題