もあわせてどうぞ.
Prelude
関数にspan :: (a -> Bool) -> [a] -> ([a],[a])
という関数があります.この関数は,リストを前後に分けます.条件を満す要素が連続する先頭部分と残りの部分です.
span _ [] = ([],[])
span p xxs@(x:xs)
| p x = case span p xs of
(ys,zs) -> (x:ys,zs)
| otherwise = ([],xxs)
span
はリスト上の再帰関数ですので,再帰パターン(recursion-scheme)のどれかの具体例になっているはずですね.
再帰パターンには,なんとかモルフィズム
という名前がついています.foldr
はその中でももっとも良く知られているもので,これは,リスト上のcatamorphismの具体例です.ほかにも,unfoldr
はリスト上のanamorphismの具体例です.さて,foldr
はリストの先頭の要素と残りの部分を畳み込んだ結果とをまとめますが,span
ではリストの先頭ではなく,リスト全体が必要になります.このような畳み込みの再帰パターンはparamorphismといいます.リスト上のparamorphismは以下のように定義できます.
para :: (a -> ([a],b) -> b) -> b -> [a] -> b
para _ z [] = z
para phi z (x:xs) = phi x (xs, para phi z xs)
para
を用いてspan
を定義すると以下のようになります.
span p = para phi ([],[])
where
phi x (xs,(ys,zs))
| p x = (x:ys,zs)
| otherwise = ([],x:xs)