4

我想學習一下Haskell與在線書籍「Learn you a Haskell」,我有一個關於高階函數的問題。與Haskell中的(高階)函數進行模式匹配

我看到some examples,我希望做一些更高級的功能,但我不知道爲什麼我總是讀以下異常:

***異常:euler13.hs:(11,0 ) - (15,39):在功能 非詳盡的模式應用於

我定義的函數,這是一個:

apply :: (Num b, Ord b) => (a -> a) -> b -> [a] -> [a] 
apply f n [] = [] 
apply f n [x] 
    | n <= 1 = map f [x] 
    | otherwise = apply f (n-1) (map f [x]) 

我想一個pply'n'將一個名爲'f'的具體函數添加到列表'[x]'中。我試圖讓這個函數具有多態性,所以參數的類型是'a'。但我想使用數字和列表也是如此,所以我直接使用列表(如果我想使用函數只是爲了一個數字,它顯然是[數字])

請問有人可以幫我嗎?我喜歡這種語言,但是在學習時有點困難,因爲它與Java或c有很大不同(例如)

謝謝!

+0

我建議重命名問題的標題:這是模式匹配的問題,不一定與高階函數。 – 2011-02-01 19:27:59

+0

確定完成了。現在呢?謝謝! – albertoblaz 2011-02-01 21:41:19

回答

13

刪除圍繞x[]。否則第二個模式只能匹配具有1個元素的列表。

apply f n x 
    | n <= 1 = map f x 
    | otherwise = apply f (n-1) (map f x) 
+8

雖然我們在這裏:將它重命名爲「xs」,這是「任何事物列表」的更常見的名稱。 – delnan 2011-02-01 16:21:17

+0

是的,這是真的。問題是我在嘗試做很多事情做更改和更改,沒有任何東西。但正確的是使用'xs' – albertoblaz 2011-02-01 21:42:50

5

您針對兩種情況定義apply:n和一個空表n和一個元素的列表。當列表包含多個元素時會發生什麼?這是缺失的模式。

11

這與其他人所說的沒有什麼不同,但也許應該努力點?列表有兩個基本的「構造函數」,因此需要從列表中定義函數時需要考慮兩個基本情況:形式爲[](:)的參數。後者,(:)可以加入任何與這種事物的列表,因此1[] - 1:[][1]。或者它可以加入1與這種類型的東西:1:(1:[])1:[1],即[1,1]作爲特殊語法讓我們寫作。

這將是比較明顯的會是什麼地方出錯了,如果你定義了自己的列表,寫作:

data List a = Nil | Cons a (List a) deriving (Show, Eq, Ord) 

採用[]x:xs只是這樣的事情斯萬克糖。同樣,特殊的String糖讓我們寫​​而不是['a','b','c'],這比'a':'b':'c':[]更好。 (根據上面的定義,我們必須編寫Cons 'a' (Cons 'b' (Cons 'c' Nil)))這對於一個簡短的字符串來說有點多! - 儘管它也提出了爲什麼人們應該更喜歡ByteStringText表示字符串用於很多目的。)有了這樣一個更詳細的列表定義,我們需要增加我們自己的map(或相當fmap),所以我們可以說

instance Functor List where 
    fmap f Nil = Nil 
    fmap f (Cons first rest) = Cons (f first) (fmap f rest) 

請注意,在定義fmap這種情況下,我不得不考慮這兩種類型的構造函數對於我的列表類型,NilCons first rest(或Cons x xs,因爲它經常被寫入)。

或者,也許你還沒有起身在LYAH的Functor型類的一般性討論 - 在這種情況下,只考慮您可以定義自己的map作爲

listMap f Nil = Nil 
listMap f (Cons first rest) = Cons (f first) (listMap f rest) 

在任何情況下,給出的列表類型的這種脫糖改寫,你的實際功能的定義是:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a 
apply f n Nil = Nil 
apply f n (Cons first Nil) 
    | n <= 1 = fmap f (Cons first Nil) -- or listMap f (Cons first Nil) 
    | otherwise = apply f (n-1) (fmap f (Cons first Nil)) 

你所涵蓋的情況:

apply f n Nil 
apply f n (Cons first Nil) 

Cons first Nilfirst : [][first] - 即[x]相同。但這意味着你沒有覆蓋每一個案例,你的定義是「非窮盡的」。您還沒有說過如果將fn應用於列表中,如果它有多個成員。如果列表的形式是Cons x (Cons y Nil)Cons x (Cons y (Cons z Nil))而不是Nil(您的第一行)或Cons x Nil(您的第二行)?

的解決方案是爲別人說,或者使用我們的脫糖列表類型:

apply :: (Num b, Ord b) => (a -> a) -> b -> List a -> List a 
apply f n Nil = Nil 
apply f n (Cons first rest) 
    | n <= 1 = fmap f (Cons first rest) 
    | otherwise = apply f (n-1) (fmap f (Cons first rest)) 

這裏的「變量」 rest涵蓋了所有的名單,Nil與否。因此,我們得到:

*Main> apply (+1) 3 Nil 
Nil 
*Main> apply (+1) 3 (Cons 3 Nil) 
Cons 6 Nil 

,你會,也:

*Main> apply (+1) 3 (Cons 0 (Cons 1 (Cons 2 Nil))) 
Cons 3 (Cons 4 (Cons 5 Nil)) 
2

這不是一個新的答案,比起給別人,但我希望是有見地不過。

您已經在函數定義中演示了對模式匹配的一些理解;當第一種模式不匹配時,評估就轉移到下一個模式。能夠無法匹配的模式被認爲是「可反駁的」。

通常,最後一個函數定義是「無可辯駁的」,這意味着它總是匹配是一個好主意。從Haskell 2010 report

無可辯駁圖案如下:一個變量,一個通配符,N APAT其中N是由NEWTYPE和APAT限定的構造是無可辯駁,VAR @ APAT其中APAT是無可辯駁,或形式的〜APAT。所有其他模式都是可以反駁的。

你的誤解是,你以爲[x]是一個變量(無可辯駁的模式),當它實際上是一個可辯駁的模式(單元素列表,結合x到單個元素的圖案)。

假設您編寫了一個函數,該函數僅適用於長度爲3的列表。如果您需要比「非窮舉模式」更具描述性的錯誤消息,那麼您可以使用通配符(下劃線)無可辯駁的模式。一個簡單的例子:

sum3 [x,y,z] = x+y+z 
sum3 _  = error "sum3 only works on lists of length 3"