「入門Haskell―はじめて学ぶ関数型言語」 p.86 より。昨日より1ページ戻ったけど。
(1) repeat,cycle,iterate をそれぞれ自分で定義しなさい。
これは簡単。再帰を使ってこうだ。
myRepeat a = a:map id (myRepeat a)
myCycle a = a ++ myCycle a
myIterate f a = a:map f (myIterate f a)
結果は省略。
(2) repeat,cycle,iterate のうち,どれか1つを自分で定義し,残りの2つはその定義した関数をもとに定義しなさい。ほかの Prelude 関数を使ってもかまいません。
こっちはちょっと難しい。とくに iterate でかなりつまった。
まずは repeat を使って他の2つを定義。
myCycle2 = (foldr (++) []) . myRepeat
myIterate2 f a = map (\x -> x a) (rep f)
where rep = (scanl (.) id) . myRepeat
結果。
*Main> take 50 $ myCycle "abc"
"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcab"
*Main> take 50 $ myIterate2 (+1) 1
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,3
0,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50]
よし,うまくいってるみたいだ。myCycle2 はこないだ覚えた foldr で無限リスト。
myIterate2 のほうは,myRepeat で関数 f のリストを作っておいて,scanl1 で合成している。これで [id, f, (f . f), (f . f . f), …] というふうなリストができる。かなりトリッキーな気がするけど,いいんだろうか。ま,結果はうまくいってるみたいだけど。
myCycle を使って他の2つを定義。
myRepeat3 a = myCycle [a]
myIterate3 f a = map (\x -> x a) (cyc f)
where cyc g = scanl (.) id (myCycle [g])
myRepeat3 は大した工夫ではなし,それができればあとは myIterate3 は上の myIterate2 とおなじ。
*Main> take 50 $ myRepeat3 'a'
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
*Main> take 50 $ myIterate3 (+1) 1
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,3
0,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50]
最後。myIterate を使って。
myRepeat4 = myIterate id
myCycle4 = (foldr (++) []) . (myIterate id)
*Main> take 50 $ myRepeat4 'a'
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
*Main> take 50 $ myCycle4 "abc"
"abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcab"
追記:
myCycle2 と myCycle4 は foldr じゃなくて concat を使った方が簡単だな。
myCycle2 = concat . myRepeat
myCycle4 = concat . (myIterate id)