私は計画を学んでいます。ラムダ式とレット式の両方を使用する方法を知っています。
ただし、ラムダを使用することのポイントを理解するのに苦労しています。ラムダでできることをletですべて行うことはできませんか?
ラムダ式がletよりも優れた選択である状況の例を見ると特に役立ちます。
もう1つ-ラムダよりもletの方が便利な状況もありますか?もしそうなら、そのような例もいいでしょう。
編集:defineとlambdaは同様のタスクを実行しているように見えるので、それらを対比することにも興味があります。
みんな助けてくれてありがとう。私はあなたの答えを読んだ後、ラムダ/レット/定義をもう少し調べました、そして今それをもっとよく理解しています。
ラムダのクールな使用法の優れた例に出くわしました-プロシージャから無名関数を返します。たとえば、以下のプロシージャoperateTwice
は、プロシージャに渡されたパラメータに基づく無名関数を返します。
(define operateTwice
(lambda (op1 op2)
(lambda (x y)
(op2 (op1 x y) y))))
((operateTwice * +) 2 3) ;equivalent to: (+ (* 2 3) 3), or in standard notation 2*3+3
出力:
9
let
はlambda
です。
例えば。
(let ((x 1))
body)
に翻訳することができます
((lambda (x) body) 1)
さらに、Scheme allでは、制御と環境の構造は、ラムダ式とラムダのアプリケーションで表すことができます。
したがって、lambda
はlet
よりも厳密に強力であり、Schemeにある多くの興味深い構成の基礎を形成します。
define
とlambda
に関しては、トップレベルのdefine
がトップレベルの環境にバインディングを追加します。
あなたが書くとき
(define (f x)
body)
あなたは本当に言っています
(define f (lambda (x) body))
ネストされた定義はletrec
に変換され、ラムダを使用して書き換えることもできます。
したがって、繰り返しになりますが、多くのSchemeコンストラクトはlambda
を使用して何かに変換できるため、lambda
をよく理解することは非常に価値があります。
別の関数(たとえばlambda
など)への引数として使用する関数を作成する場合はmap
を使用しますが、実際には関数に名前を付けたくありません。
たとえば、リスト内のすべての番号に42を追加する場合は、次の操作を実行できます。
(define (add42 x) (+ x 42))
(map add42 (list 1 2 3 4))
ただし、これを1回だけ使用する関数に名前を付けたくない場合は、次のようにすることができます。
(map (lambda (x) (+ x 42)) (list 1 2 3 4))
実際には、Lambda式の省略形です。次の2つの式は同等です。
(let ((alpha 7)) (* 5 alpha))
((lambda (alpha) (* 5 alpha)) 7)
ラムダは、すべてが数学関数のように見えるべきであるという言語哲学に従います。しかし実際には、変数が多すぎる場合に何が起こっているのかを簡単に理解できるようにします。 Lambdaブロックの後に値が定義されている10個の変数を想像してみてください。それぞれの変数を変数名と一致させようとすると、変数の値が名前のすぐ隣に配置されます。プログラマーにとっては便利ですが、関数型にはあまり準拠していません。プログラミング哲学。
Lambdaを使用して、高階関数から関数を返すことができますが、それはできません。例えば:
(define (plus-list x)
(cond ((number? x)
(lambda (y) (+ (sum-n x) y)))
((list? x)
(lambda (y) (+ (sum-list x) y)))
(else (lambda (x) x))
))
> ((plus-list 3) 4)
10
> ((plus-list '(1 3 5)) 5)
14
> ((plus-list 'a) 5)
5
Lambdaを使用して、関数を関数に渡すこともできます。
>(map (lambda (x) (+ 1 x)) '(-1 2 -3))
(0 3 -2)
lambdaは新しい無名関数を作成します。もちろん、それらを使用するたびに評価されます。
letは値の一時的な名前を作成し、letフォームで定義されたスコープで使用するために一度設定されます。
彼らは本当に非常に異なる獣です。
いくつかの例 :
(ラムダ(x)(* 5 x))
(let([x 2])(* 5 x))10(let([f(lambda(x)(* 5 x))])(f 2))10
最初の形式は、5を掛ける関数を作成します
2番目の形式はxに2を割り当て、それを5で乗算すると、10になります。
3番目に、1の関数(5で乗算)を使用し、パラメーターとして2を使用して呼び出すと、10になります。
Schemeでは、プロシージャ(または関数)は、リスト、数値、文字列などのファーストクラスのオブジェクトです。リストリテラルを作成するには、list
というプリミティブを使用します。
> (define marks (list 33 40 56))
> marks
> (33 40 56)
このように、プロシージャを作成するには、lambda
プリミティブ(または特殊な形式)を使用します。
> (define add-marks (lambda (m) (apply + m)))
> (add-marks marks)
> 129
プロシージャは抽象化の主要な形式であるため、Schemeはdefine
にショートカットを提供して、新しいプロシージャを簡単にバインドできるようにします。
> (define (add-marks m) (apply + m))
これを除けば、プロシージャは他のすべてのファーストクラスオブジェクトとまったく同じです。それらは引数として他のプロシージャに渡すことができ、プロシージャは別のプロシージャを生成(または返す)するために評価できます。
あなたはそれをそのように考えることができます...あなたは別の関数を使用する関数を作成しますが、物事をよりモジュール化したいので、最初の関数の引数として2番目の関数を呼び出すことです。別の機能が必要だと感じたらいつでも秒を変更してください...それが理にかなっていることを願っています