コンピュータプログラミングにおいて、匿名関数(関数リテラル、ラムダ関数、またはブロック)とは、識別子に束縛されない関数定義のことです。匿名関数は、多くの場合、高階関数に渡される引数として、または関数を返す必要がある高階関数の結果を構築するために使用されます。[ 1 ] 関数が一度だけ、または限られた回数しか使用されない場合、匿名関数は名前付き関数を使用するよりも構文的に簡潔になることがあります。匿名関数は、関数型プログラミング言語や、第一級関数を持つ他の言語で広く使用されており、関数型に対して、他のデータ型に対するリテラルと同じ役割を果たします。
匿名関数は、電子計算機が登場する前の1936年に、すべての関数が匿名であるラムダ計算を発明したアロンゾ・チャーチの研究に端を発しています。 [ 2 ]いくつかのプログラミング言語では、匿名関数はキーワードlambdaを使用して導入され、匿名関数はしばしばラムダまたはラムダ抽象化と呼ばれます。匿名関数は、1958年のLisp以来、プログラミング言語の特徴となっており、匿名関数をサポートする現代のプログラミング言語は増え続けています。
「ラムダ抽象」、「ラムダ関数」、「ラムダ式」という名称は、ラムダ計算における関数抽象の表記法を指し、通常の関数は書かれるだろう、そしては、Python の構文と比較してください。lambdax:M
「矢印関数」という名前は、数学の「写像」記号を指します。JavaScript の構文と比較してください。[ 3 ]x=>M
匿名関数は、名前を付ける必要がなく、短期間または局所的な使用を目的とした機能をカプセル化できます。代表的な例としては、クロージャやカリー化が挙げられます。
匿名関数の使用はスタイルの問題です。匿名関数を使うことが問題を解決する唯一の方法であることは決してなく、各匿名関数は名前付き関数として定義し、名前で呼び出すこともできます。匿名関数は、名前付き関数を定義するよりも簡潔な表記を提供することがよくあります。ローカルスコープで名前付き関数を定義することを許可しない言語では、匿名関数はローカルスコープを介してカプセル化を提供できますが、そのような匿名関数の本体のコードは再利用できなかったり、個別のテストに適さなかったりする可能性があります。式で使用される短くシンプルな匿名関数は、個別に定義された名前付き関数よりも読みやすく理解しやすい場合がありますが、説明的な名前がないとコードの可読性が低下する可能性があります。
一部のプログラミング言語では、匿名関数は、イベントをコールバックにバインドしたり、特定の値に対して関数をインスタンス化したりするなど、非常に特定の目的のために一般的に実装されます。これは、動的プログラミング言語では、名前付き関数を呼び出すよりも効率的で、読みやすく、エラーが発生しにくい場合があります。
以下の例はPython 3で記述されています。
多くのプログラミング言語には、オブジェクトのリスト(または配列)を、2つのオブジェクトを比較して等しいか、あるいは一方が他方より大きいか小さいかを判定する比較関数によって決定される順序に並べ替える汎用関数が用意されています。汎用ソート関数に引数として渡される匿名比較関数式を使用する方が、名前付き比較関数を作成するよりも簡潔な場合が多いです。
文字列のリストを文字列の長さでソートするPythonコードを考えてみましょう。
a : list [ str ] = [ "house" , "car" , "bike" ] a . sort ( key = lambda x : len ( x )) print ( a ) # ['car', 'bike', 'house' と出力されます]この例における匿名関数はラムダ式です。
lambda x : len ( x )匿名関数は引数を1つ受け取りx、その引数の長さを返します。この長さは、sort()メソッドによってソートの基準として使用されます。
Pythonにおけるラムダ関数の基本的な構文は次のとおりです。
lambda arg1 , arg2 , arg3 , ... : <引数に対する値を返す操作>ラムダ関数によって返される式は、変数に代入してコード内の複数の場所で使用できます。
from typing import Callableadd : Callable [[ int ], int ] = lambda a : a + a print ( add ( 20 )) # 40 と出力別の例としては、リスト内の項目をクラス名でソートすることが挙げられます(Pythonでは、すべての項目にクラスがあります)。
a : list [ int | str ] = [ 10 , "number" , 11.2 ] a . sort ( key = lambda x : x . __class__ . __name__ ) print ( a ) # [11.2, 10, 'number'] と出力されます11.2はクラス名がfloat" 、10はクラス名がint" 、は'number'クラス名が " であることに注意してくださいstr。ソート順は " float、 " int、そしてstr" です。
クロージャとは、バインドされた変数を含む環境で評価される関数です。次の例では、入力値をこのしきい値と比較する匿名関数内で、変数「threshold」をバインドしています。
def comp ( threshold : int ) -> Callable [[ int ], bool ]: return lambda x : x < thresholdこれは、一種の比較関数生成器として使用できます。
func_a : Callable [[ int ], bool ] = comp ( 10 ) func_b : Callable [[ int ], bool ] = comp ( 20 )print ( func_a ( 5 ), func_a ( 8 ), func_a ( 13 ), func_a ( 21 )) # True True False False と出力されますprint ( func_b ( 5 ), func_b ( 8 ), func_b ( 13 ), func_b ( 21 )) # True True True False と出力されます考えられるすべての比較関数に対応する関数を作成するのは非現実的であり、閾値を保持して後で使用することも不便すぎる可能性があります。クロージャを使用する理由に関わらず、匿名関数は比較を行う機能を含むエンティティです。
カリー化とは、複数の引数を取る関数を、それぞれが単一の引数を取る一連の関数に変換する手法です。この例では、任意の整数による除算を行う関数が、特定の整数による除算を行う関数に変換されます。
def divide ( x : int , y : int ) -> float : return x / ydef divisor ( d : int ) -> Callable [[ int ], float ]: return lambda x : divide ( x , d )half : Callable [[ int ], float ] = divisor ( 2 ) third : Callable [[ int ], float ] = divisor ( 3 )print ( half ( 32 ), third ( 32 )) # 16.0 10.666666666666666print ( half ( 40 ), third ( 40 )) # 20.0 13.3333333333333334 と出力されます匿名関数はカリー化において一般的ではないかもしれませんが、使用することは可能です。上記の例では、関数 divisor は指定された除数を持つ関数を生成します。関数 half と third は、固定された除数を持つ割り算関数をカリー化します。
除数関数は変数を束縛することによっても閉包を形成しますd。
高階関数とは、関数を引数として受け取るか、関数を結果として返す関数のことです。この手法は、ループや再帰パターンなど、汎用的に定義された関数の動作をカスタマイズするためによく用いられます。匿名関数は、このような関数引数を指定する便利な方法です。以下の例はPython 3で記述されています。
map関数は、リストの各要素に対して関数呼び出しを実行します。次の例では、配列の各要素を匿名関数で二乗しています。
a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ( list ( map ( lambda x : x * x , a ))) # [1, 4, 9, 16, 25, 36] と出力されます匿名関数は引数を受け取り、その二乗を返します。上記の形式は言語開発者によって推奨されておらず、以下の形式が同じ意味を持ち、言語の理念により合致していると主張しています。
a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ([ x * x for x in a ]) # [1, 4, 9, 16, 25, 36] と出力されますフィルター関数は、特定の関数に渡されたときにTrueと評価されるリスト内のすべての要素を返します。
a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ( list ( filter ( lambda x : x % 2 == 0 , a ))) # [2, 4, 6] と出力されます匿名関数は、渡された引数が偶数かどうかをチェックします。map関数と同様に、以下の形式がより適切であると考えられます。
a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 , 6 ] print ([ x for x in a if x % 2 == 0 ]) # [2, 4, 6] と出力されますfold関数は、構造体内のすべての要素に対して実行され(リストの場合は通常左から右へ、reducePythonでは「左折り返し」と呼ばれる)、その都度値を蓄積します。これは、構造体のすべての要素を1つの値に結合するために使用できます。たとえば、次のようになります。
a : list [ int ] = [ 1 , 2 , 3 , 4 , 5 ] print ( functools . reduce ( lambda x , y : x * y , a )) # 120 と出力これは実行します
ここでの匿名関数は、2つの引数の乗算です。
foldは必ずしも単一のスカラー値を生成するとは限りません。リストなどの構造化された結果を生成することもできます。実際、foldを使用してmapとfilterの両方を作成できます。mapでは、蓄積される値は、元のリストの各要素に関数を適用した結果を含む新しいリストです。filterでは、蓄積される値は、指定された条件に一致する要素のみを含む新しいリストです。
以下は、名前のない匿名関数を完全にサポートしている、あるいは何らかの形で部分的にサポートしている、または全くサポートしていないプログラミング言語のリストです。
次の表は、いくつかの一般的なパターンを示しています。特に注目すべきは、従来匿名関数をサポートしていなかったC、Pascal、Object Pascal などの言語はすべて静的型付け言語であるということです。しかし、静的型付け言語でも匿名関数をサポートできます。たとえば、ML言語は静的型付け言語であり、基本的に匿名関数を含んでいます。また、 Object Pascalの方言であるDelphi は、 C++ ( C++11標準による)と同様に、匿名関数をサポートするように拡張されています。次に、関数を第一級関数として扱う言語( Dylan、Haskell、JavaScript、Lisp、ML、Perl、Python、Ruby、Scheme ) は、一般的に匿名関数をサポートしているため、関数を他のデータ型と同じように簡単に定義して渡すことができます。
1930年代にアロンゾ・チャーチによって匿名関数の理論の正確な表記法として導入された。
{{cite web}}: CS1メンテナンス: アーカイブサービスは非推奨になりました (リンク)引用とは、値として使用でき、基本コンビネータを使用して呼び出すことができる匿名関数(コードスニペットを示す値)です。