这与其他人所说的没有什么不同,但也许应该努力点?列表有两个基本的“构造函数”,因此需要从列表中定义函数时需要考虑两个基本情况:形式为[]
和(:)
的参数。后者,(:)
可以加入任何与这种事物的列表,因此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