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) : [])
に評価します。そして、これで全体の表現が理解できるようになります。
折り目は、実際には非常に単純ですが、どういうわけか非常に混乱します。:
特に右の折り畳み: 基本的には、リスト内のそれぞれを代替の指定された関数に置き換え、リストをnil
init 値に置き換える以外に何もしません。あなたの例:
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] -> c
b
ます(a -> a)
:((a -> a) -> c -> c) -> c -> [a -> a] -> c
c
ます(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
リストの各要素に適用するだけです。
注: 潜在意識がこれに慣れるまで、ホワイトボードを使用してこれらすべてを理解してください ;)