好吧,我们可以这样评论 Churchlist 类型以澄清它:
-- Tell me...
type Churchlist t u = (t -> u -> u) -- ...how to handle a pair
-> u -- ...and how to handle an empty list
-> u -- ...and then I'll transform a list into
-- the type you want
请注意,这与foldr 函数密切相关:
foldr :: (t -> u -> u) -> u -> [t] -> u
foldr k z [] = z
foldr k z (x:xs) = k x (foldr k z xs)
foldr 是一个非常通用的函数,可以实现其他各种列表函数。一个可以帮助您的简单示例是使用foldr 实现列表副本:
copyList :: [t] -> [t]
copyList xs = foldr (:) [] xs
使用上面的注释类型,foldr (:) [] 的意思是:“如果你看到一个空列表返回空列表,如果你看到一对返回 head:tailResult。”
使用Churchlist,你可以很容易地写成这样:
-- Note that the definitions of nil and cons mirror the two foldr equations!
nil :: Churchlist t u
nil = \k z -> z
cons :: t -> Churchlist t u -> Churchlist t u
cons x xs = \k z -> k x (xs k z)
copyChurchlist :: ChurchList t u -> Churchlist t u
copyChurchlist xs = xs cons nil
现在,要实现map,您只需将cons 替换为合适的函数,如下所示:
map :: (a -> b) -> [a] -> [b]
map f xs = foldr (\x xs' -> f x:xs') [] xs
映射就像复制一个列表,只不过不是逐字复制元素,而是将f 应用于每个元素。
仔细研究所有这些,你应该可以自己写mapChurchlist :: (t -> t') -> Churchlist t u -> Churchlist t' u。
额外练习(简单):用foldr 编写这些列表函数,并为Churchlist 编写对应项:
filter :: (a -> Bool) -> [a] -> [a]
append :: [a] -> [a] -> [a]
-- Return first element of list that satisfies predicate, or Nothing
find :: (a -> Bool) -> [a] -> Maybe a
如果您想解决更难的事情,请尝试为Churchlist 写tail。 (首先使用foldr为[a]写tail。)