2012-02-11 85 views
9

讀「真實世界哈斯克爾」,95頁的作者提供了一個例子:函數獲取四個參數而不是三個 - 爲什麼不打破?

myFoldl f z xs = foldr step id xs z 
    where step x g a = g (f a x) 

我的問題是:爲什麼這個代碼編譯? foldr只需要三個參數 - 但在這裏,它通過四個:step,id,xs,z

例如,這不起作用(因爲總和預計一個):

sum filter odd [1,2,3] 

相反,我必須寫:

sum $ filter odd [1,2,3] 

回答

12

這裏是foldr類型:

Prelude> :t foldr 
foldr :: (a -> b -> b) -> b -> [a] -> b 

我們可以計算出它是如何成爲一個四參數功能?試一試吧!

  1. 我們給它id :: d -> d作爲第二個參數(b),所以讓我們替代品入式:

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d) 
    
  2. 在Haskell

    a -> a -> a相同a -> (a -> a),這給了我們(去掉最後的括號):

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d 
    
  3. 讓我們簡化,通過代e(a -> (d -> d) -> (d -> d))f(d -> d),以使其更易於閱讀:

    e -> f -> [a] -> d -> d 
    

因此,我們可以清楚地看到,我們已經構建了四個參數的功能!我頭疼。


下面是從n-ARG FUNC創建的n + 1參數的功能的一個簡單的例子:

Prelude> :t id 
id :: a -> a 

id是一個參數的函數。

Prelude> id id id id id 5 
5 

但我剛給了它5個參數!

+0

我不明白你爲什麼可以做'id id 5',但是你不能這樣做:'foo x = x + 1;條y = y + 1; foo bar 1'? – drozzy 2012-02-11 23:46:32

+4

@drozzy - 這一切都是關於類型和多態的。以'id :: a - > a':你可以用* any替換'a'。然而,'foo'是不同的,因爲它有約束:它需要一個數字:'foo ::(Num a)=> a - > a'。 'bar ::(Num a)=> a - > a'不是'Num'類型類型的實例,因此不符合'foo'的'(Num a)'約束。 – 2012-02-11 23:51:03

+2

@drozzy如果我們澄清函數應用程序的關聯性,也許會有所幫助!請記住'id id 5'解析爲'(id id)5' - 也就是說,首先將'id'作爲'id'的參數,然後將'5'作爲結果的參數 - 而不是' id(id 5)'。 – 2012-02-12 01:26:09

10

這是因爲foldr如何多態是:

foldr :: (a -> b -> b) -> b -> [a] -> b 

在這裏,我們已經將b實例化爲一個函數類型,我們稱之爲c -> c,所以foldr類型專門到(例如)

foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c 
+1

你也可以指出原始問題中的中性元素已經是一個函數'id'。 – ShiDoiSi 2012-02-11 20:53:03

9

foldr只需要3個參數

錯誤。 Haskell中的所有函數都只需要1個參數,並且只產生1個結果。

foldr :: (a -> b -> b) -> b -> [a] -> b 

見,foldr需要一個參數(a -> b -> b),併產生1個結果:b -> [a] -> b。當你看到這一點:

foldr step id xs z 

請記住,這僅僅是簡寫本:

((((foldr step) id) xs) z) 

這就解釋了爲什麼這是無稽之談:

sum filter odd [1,2,3] 
(((sum filter) odd) [1,2,3]) 

sum :: Num a => [a] -> a將列表作爲其輸入,但你給了它一個功能。

相關問題