Paramorphismの練習
その上で、
なぜ foldr
では無理(あるいは複雑になる)で、 para
では書けるのか、ということを考える
また、それはさておき、 para
を使って書く時の考え方、というのをメモる
まずparaの定義
hspara :: (a -> ([a], b) -> b) -> b -> [a] -> b
para f z [] = z
para f z (x : xs) = f x (xs, para f z xs)
Data.List.insert
の再実装
こんな感じで書ける
hsinsertWithPara :: Ord a => a -> [a] -> [a]
insertWithPara v = para f []
where
f x (xs, ys)
| v <= x = v:x:xs
| otherwise = x:ys
この f
がどういう関数なのか、というのを捉えるのがまず難しい
まず para
は foldr
の強化版であることをまず抑える
foldl
ではなく foldr
である
f x (xs, ys)
の理解
ys
accumratorとなるリスト
f
が呼ばれた時点で ys
は処理済になっている
x
currentとなる要素
xs
para
特有のもの
x:xs
とすることで、 f
が呼ばれた時点でのリストを再生できる
まだちゃんと捉えきれてない
あと、そもそもpara使わなくても以下のようにfoldrで書けるのでは
hsinsert' :: Ord a => a -> [a] -> [a]
insert' v = foldr f [v]
where
f x (y:ys)
| x <= y = x:y:ys
| otherwise = y:x:ys
foldrにできなくて、paraでのみできることって何だっけ?
そもそもfoldr自体に捉えが甘いのと、
というのはどうでしょう?
hsdeleteWithPara :: Ord a => a -> [a] -> [a]
deleteWithPara v = para f []
where
f x (xs, ys)
| v == x = xs
| otherwise = x:ys
hsdelmin :: Ord a => [a] -> Maybe (a, [a])
delmin = para f Nothing
where
f x (xs, Nothing)
| null xs = Just (x, [])
| otherwise = Just (x, xs)
f x (xs, Just (min, ys))
| x <= min = Just (x, xs)
| otherwise = Just (min, x : ys)