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


54

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

.netでオブジェクトについて話す場合、「関数」と「メソッド」は同じ意味で使用できると言われています。「ラムダ」と「関数」が同じことを意味するのか疑問に思っています。ギリシャ文字のラムダ(λ)がこのサイトの非常に多くのアバターに登場しているのを見て、「ラムダ」には難解な意味があるのだろうか。物事をさらに混乱させるために、.netでは、C#の機能部分は別の関数に渡される関数式を「ラムダ式」と呼んでいます。

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

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


3
Nitpick-少なくともC#/。NETのドキュメントに関する限り、「ラムダ関数」ではなく「ラムダ式」と呼ばれます。
-Oded

@ TWith2Sugars-メッセージを読みます。あなたの答えはほとんどリンクにすぎないので低品質なので、コメントに変換されました。
-Oded

17
I wonder if 'lambda' has some esoteric meaning, seeing that the Greek letter lambda (λ) appears in so many avatars on this site.ラムダ計算に関連することを願っていますが、Half Lifeはラムダアバターのせいだと不思議に思います。
ヤニス

3
結構

@ZaphodBeeblebrox:半減期の影響については正しいと思います。:/
FrustratedWithFormsDesigner

回答:


44

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

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

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


1
それは非常にラフです。あなたは、使用define(またはletまたはその親族の1、または内部は定義)の名前を作成する-それがすべてです。define関数に関して特別なことは何もありません。
エリバルジレイ

2
@EliBarzilayまあ、define ありません(つまり、あなたが書くことができる機能を定義するための特殊な形式を持っている(define (f x) (foo))代わりにする(define f (lambda (x) (foo))))、しかし、私のポイントは、あなたが使用してという名前の関数を作成することはできませんということであったlambdaだけでは、同様にあなたが何かを書くことができない、つまり(lambda f (x) (foo))名前の関数を定義しますfJavascriptのfunctionキーワードでできるように、1つの引数を取ります。
sepp2k

1
defineそれは構文的な糖としてあるため、すべての値の名前バインディングツールとしての役割ほど重要ではありません。lambda名前をそれ自体で作成しないことに関しては、それは重要な機能です。関数フォームから名前の付与を分離しているためです... IMO JSは、名前のない関数のアイデア。(そして幸いなことに、これらの質量のサイズは一般的に減少しています...)
エリバルジレイ

18

ラムダは、単に匿名の関数、つまり名前のない関数です。


4
注かなり:ラムダは、宣言されたコンテキストからスナッグする状態を含むことができます(クロージャのように)。
マーティンヨーク

7
言語でネストされた関数を宣言できる場合、名前付き関数も可能です。
cHao

4
「低品質の投稿」レビュータブに入れて、賛成票を投じてくれたことを評価してください。
ヤニス

@ZaphodBeeblebrox-意図的ではなく、保証できます。
-Oded

そうでもない、lambdaスキームの式は同じようにあるfunction名前のない表現- しかし、後でそれらに名前を与えることからあなたを止めるものは何もありません。たとえばvar f = [function(x){return x;}][0]。あなたは...関数値自体は名前がありませんが、それはすべての関数の真のだろうと主張することができ
イーライBarzilay


8

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

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

式ラムダ:

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

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

(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

+1ラムダは匿名関数であると多くの人が言及していますが、それ以上のことがあります。ラムダの本体(右側)は、多くの場合、ステートメントブロックではなくです。式である名前付き関数の本体は、通常、関数型言語では許可されています(または必須です)が、命令型言語では許可されていません。
ザンティエ

4

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

ロングバージョン

このトピックについて非常に興味深いと思うので、少し詳しく説明したいと思います。免責事項:私はずっと前にラムダ計算のコースを取りました。より良い知識を持つ誰かが私の答えに誤りを見つけた場合、私がそれを改善するのを手伝ってください。

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

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

ラムダ表記は、特定の入力値を変数にバインドするためのスキーマを提供します。ラムダ式を添加することによって形成することができλx .、例えば、既存の発現の前にλx . x + 1。変数x自由x + 1束縛されていると言われていますλx . x + 1

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

(λx . x + 1) 2

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

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

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

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

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

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

(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などの一部の言語は、(名前付き)関数を定義するための後者の表記法のみをサポートしています。

閉鎖

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

\x -> x + y

まだ無料の変数が含まれているため、これは(まだ)関数ではありませんyy同様にバインドすることで、それから関数を作成できます。

\x -> \y -> x + y

または

\x y -> x + y

これは+関数とまったく同じです。

ただしy、別の方法でバインドすることもできます(*):

incrementBy y = \x -> x + y

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

だから、incrementBy 55で数字をインクリメント機能(閉鎖)です。

注意 (*)

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

incrementBy y = \x -> x + y

と同等です

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

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


Imは単なる初心者ですが、定数と呼ぶものは変数と呼ばれ、記号a、b、cで示されるため、数学的な意味でλ計算を理解しようとしている場合、これは少し混乱する可能性があると思います...呼び出し変数は未決定の変数 xになります。一方、1にλであるF XF X 2はλであるF Xff x)など。
jinawee

@jinawee:私は正確な定義を調べなかったことを認めます。論理で変数と定数という用語を使用したことを覚えています。そこでは、定数はドメインにマッピングされるシンボルですが、変数は定量化できるシンボルです。しかし、繰り返しますが、(1)論理学のコースを受講してからかなり前のことです。(2)ラムダ計算は、数学論理の概念1-1に従う必要はありません。参照先を教えていただければ、用語を修正することができます。
ジョルジオ

0

プログラミングにおける「ラムダ」は、通常「ラムダ関数」(または「ラムダ式」、「ラムダ項」)を意味します。関数がその使用前に定義された名前付きコードブロックである場合、「ラムダ関数」は、プログラミング言語の第一級市民として使用できる使用の代わりに定義されたコードブロック(または式)です。

JavaScript ES6(2015)には、「矢印関数」と呼ばれるラムダを定義する短い構文があります。C#では、そのような構文が.NET 3.0(2006年ごろ)で導入されました

数学では、「関数」の概念にはいくつかの意味があり、その意味の1つは関数の表記法(つまり、書き方)であり、「ラムダ関数」(計算)は特別な種類の関数表記法です。詳細については、プログラミング言語のラムダ関数を確認してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.