這與其他人所說的沒有什麼不同,但也許應該努力點?列表有兩個基本的「構造函數」,因此需要從列表中定義函數時需要考慮兩個基本情況:形式爲[]
和(:)
的參數。後者,(:)
可以加入任何與這種事物的列表,因此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)))
這對於一個簡短的字符串來說有點多! - 儘管它也提出了爲什麼人們應該更喜歡ByteString
和Text
表示字符串用於很多目的。)有了這樣一個更詳細的列表定義,我們需要增加我們自己的map
(或相當fmap
),所以我們可以說
instance Functor List where
fmap f Nil = Nil
fmap f (Cons first rest) = Cons (f first) (fmap f rest)
請注意,在定義fmap
這種情況下,我不得不考慮這兩種類型的構造函數對於我的列表類型,Nil
和Cons 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 Nil
與first : []
或[first]
- 即[x]
相同。但這意味着你沒有覆蓋每一個案例,你的定義是「非窮盡的」。您還沒有說過如果將f
和n
應用於列表中,如果它有多個成員。如果列表的形式是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))
我建議重命名問題的標題:這是模式匹配的問題,不一定與高階函數。 – 2011-02-01 19:27:59
確定完成了。現在呢?謝謝! – albertoblaz 2011-02-01 21:41:19