これまで私は聞いた:
- ラムダ計算
- ラムダプログラミング
- ラムダ式
- ラムダ関数
すべてが関数型プログラミングに関連しているようです...
どうやらそれはC ++ 1xに統合されるので、今よりよく理解するかもしれません:
http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions
誰かがラムダのことを簡単に定義して、それがどこで役立つかを教えてもらえますか?
これまで私は聞いた:
すべてが関数型プログラミングに関連しているようです...
どうやらそれはC ++ 1xに統合されるので、今よりよく理解するかもしれません:
http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions
誰かがラムダのことを簡単に定義して、それがどこで役立つかを教えてもらえますか?
回答:
ラムダ計算は、30年代にアロンゾ教会によって発明された計算モデルです。ほとんどの関数型プログラミング言語の構文とセマンティクスは、ラムダ計算に直接的または間接的に影響を受けています。
最も基本的な形式のラムダ計算には、抽象化((匿名)関数の作成)とアプリケーション(関数の適用)の2つの操作があります。抽象化はλ演算子を使用して実行され、ラムダ計算に名前が付けられます。
匿名関数はよく「ラムダ」、「ラムダ関数」、または「ラムダ式」と呼ばれます。前述したように、ラムダ計算でラムダが匿名関数を作成するための記号であったためlambda
です同じ理由でベースの言語)。
これは一般的に使用される用語ではありませんが、匿名関数を使用したプログラミングまたは高階関数を使用したプログラミングを意味すると思います。
C ++ 0xのラムダに関するもう少しの情報、その動機、およびそれらが関数ポインターにどのように関係するか(これの多くはおそらくあなたがすでに知っていることの繰り返しですが、ラムダの動機とそれらがどのように異なるかを説明するのに役立つことを願っています関数ポインタから):
Cに既に存在する関数ポインターは、たとえば比較関数をソート関数に渡す場合に非常に便利です。ただし、その有用性には制限があります。
たとえば、ベクトルのベクトルi
を各ベクトルのth要素(i
実行時パラメーター)で並べ替える場合、関数ポインターでこれを解決することはできません。i
th要素で2つのベクトルを比較する関数は、3つの引数(i
および2つのベクトル)を取る必要がありますが、ソート関数には2つの引数を取る関数が必要です。必要なのはi
、ソート関数に渡す前に何らかの方法で関数に引数を提供する方法ですが、プレーンなC関数ではこれを行うことができません。
これを解決するために、C ++は「関数オブジェクト」または「ファンクター」の概念を導入しました。ファンクターは、基本的にoperator()
メソッドを持つオブジェクトです。これでclassを定義できます。このクラスCompareByIthElement
はi
、コンストラクター引数として引数を受け取り、メソッドへの引数として比較される2つのベクトルを受け取りますoperator()
。i
th要素でベクトルのベクトルを並べ替えるために、引数としてを使用してCompareByIthElement
オブジェクトを作成し、i
そのオブジェクトを並べ替え関数に渡すことができます。
関数オブジェクトは単なるオブジェクトであり、技術的には関数ではないため(関数のように動作することを意図している場合でも)、関数ポインターを関数オブジェクトを指すようにすることはできません(もちろん関数オブジェクトへのポインターを持つことはできますが、のような型を持つためCompareByIthElement*
、関数ポインタではありません)。
関数を引数としてとるC ++標準ライブラリのほとんどの関数は、テンプレートを使用して定義されるため、関数オブジェクトだけでなく関数ポインターも使用できます。
ラムダについて:
クラス全体を定義してi
th要素で比較するのは、ベクトルをソートするために一度だけ使用する場合は少し冗長です。関数ポインターのみが必要な場合でも、名前付き関数の定義は、a)名前空間を汚染し、b)関数は通常非常に小さくなり、実際には存在しないため、一度しか使用されない場合は次善ですロジックを独自の関数に抽象化する正当な理由(関数を定義しないと関数ポインタを取得できないことを除く)。
そのため、このラムダを修正するために導入されました。ラムダは関数オブジェクトであり、関数ポインターではありません。[x1, x2](y1,y2){bla}
基本的に次のことを行うコードのようなラムダリテラルを使用する場合:
x1
とx2
)とoperator()
、引数(y1
とy2
)とbody を持つ1つのクラスを定義しbla
ます。x1
し、x2
変数の値にx1
し、x2
現在のスコープ内。そのため、ラムダは関数オブジェクトのように動作しますが、ラムダを使用する以外の方法でラムダを実装するために生成されたクラスにアクセスすることはできません。したがって、ファンクターを引数として受け入れる関数(基本的には標準ライブラリの非C関数を意味します)はラムダを受け入れますが、関数ポインターのみを受け入れる関数は受け入れません。
std::sort
たとえば)を使用できるほとんどの場所で、代わりに匿名関数を使用できます。ただし、匿名関数を引数として使用する関数を定義する場合は、テンプレートを使用するかstd::function
、引数の型として使用する必要があります。
+1
私から。
基本的に、ラムダ関数は「オンザフライ」で作成する関数です。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()
、そのラムダ関数にはいくつかの利点があります。
ラムダ関数は、匿名関数の別の名前です-基本的に名前のない関数です。
通常、これは関数を1回だけ使用する必要がある言語で使用します。たとえば
def add(a, b)
return a+b
そしてその関数を別の関数に渡します
reduce(add, [5,3,2])
ラムダを使用すると、単純に
reduce(lambda x, y: a+b, [5,3,2])