3

私は次の方法でリストの連結を行っています(GHCを使用した例):

myConcat :: [[a]] -> [a]
myConcat xs = foldr (++) [] xs
myConcat    = foldr (++) []

上記の定義が機能する理由と方法を説明してください。これは機能しません。

myConcat xs = foldr (++) []

コードの最後の行は意図的に許可されていませんか (コンストラクトが混乱する可能性がある、役に立たないなどの理由で)、それともより深いもので、おそらくカリー化に関連しています...

私はこれにいくつかの光を当てることができることを願っています, それは本当に私を困惑させます:/

LATER EDIT:以下の説明に加えて、この問題に関する良い情報源がChap . 4 「 Real World Haskell」という本からの「Functional Programming」。この本はオンラインで無料で入手できます。

4

3 に答える 3

7

さまざまなバージョンを確認してみましょう。

myConcat xs = foldr (++) [] xs

これは、 によって消費される引数を提供する通常の方法foldrです。型は です。左側に[[a]] -> [a]type の引数があり、右側に供給されると生成されます。[[a]][a]

myConcat = foldr (++) []

ここでfoldrは部分的に適用されるので、リストのリストである追加の引数を取ることができる関数を返します。したがって、右側から返されるものはすでに必要なものです。これは「構文上の砂糖」ではなく、最初のバージョンと同じことを表現する別の方法です。型は再び[[a]] -> [a]: 左側には何もありませんが、右側にその署名の関数を返します。

myConcat xs = foldr (++) []

ここfoldrでも部分的に適用され、以前と同じように引数を取ることができる関数を返しますが、定義には追加の引数xsがあり、右側では使用されません。コンパイラは、右辺に適用したいのがこの引数であることを「認識」していません。タイプはt -> [[a]] -> [a]. なんで?

二乗関数があるとします。

sqr :: Int -> Int 
sqr x = x*x

あなたがしていることは、追加の未使用の引数を提供することと本質的に同じです:

sqr:: Int -> t -> Int 
sqr x y = x*x

関数は引き続き「機能」します。たとえばsqr 3 "bla"、9 が返されますが、型シグネチャは無効であり、未使用の引数は... ええと、未使用です。未使用の引数には、事実上「何でも」できるため、固定された型はありませんが、問題ではありません。したがってt、署名で型変数 ( ) を取得します。

于 2011-07-22T06:34:39.850 に答える
3

さて、カリー化された関数 の型シグネチャを見てみましょうfoldr:

>:t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

したがってfoldr、バイナリ関数 (つまりa->b->b)、b値、値のリストを取り、a値を返しbます。

より明確な定義を得るために、 のドキュメントも見てみましょう。foldr

二項演算子、開始値 (通常は演算子の右側の同一性)、およびリストに適用される foldr は、二項演算子を使用してリストを右から左に縮小します。

では、型シグネチャを見てみましょうmyConcat xs = foldr (++) []

> :t myConcat
myConcat :: t -> [[a]] -> [a]

うーん...それは私たちが望んでいたものではありません...

問題はfoldr、 type の値を提供したことがないことです[a]。したがって、次myConcatのように、満たすために任意のタイプの値xs [a]complete するタイプの値が必要foldr (++) []です。

> myConcat 2 [[1,2],[3,4]] 
[1,2,3,4]
> myConcat Nothing [[1,2],[3,4]] 
[1,2,3,4]

それは機能しますが、最初の引数は無駄です。

ただし、そのxs値を に渡すとfoldr (++) []、次のようになります。

myConcat xs = foldr (++) [] xs

その型シグネチャを確認します

> :t myConcat
myConcat :: [[a]] -> [a]

ああ、ずっといい。myConcat を使用xsして関数を完成させfoldrます。

また、myConcat = foldr (++) []も機能し、実際にはポイントフリー スタイル プログラミングの例です。の型シグネチャを確認するとfoldr (++) []

> :t foldr (++) []
foldr (++) [] :: [[a]] -> [a]

部分適用foldrによって最初の 2 つの引数を既に提供しているので、値を取り、必要な処理を行う関数が返されます。したがって、名前に割り当てるだけで、上記の例と同じように機能しますが、引数を明示的に渡す必要はありません![[a]]

> let myConcat = foldr (++) []
> :t myConcat
myConcat :: [[a]] -> [a]
> myConcat [[1,2],[3,4]]
[1,2,3,4]
于 2011-07-22T06:35:37.253 に答える
2
myConcat xs = foldr (++) []

t -> [[a]] -> [a]は、他の 2 つの型と同じではない型を持ってい[[a]] -> [a]ます。

于 2011-07-22T06:14:46.180 に答える