2011-07-22 15 views
3

私は、次の方法(GHCを使用した例、)でリストの連結をやってる:Haskellの関数定義の構文

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

誰かが私に説明することができますしてくださいなぜ、どのように上記の定義が働き、この1つはありません:...

myConcat xs = foldr (++) [] 

は(、それはなど、役に立たない混乱になるかもしれない構造のような理由で)意図的に許可されていないコードの最後の行ですかそれは多分カリー化に関連し、より深い何か、である

私はこれについていくつかの光を放つことができる、それは本当に私を困惑させる:/

後で編集:本書の「機能プログラミング」"Real World Haskell"。この本はオンラインで自由に入手できます。

答えて

7

は異なるバージョンを確認できます。タイプは[[a]] -> [a]です。左側にタイプ[[a]]という引数があり、右側に入力すると[a]となります。ここでfoldr

myConcat = foldr (++) [] 

は部分的に適用されるので、我々は追加の引数、リストのリストを取ることができます関数を返しています。右から戻ってきたものは、すでに必要なものです。それは、「構文上のsuger」ではなく、最初のバージョンと同じことを表現する別の方法です。タイプは再び[[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を返しますが、タイプシグネチャはオフで、未使用の引数は... erm、unusedです。使用されていない引数には固定型はありません。事実上「何か」である可能性がありますので問題はありません。したがって、シグネチャには型変数(t)が得られます。

+0

+1:非常に分かりやすい説明。万が一ハスケル関連のブログを持っているのですか?私はあなたのスタイルが好きです。 :-) –

+0

@Frerich Raabe:ありがとう!実際に私はScalaを中心にしたブログを持っていますが、現在はHaskellにもかかわらず、残念ながらそれはドイツ語です:http://dgronau.wordpress。com/ – Landei

+0

本当にありがとう、私は今理解している:)偉大な説明 – Adi

2
myConcat xs = foldr (++) [] 

は、他の2つの[[a]] -> [a]のタイプと同じでないタイプt -> [[a]] -> [a]を有しています。

myConcat xs = foldr (++) [] xs 

これは、通常の方法であるfoldrによって消費された引数を、提供:

3

まあ、のはcurried functionfoldrための型シグネチャを見てみましょう:だから

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

foldrはバイナリ関数を受け取り(すなわちa->b->b)、b値、a値のリスト、および返しますb値。

するのは、より明確な定義を取得するためのfoldrdocumentationを見てみましょう:

foldrを、二項演算子、開始値(オペレータの通常 右アイデンティティ)に適用され、

をそれでは、myConcat xs = foldr (++) []

のための型シグネチャを見てみましょう:リストには、右から左へ、 二項演算子を使用してリストを削減します
> :t myConcat 
myConcat :: t -> [[a]] -> [a] 

うーん...それは我々が望んでいないのです...

問題は、あなたがタイプ[a]foldr値を提供したことがないということです。だから今、myConcatはタイプ[a]の値は以下のように、foldr (++) []を完了するために、xsを満たすために、どのようなタイプの、いくつかの値を必要とします:作品

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

が、最初の引数は無駄です。しかし

、我々は同様に、foldr (++) []にかけてそのxs値を渡す場合:

myConcat xs = foldr (++) [] xs

とそのタイプの署名をチェック

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

はるかに良いああ、。これで、myConcatはxsを使用してfoldr関数を完了します。

また、myConcat = foldr (++) []も機能し、実際にはpoint-free style programmingの例です。我々はfoldr (++) []

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

の型シグネチャをチェックすると、我々はすでにpartial applicationを通じてfoldrその最初の二つの引数を提供しているので、我々は機能を得るバックという意志が[[a]]値を取り、我々がやりたいです!だから、名前に代入するだけです。上の例のように動作しますが、明示的に引数を渡す必要はありません!

> let myConcat = foldr (++) [] 
> :t myConcat 
myConcat :: [[a]] -> [a] 
> myConcat [[1,2],[3,4]] 
[1,2,3,4] 
+0

あなたの説明をありがとう、私は本当にあなたの助けに感謝:) – Adi