unfold 関数

「プログラミング Haskell 第7章 高階関数」の練習問題に unfold 関数が登場しています。
unfoldr は Data.List にも登録されていますので、どのような関数なのかやってみました。
foldはリストから値を求めますが、問題で作られている unfold 関数は初期値からリストを作る関数です。そして、引数として渡すのは次の3つの関数です。

unfold (終了を判定する関数) (リストの要素を作る関数) (再帰に渡す値を作る関数)

unfold p h t x | p x      = []
               |otherwise = h x : unfold p h t (t x)

int2bin = unfold (==0) (`mod` 2) (`div` 2)
-- int2bin 256 -- > [0,0,0,0,0,0,0,0,1]

map' f =  unfold (==[]) (f.head)  tail
-- map' (+1) [0..10] -- > [1,2,3,4,5,6,7,8,9,10,11]

iterate' f =  unfold (const False) f f
-- take 10 $ iterate' (*2) 1 -- > [2,4,8,16,32,64,128,256,512,1024]

fib  = [1,1]++ (unfold (const False) (\[x,y]->x+y) (\[x,y]->[y,x+y]) [1,1])
-- > take 20 $ fib
-- > [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765]

Data.List に定義されている unfoldr で同等の関数を定義してみます。

import Data.List

-- unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

int2bin' = unfoldr (\x -> if x==0 then Nothing else Just (x `mod` 2,x `div` 2))
-- int2bin' 256 -- > [0,0,0,0,0,0,0,0,1]

map'' f =  unfoldr (\x -> if x==[] then Nothing else Just ((f.head) x ,tail x ))
-- map'' (+1) [0..10] -- > [1,2,3,4,5,6,7,8,9,10,11]

iterate'' f =  unfoldr (\x -> Just (f x ,f x ))
-- take 10 $ iterate'' (*2) 1 -- > [2,4,8,16,32,64,128,256,512,1024]

fib' = [1,1]++ (unfoldr (\[x,y] -> Just (x+y ,[y,x+y])) [1,1])
-- > take 20 $ fib'
-- > [1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765]