2013-04-21 52 views
3

我正在嘗試使用摺疊函數在Haskell中取整數的平方和。但是,我從GHCi得到一個神祕的錯誤。這裏是我的一行:帶有函數組合的類型推斷列表

((^2) . foldl) (+) 0 [1..100] 

我正在從GHCI得到的是:

Prelude> ((^2) . foldl) (+) 0 [1..100] 

<interactive>:19:3: 
    No instance for (Num (b0 -> [b0] -> b0)) 
     arising from a use of `^' 
    Possible fix: 
     add an instance declaration for (Num (b0 -> [b0] -> b0)) 
    In the first argument of `(.)', namely `(^ 2)' 
    In the expression: (^ 2) . foldl 
    In the expression: ((^ 2) . foldl) (+) 0 [1 .. 100] 

我認爲這個問題是我基於此類型傳遞末名單宣言。

Prelude> :t ((^2) . foldl) (+) 0 [1..100] 
((^2) . foldl) (+) 0 [1..100] 
    :: (Enum b, Num b, Num (b -> [b] -> b)) => b 

任何人都可以給我一些瞭解爲什麼這種類型期待一個Enum任何方式來顯式轉換列表中,這樣我可以調試這個功能呢?提前致謝。

回答

5

寫這個的正確方法是(^2) . foldl (+) 0 :: Num a => [a] -> a(^2) . foldl (+) 0 $ [1..100] :: (Num a, Enum a) => a。當您自己做(^2) . foldl時,您嘗試將的第一個返回類型foldl的一個參數平方,這是一個函數a -> [a] -> a。該錯誤聲明瞭這一點:它沒有這種功能的Num實例,所以它不能派遣適當的電源功能(^)

一般來說,將構圖(.)想象爲僅適用於單一輸入功能的東西。這種類型是指示

(.) :: (b -> c) -> (a -> b) -> a -> c 

雖然有更多的一般用途,它們有點難以找到。

所以我的解決方案的工作原理是因爲我在寫作之前直接將參數應用於foldl。這些參數使得foldl (+) 0 :: Num a => [a] -> a成爲單個輸入參數的函數。

9

是的,這仍然是GHC產生的最荒謬和無用的錯誤信息之一。

首先,忽略了消息,考慮foldl(.)類型:

foldl :: (a -> b -> a) -> a -> [b] -> a 
(.) :: (b -> c) -> (a -> b) -> a -> c 

注意(.)構成只使用第一個參數。由於currying,具有「多個」參數的函數實際上是一個返回另一個函數的參數的函數。因此在表達式((^2) . foldl)中,foldl的「返回類型」是a -> [b] -> a,這是它試圖與(^ 2)合成的結果。

而且因爲錯誤信息是啞巴,它會抱怨a -> [b] -> a沒有Num實例以便與(^2) :: Num a => a -> a合併,並建議您添加一個實例。

你想要的是這樣的:((^2) . foldl (+) 0)。也就是說,使用(懶惰)foldl在這裏可能是一個壞主意。最好使用嚴格foldl',或者更好的是,內置sum功能:(^2) . sum

而且,在類型中提到的Enum約束是無關的,而實際上正確的 - 在Enum型類提供用於功能解釋範圍表示法。所以(Enum b, Num b) => ...意味着b是一個可以枚舉的數字類型,這正是表達式[1 .. 100]所需的。

0

很好的答案已經給出,但也許這是更直接的把它寫

(^2) $ foldl (+) 0 [1..100]

表達foldl (+) 0 [1..100]作品本身,它幫助,如果你想了解如何與foldl的作品,然後結果傳遞給(^2)。寫成一個函數

f list = (^2) $ foldl (+) 0 list

+0

甚至更​​簡單:'與foldl(+)0 [1..100]^2'。 – augustss 2013-05-01 19:29:18