関数をn回適用する
foldr (.) id (replicate n f)
を理解したい。
*Main> :t foldr (.)
の型を考える。
*Main> :t foldr foldr :: (a -> b -> b) -> b -> [a] -> b
置き換えておく。
foldr :: (x -> y -> y) -> y -> [x] -> y
*Main> :t (.) (.) :: (b -> c) -> (a -> b) -> a -> c
(1) b -> c
を x
(2) a -> b
を y
(3) a -> c
を y
と対応させる。
2番目と3番目をみるとbとcは同じになる。
また、
(1) は b->b
となる。
(2),(3)は a->b
となる。
これをx,yにあてはめると、
( (b->b) -> (a->b) -> (a->b) ) -> (a->b) -> [b->b] -> a -> b
となり、foldr (.)
は
foldr (.) :: (a -> b) -> [b -> b] -> a -> b
となる。
*Main> :t id id :: a -> a
を適用すると、aとbは同じになるので、
*Main> :t foldr (.) id foldr (.) id :: [b -> b] -> b -> b *Main>
これの第1引数は関数のリストをとり、(それらをつなげた、一つの)関数を返す。
この第1引数につながるように、関数のリストをつくるが、それはreplicate
がつかえる。
*Main> :t replicate replicate :: Int -> a -> [a] *Main>
*Main> let repeatFunN n f = foldr (.) id (replicate n f) *Main> :t repeatFunN repeatFunN :: Int -> (b -> b) -> b -> b *Main> repeatFunN 5 (\x -> x * 2) 1 32 *Main>
というか、面倒なことを考えずに、直感的に、通常使う場合の関数版だと思えば良い。
要素 | 内容 | 通常使う場合の例 |
---|---|---|
foldr |
||
(.) |
関数をつなげるもの | (\x -> \y -> x + y ) |
id |
関数の単位元(?!)のようなもの | 0 |
(replicate n f) |
関数のリスト | [1,2,3,4] |