好吧,我们可以这样评论 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
如果您想解决更难的事情,请尝试tail
为Churchlist
. (从写使用tail
开始。)[a]
foldr