web-dev-qa-db-ja.com

関数とラムダの違いは何ですか?

「関数」と「ラムダ」について少し混乱しています。スキーマキーワードlambdaがJavaScriptキーワードfunctionと非常によく似ていることを示す例をいくつか見ましたが、それらがどのように関連しているかは本当にわかりません。

.netのオブジェクトについて話すとき、「関数」と「メソッド」は互換的に使用できると言われています。 「ラムダ」と「関数」が同じように同じことを意味するのだろうかと思います。 「lambda」には難解な意味があるのでしょうか。ギリシャ語のラムダ(λ)がこのサイトの非常に多くのアバターに表示されているのを見てください。さらに混乱を招くように、.netでは、C#の機能部分が別の関数に渡される関数式を「ラムダ式」と呼んでいるため、Wordはあちこちにあるようです。

私はまた、「ラムダ計算」という用語に漠然と精通しています。

関数とラムダの違いは何ですか?

54

「ラムダ」または「ラムダ式」という言葉は、ほとんどの場合、無名関数を指します。したがって、その意味ではラムダは一種の関数ですが、すべての関数がラムダであるとは限りません(つまり、名前付き関数は通常ラムダと呼ばれません)。言語によっては、匿名関数は名前付き関数とは異なる方法で実装されることが多く(特に、匿名関数がクロージャーで名前付き関数がそうでない言語では)、異なる用語でそれらを参照することは意味があります。

スキームのラムダキーワードとJavascriptの関数キーワードの違いは、後者は匿名関数と名前付き関数の両方を作成するために使用できるのに対し、前者は匿名関数のみを作成することです(そして名前付き関数の作成にはdefineを使用します)。

ラムダ計算は最小のプログラミング言語/計算の数学モデルであり、関数を唯一の「データ構造」として使用します。ラムバ計算では、ラムダ記号を使用して(無名の)関数を作成します。これが、他の言語での「ラムダ」という用語の使用法の由来です。

44
sepp2k

ラムダは単に無名関数です-名前のない関数です。

19
Oded

ここで回答: https://stackoverflow.com/questions/16501/what-is-a-lambda-function

基本的にラムダは無名関数です。

9
TWith2Sugars

C#では匿名関数は、ラムダ式と匿名メソッドの両方を含む一般的な用語です(匿名メソッドは、実際のメソッド宣言のないデリゲートインスタンスです)。

ラムダ式は、式ラムダおよびステートメントラムダに分解できます。

式ラムダ:

(int x, string y) => x == y.Length 

ステートメントラムダは、ステートメントが中括弧で囲まれていることを除いて、式ラムダに似ています。

(int x, string y) => {
         if (x == y.Length) {
             Console.WriteLine(y);
         }
}

JavaScriptのラムダ式について話すとき、それは基本的に、関数を別の関数の呼び出しで引数として使用することを意味します。

var calculate = function(x, y, operation){
    return operation(x, y);
}

// we're passing anonymous function as a third argument
calculate(10, 15, function(x, y) {
    return x + y;
}); // 25
8
Christian P

TL; DR他の人が指摘したように、ラムダ表記は、関数に名前を付けることを強制されずに関数を定義するための方法にすぎません。

ロングバージョン

このトピックについては、非常に興味深いと思うので、少し詳しく説明します。免責事項:私はずっと前にラムダ計算のコースを受講しました。知識が豊富で誰かが私の回答に不正確な点を見つけた場合は、遠慮なく改善してください。

式から始めましょう。 1 + 2およびx + 212などのリテラルは、特定の固定値にバインドされているため、定数と呼ばれます。

xなどの識別子はvariableと呼ばれ、それを評価するために、まず何らかの値にバインドする必要があります。したがって、xが何であるかを知らない限り、基本的にx + 1を評価することはできません。

ラムダ表記は、特定の入力値を変数にバインドするためのスキーマを提供します。 ラムダ式は、既存の式の前にλx .を追加することで形成できます。 λx . x + 1。変数xx + 1ではfreeであり、λx . x + 1ではboundであると言われています

これは式の評価にどのように役立ちますか?次のようにラムダ式に値をフィードすると

(λx . x + 1) 2

