type を持つ関数「パイプライン」を作成するように求められました。[a -> a] -> [a] -> [a]このようなパイプラインでは、元の関数リストの各関数が入力の各要素に順番に適用されます。たとえば、パイプライン[(+1),(*2),pred] [1,2,3]は を返し[1,3,5]ます。
ソリューション シートの答えは ですがpipeline = map . foldr (.) id、よくわかりません。この解決策はどのように実現できますか?
type を持つ関数「パイプライン」を作成するように求められました。[a -> a] -> [a] -> [a]このようなパイプラインでは、元の関数リストの各関数が入力の各要素に順番に適用されます。たとえば、パイプライン[(+1),(*2),pred] [1,2,3]は を返し[1,3,5]ます。
ソリューション シートの答えは ですがpipeline = map . foldr (.) id、よくわかりません。この解決策はどのように実現できますか?
ひとつ考えられるのfoldrは、
foldr f z xs
すべての (:) を に置き換えxs、f空のリストをに置き換えますz
ご了承ください
[(+1), (*2)]
の省略形です
(+1) : (*2) : []
あなたは今、何を見ることができるはずです
foldr (.) id ((+1) : (*2) : [])
に評価します。そして、これで全体の表現が理解できるようになります。
折り目は、実際には非常に単純ですが、どういうわけか非常に混乱します。:特に右の折り畳み: 基本的には、リスト内のそれぞれを代替の指定された関数に置き換え、リストをnilinit 値に置き換える以外に何もしません。あなたの例:
foldr (.) id [(+1),(*2),pred]
≡ foldr (.) id ( (+1) : (*2) : pred : [] )
≡ (+1) . (*2) . pred . id
したがって、これは単にリスト内のすべての関数を大きな構成にチェーンするだけです。
このチェーンを取得したら、それを別のリストのすべての値に適用するのは簡単で、map.
問題の核心は type の関数を持つことです:[a -> a] -> (a -> a)つまり、関数のリストを 1 つの関数に変換します。
foldrタイプがあります:(b -> c -> c) -> c -> [b] -> c
タイプがどのように適合するかを見てみましょう。
(b -> c -> c) -> c -> [b] -> cbます(a -> a):((a -> a) -> c -> c) -> c -> [a -> a] -> ccます(a -> a):((a -> a) -> (a -> a) -> (a -> a)) -> (a -> a) -> [a -> a] -> (a -> a)(.)です(b -> c) -> (a -> b) -> a -> c。これは、前の署名の最初の型にあるものです (私たちのものは all でしたa)。そこで使用できます(.)。(a -> a)を使用できidます。(.) idが残っています。[a -> a] -> (a -> a)foldr (.) id与えます[a -> a] -> (a -> a)その後、mapパーツは結果の関数をfoldrリストの各要素に適用するだけです。
注: 潜在意識がこれに慣れるまで、ホワイトボードを使用してこれらすべてを理解してください ;)