この質問に答えるには、何をして何foldr
をするかを思い出すのが良いmap
でしょう。
2つのうち、より複雑なのはfoldr
、
-- list to be folded
-- v
foldr :: (a -> b -> b) -> b -> [a] -> b
-- ^ ^
--folding function terminal value
折りたたまれるリストは、実際には一連のコンス(:)
とターミナルの空のリストです。
1 : 2 : 3 : []
のアクションは、コンストラクターとコンストラクターをそれぞれフォールディング関数とターミナル値にfoldr
置き換えることです。:
[]
foldr (+) 0 (1 : 2 : 3 : []) == 1 + 2 + 3 + 0
map
関数はより単純です。それを考える1つの方法は、関数とリストを取得し、その関数をリストのすべての引数に適用することです。
map :: (a -> b) -> [a] -> [b]
-- ^ ^
-- function list
ただし、関数を取得し、代わりにリストに作用する関数として持ち上げることもできます。
map :: (a -> b) -> ( [a] -> [b] )
-- ^ ^
-- function function on lists
これら2つの機能を構成するとはどういう意味map . foldr
ですか?これは関数を次々に適用しているだけであることに注意してください-特に、
(map . foldr) f == map (foldr f)
最初に適用するのでfoldr
、それを関数に適用する必要があり、f :: a -> b -> b
別の関数を取得します。
foldr f :: b -> [a] -> b
-- ^ ^
--terminal val list to be folded
次に、を適用しますmap
。これにより、リストに作用する関数が持ち上げられます。
map (foldr f) :: [b] -> [[a] -> b]
-- ^ ^
--list of terminal vals functions that fold lists
このタイプは奇妙に見えますが、有効です。ここで、単一の端末値の代わりに、端末値のリストを指定すると、折り返し関数のリストが返されます(指定した端末値ごとに1つ)。
明確にするために、(+)
タイプを持つ特定の関数、を見ることができます。
(+) :: Num a => a -> a -> a
これを上記の式に代入すると、次のようになります。
(map . foldr) (+) :: Num a => [a] -> [[a] -> a]
-- ^ ^
-- list of terminal vals functions that fold lists
これをリスト[0, 1, 2]
に適用すると、次の3つの関数のリストが得られます。
(map . foldr) (+) [0,1,2] :: Num a => [[a] -> a]
このイディオムを使用してmap ($x)
、リスト内の各関数を特定の引数に適用できます。それは数字のリストでなければなりません、そして私はを選びます[3,4,5]
。注意深く見てください:
> map ($[3,4,5]) ((map.foldr) (+) [0,1,2])
[12, 13, 14]
リスト[3,4,5]
は、折りたたみ関数としてを使用して3回折りたたま(+)
れ、そのたびに異なる端末値が使用されました。
3 + 4 + 5 + 0 == 12
3 + 4 + 5 + 1 == 13
3 + 4 + 5 + 2 == 14
最終値が0
、の場合、値の合計を取得するだけです3 + 4 + 5 == 12
。最終値がの場合、値の合計( )1
より1つ多くなり、最終値がの場合、値の合計()より2つ多くなります。13
2
14