それを明確にするために、このように 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