次に、変数xのすべての出現箇所を値2に置き換える(バインドする)ことにより、式全体を評価できます。

(λx . x + 1) 2
      2 + 1
      3

したがって、ラムダ表記は、式/プログラムブロックに現れる変数に物事をバインドするための一般的なメカニズムを提供します。コンテキストに応じて、これはプログラミング言語に視覚的に異なる概念を作成します。

  • Haskellのような純粋に関数型の言語では、ラムダ式は数学的な意味でfunctionsを表します。入力値がラムダの本体に注入され、出力値が生成されます。
  • 多くの言語(JavaScript、Python、Schemeなど)では、ラムダ式の本体を評価すると副作用が生じる可能性があります。この場合、用語procedureを使用して、純粋な関数の違いをマークできます。

違いは別として、ラムダ表記は仮パラメータを定義し、それらを実際のパラメータにバインドすることです。

次のステップは、関数/プロシージャに名前を付けることです。いくつかの言語では、関数は他の関数と同様に値であるため、次のように関数に名前を付けることができます。

(define f (lambda (x) (+ x 1)))      ;; Scheme

f = \x -> x + 1                      -- Haskell

val f: (Int => Int) = x => x + 1     // Scala

var f = function(x) { return x + 1 } // JavaScript

f = lambda x: x + 1                  # Python

Eli Barzilayが指摘したように、これらの定義は名前fを値にバインドするだけで、これはたまたま関数です。したがって、この点で、関数、数値、文字列、文字はすべて同じ方法で名前にバインドできる値です。

(define n 42)   ;; Scheme

n = 42          -- Haskell

val n: Int = 42 // Scala

var n = 42      // JavaScript

n = 42          # Python

これらの言語では、より一般的な(ただし同等の)表記を使用して、関数を名前にバインドすることもできます。

(define (f x) (+ x 1))         ;; Scheme

f x = x + 1                    -- Haskell

def f(x: Int): Int = x + 1     // Scala

function f(x) { return x + 1 } // JavaScript

def f(x): return x + 1         # Python

一部の言語、たとえばC、(名前付き)関数を定義するための後者の表記のみをサポートします。

閉鎖

closuresに関するいくつかの最終的な観察。式x + yを考えます。これには2つの自由変数が含まれます。ラムダ表記を使用してxをバインドすると、次のようになります。

\x -> x + y

これは(まだ)関数ではありません。これは、フリー変数yがまだ含まれているためです。 yをバインドすることで、関数を作成することもできます。

\x -> \y -> x + y

または

\x y -> x + y

これは、+関数と同じです。

しかし、たとえばyを別の方法でバインドできます(*):

incrementBy y = \x -> x + y

関数incrementByを数値に適用した結果はクロージャです。つまり、クロージャが定義された環境からの値にバインドされた自由変数(yなど)をボディに含む関数/プロシージャです。

したがって、incrementBy 5は、数値を5ずつ増やす関数(クロージャ)です。

注(*)

私はここで少し浮気しています:

incrementBy y = \x -> x + y

に相当

incrementBy = \y -> \x -> x + y

バインドのメカニズムは同じです。直感的に、クロージャーは、より複雑なラムダ式のチャンクを表すものと考えています。この表現が作成されるとき、マザー式のバインディングの一部はすでに設定されており、クロージャーは後で評価/呼び出されるときにそれらを使用します。

4
Giorgio

プログラミングにおける「ラムダ」は通常「ラムダ関数」(または「ラムダ式」、「ラムダ項」)も意味します。 functionが使用前に定義された名前付きコードのブロックである場合、「ラムダ関数」は、プログラミング言語のファーストクラスシチズンとして使用できる使用法の代わりに定義されたコード(または式)のブロックです。

JavaScript ES6(2015)には、ラムダを定義するための短い構文 "矢印関数" があります。 C#では、このような構文 。NET 3.0で導入されました(2006年頃)

数学では、「関数」の概念にはいくつかの意味があり、その意味の1つは関数の表記(つまり、それをどのように書き留めるか)に関するものであり、「ラムダ関数」(微積分)は特別な種類の関数表記です。詳細については、 プログラミング言語のラムダ関数 を確認してください。

0
battlmonstr