ラムダとは何ですか、なぜ有用なのでしょうか?[閉まっている]


56

これまで私は聞いた:

  • ラムダ計算
  • ラムダプログラミング
  • ラムダ式
  • ラムダ関数

すべてが関数型プログラミングに関連しているようです...

どうやらそれはC ++ 1xに統合されるので、今よりよく理解するかもしれません:

http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

誰かがラムダのことを簡単に定義して、それがどこで役立つかを教えてもらえますか?


2
用語は歴史的に、式で表される関数について話す良い方法を望んでいることに注意してください。x + 1で表される関数は、ラムダxと記述されます。x + 1。
カステルマ

ラムダ式では、関数は別の関数および/または入力値を食べて、別の関数を生成します。これは、関数がソリューションを生成するまで続きます。また、ワニの卵
SD

私にとってはギリシャ語です。私はジャイロを持って行くと思う、私は子羊が好きだ、当たり前。

回答:


44
  • ラムダ計算

ラムダ計算は、30年代にアロンゾ教会によって発明された計算モデルです。ほとんどの関数型プログラミング言語の構文とセマンティクスは、ラムダ計算に直接的または間接的に影響を受けています。

最も基本的な形式のラムダ計算には、抽象化((匿名)関数の作成)とアプリケーション(関数の適用)の2つの操作があります。抽象化はλ演算子を使用して実行され、ラムダ計算に名前が付けられます。

  • ラムダ式
  • ラムダ関数

匿名関数はよく「ラムダ」、「ラムダ関数」、または「ラムダ式」と呼ばれます。前述したように、ラムダ計算でラムダが匿名関数を作成するための記号であったためlambdaです同じ理由でベースの言語)。

  • ラムダプログラミング

これは一般的に使用される用語ではありませんが、匿名関数を使用したプログラミングまたは高階関数を使用したプログラミングを意味すると思います。


C ++ 0xのラムダに関するもう少しの情報、その動機、およびそれらが関数ポインターにどのように関係するか(これの多くはおそらくあなたがすでに知っていることの繰り返しですが、ラムダの動機とそれらがどのように異なるかを説明するのに役立つことを願っています関数ポインタから):

Cに既に存在する関数ポインターは、たとえば比較関数をソート関数に渡す場合に非常に便利です。ただし、その有用性には制限があります。

たとえば、ベクトルのベクトルiを各ベクトルのth要素(i実行時パラメーター)で並べ替える場合、関数ポインターでこれを解決することはできません。ith要素で2つのベクトルを比較する関数は、3つの引数(iおよび2つのベクトル)を取る必要がありますが、ソート関数には2つの引数を取る関数が必要です。必要なのはi、ソート関数に渡す前に何らかの方法で関数に引数を提供する方法ですが、プレーンなC関数ではこれを行うことができません。

これを解決するために、C ++は「関数オブジェクト」または「ファンクター」の概念を導入しました。ファンクターは、基本的にoperator()メソッドを持つオブジェクトです。これでclassを定義できます。このクラスCompareByIthElementi、コンストラクター引数として引数を受け取り、メソッドへの引数として比較される2つのベクトルを受け取りますoperator()ith要素でベクトルのベクトルを並べ替えるために、引数としてを使用してCompareByIthElementオブジェクトを作成し、iそのオブジェクトを並べ替え関数に渡すことができます。

関数オブジェクトは単なるオブジェクトであり、技術的には関数ではないため(関数のように動作することを意図している場合でも)、関数ポインターを関数オブジェクトを指すようにすることはできません(もちろん関数オブジェクトへのポインターを持つことはできますが、のような型を持つためCompareByIthElement*、関数ポインタではありません)。

関数を引数としてとるC ++標準ライブラリのほとんどの関数は、テンプレートを使用して定義されるため、関数オブジェクトだけでなく関数ポインターも使用できます。

ラムダについて:

クラス全体を定義してith要素で比較するのは、ベクトルをソートするために一度だけ使用する場合は少し冗長です。関数ポインターのみが必要な場合でも、名前付き関数の定義は、a)名前空間を汚染し、b)関数は通常非常に小さくなり、実際には存在しないため、一度しか使用されない場合は次善ですロジックを独自の関数に抽象化する正当な理由(関数を定義しないと関数ポインタを取得できないことを除く)。

そのため、このラムダを修正するために導入されました。ラムダは関数オブジェクトであり、関数ポインターではありません。[x1, x2](y1,y2){bla}基本的に次のことを行うコードのようなラムダリテラルを使用する場合:

  1. 2つのメンバー変数(x1x2)とoperator()、引数(y1y2)とbody を持つ1つのクラスを定義しblaます。
  2. メンバ変数の設定、クラスのインスタンスを作成x1し、x2変数の値にx1し、x2現在のスコープ内。

そのため、ラムダは関数オブジェクトのように動作しますが、ラムダを使用する以外の方法でラムダを実装するために生成されたクラスにアクセスすることはできません。したがって、ファンクターを引数として受け入れる関数(基本的には標準ライブラリの非C関数を意味します)はラムダを受け入れますが、関数ポインターのみを受け入れる関数は受け入れません。


関数ポインターで匿名関数を使用しますか?そうでない場合、違いは何ですか?
jokoon

1
@jokoon:いいえ、関数ポインタのみを受け取る関数に匿名関数をパラメータとして渡すことはできません。ただし、関数を引数として取るほとんどの関数はテンプレートを使用して定義されているため、関数ポインターだけでなく、あらゆる種類の関数オブジェクトを引数として取ることができます。つまり、関数ポインター(std::sortたとえば)を使用できるほとんどの場所で、代わりに匿名関数を使用できます。ただし、匿名関数を引数として使用する関数を定義する場合は、テンプレートを使用するかstd::function、引数の型として使用する必要があります。
sepp2k

その関数ポインタは、ラムダを含めることはできません...
jokoon

1
+1優れた説明-私もそれを見つけることができませんでした。
マイケルK

2
私はこれについてマイケルと一緒です。これは非常に包括的なものです。+1私から。
sbi

18

基本的に、ラムダ関数は「オンザフライ」で作成する関数です。C ++ 1xでは、関数プログラミングのサポートを改善するために使用できます。

std::for_each( begin, end, [](int i){std::cout << i << '\n';} );

これにより、おおよそ次のようなコードが生成されます。

struct some_functor {
  void operator()(int i) {std::cout << i << '\n';}
};

std::for_each( begin, end, some_functor() );

some_functorこの1回の呼び出しだけが必要な場合std::for_each()、そのラムダ関数にはいくつかの利点があります。

  • ループで行われることは、ループ関数が呼び出される場所で指定されます
  • ボイラープレートコードのいくつかを書くことからあなたを解放します
  • 誰もがコードが何のために必要なのか不思議に思うような名前空間スコープには、ファンクタがありません。

7

ラムダ関数は、匿名関数の別の名前です-基本的に名前のない関数です。

通常、これは関数を1回だけ使用する必要がある言語で使用します。たとえば

def add(a, b)
  return a+b

そしてその関数を別の関数に渡します

reduce(add, [5,3,2])

ラムダを使用すると、単純に

reduce(lambda x, y: a+b, [5,3,2])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.