8

Haskellのラムダ関数(つまり無名関数)を使用するいくつかの簡単な関数を記述して、それらを理解しようとしています。

次の例では、3つのパラメーターを取り込んで、匿名関数を使用して3つのうち2つを追加し、その後に3番目のパラメーターを追加しようとしています。最初にインスタンスを宣言する必要があるというエラーが表示されます。

specialAdd x y z = (\x y -> x + y) + z

私の例が機能しない理由の説明や、ラムダ関数をよりよく理解するのに役立つ説明に感謝します。

4

5 に答える 5

17

specialAdd x y z = (\x y -> x + y) + z

この例では、実行しようとしているのは、機能しない関数を数値に追加することです。見てください(\x y -> x + y) + z:それは形をしていa + bます。このような表現が機能するためには、aパーツとbパーツが同じタイプの番号である必要があります。

Haskellは少し変わった言語なので、エラーメッセージが「それができない」という形式になることはめったにありません。つまり、ここで起こっていることは、Haskellがそれ(\x y -> x + y)を関数と見なしていることです。また、のような式では、と同じ型である必要があるためa + b、これも関数である必要があると結論付けます。Haskellでは、組み込み以外のタイプを追加するための独自のルールを定義することもできます。したがって、「2つの関数を追加できません」というエラーが表示されるだけでなく、「2つの関数を追加できるルールが定義されていません」というエラーが表示されます。bab

以下はあなたが望むことをするでしょう:

specialAdd x y z = ((\x y -> x + y) x y) + z

ここでは、関数(\x y -> x + y)を引数xyに適用してから、結果をに追加していzます。

于 2013-03-27T15:34:57.370 に答える
10

匿名関数を練習する良い方法は、フォールドまたはマップとして高階関数でそれらを使用することです。

マップをエントリポイントとして使用して、

マップの基本的な定義、

map f [] = []
map f (x:xs) = f x : f xs  

例を作成し、

>>> let list = [0..4]
>>> let f x = x + 1

得られた地図を適用して、

>>> map f list 
[1,2,3,4,5]

これで、fの宣言を省略し、無名関数を使用して置き換えることができます。

>>> map (\x->x+1) list 
[1,2,3,4,5]

次に、 map f list == map(\ x-> x + 1)listを推定し ます。したがって、

f = \x-> x + 1 --- The same as f x = x + 1, but this is the equivalent lambda notation.  

次に、単純な関数から始めて、無名関数に変換する方法と、無名関数をラムダ抽象化に依存する方法を確認します。

演習として、fx = 2*xを変換してみてください。

今ではもっと複雑で、2つの引数を取る無名関数、

再び実用的な例、

>>> let add x y = x + y
>>> foldl' add 0 [0..4]
10

次のように無名関数を使用して書き換えることができます、

>>> foldl' (\x y -> x + y) 0 [0..4]  

再び等式を使用して、add = \ xy-> x + yと推定し
ます。さらに、hakellの場合と同様に、すべての関数は1つの引数の関数であり、部分的に適用できます。以前の無名関数を次のように書き換えることができます。add= \ x->( \ y-> x + y)。

では、トリックはどこにありますか?なぜなら、無名関数の使用法を高次のものに示し、それから始めて、ラムダ表記を使用して関数を書き換えるためにこれをどのように利用できるかを示しています。つまり、無名関数を書き留める方法を学ぶのにどのように役立つのでしょうか?

高階関数を使用した既存のフレームワークを提供(表示)したからです。
このフレームワークは、この表記法に対応するための大きな機会です。
それから始めて、無限の範囲の運動を推測することができます。たとえば、次のようにしてみてください。

A - Find the corresponding anonymous function ?

1 - let f (x,y) = x + y in map f [(0,1),(2,3),(-1,1)]  
2 - let f x y = x * y in foldl' f 1 [1..5] 

B - Rewrite all of them using lambda notation into a declarative form (f = \x-> (\y-> ...) 

等々 ....


要約する、

としての機能

(F0)   f x1 x2 ... xn = {BODY of f}

いつでも次のように書き換えることができます、

(F1)   f = \x1 x2 ... xn -> {BODY of f}

どこ

(F2)   (\x1 x2 ... xn -> {BODY of f})

F2形式は単なる無名関数であり、関数をラムダ計算形式に純粋に変換したものです。F1は宣言型ラムダ表記です(fを定義するときにfを宣言し、匿名F2にバインドするため)。F0はHaskellerの通常の表記法です。

引数の間に括弧を入れることができるという事実に焦点を当てた最後のメモ、これはクロージャを作成します。これは、関数の引数のサブセットを使用して関数のコードのサブセットを完全に評価できることを意味します(つまり、自由変数が発生しない形式に変換することを意味します)が、それは別の話です。

于 2013-03-27T14:31:05.723 に答える
3

正しい形式は次のとおりです。
specialAdd a b c = ((\x y -> x + y) a b) + c

Learn You a Haskellの例...:
zipWith (\a b -> (a * 30 + 3) / b) [5,4,3,2,1] [1,2,3,4,5]

すばらしい説明: http: //learnyouahaskell.com/higher-order-functions#lambdas

于 2013-03-27T13:41:46.303 に答える
2

私が理解していることから、Labmbda /匿名関数は、名前を付ける必要なしに関数を「インライン」で宣言するのに役立ちます。「\」(ギリシャ語のASCII、λ)は、「->」に続く式の変数名の前にあります。例えば、

(\x y -> x + y) 

(+)に似た無名(ラムダ)関数です。タイプNumの2つのパラメーターを受け取り、それらの合計を返します。

Prelude> :type (+)
(+) :: Num a => a -> a -> a

Prelude> :type (\x y -> x + y)
(\x y -> x + y) :: Num a => a -> a -> a

他の人が指摘しているように、その右側はデフォルトで定義されている(+)演算子のパラメーターとしてラムダ関数(\ xy-> x + y)を使用しているため、この例は機能していません。タイプNumのパラメーターの場合のみ。ラムダ関数の美しさのいくつかは、その「匿名」使用にあります。ウラジミールは、左側から変数を渡すことで、宣言でラムダ関数を使用する方法を示しました。より「匿名の」使用法は、関数に名前を付けずに(したがって匿名で)、変数を使用して単純に呼び出すことです。例えば、

Prelude> (\x y z -> x + y + z) 1 2 3
6

and if you like writing parentheses:

Prelude> (((+).) . (+)) 1 2 3
6

または、より長い式(例の宣言のように)で、たとえば、

Prelude> filter (\x -> length x < 3) [[1],[1,2],[1,2,3]]
[[1],[1,2]]
于 2013-03-28T04:21:10.533 に答える
1

あなたは正しくない(+)ようなものとして使用しようとしています。(Num a) => (a -> a -> a) -> a -> ??

(+)はクラスで定義されておりNum、(a-> a-> a)はこのクラスのインスタンスではありません。

正確に何を達成しようとしていますか?

于 2013-03-27T13:42:29.367 に答える