無名関数プログラミング言語における無名関数(英語: anonymous functionあるいはnameless function)[1]とは、名前付けされずに定義された関数のことである。無名関数を表現するための方法には様々なものがあるが、近年[2]主流となっているのはラムダ式による記法である。無名関数を表現するリテラル式は、関数リテラル (function literal) とも呼ばれる。値がある場合は関数オブジェクトであるものが多い。 ラムダ式→「クロージャ」も参照
ラムダ式 (lambda expression) はラムダ計算と関係が深く、関数型言語で特によく採用されている。 Haskellにおける例を示す。バックスラッシュ '\' がギリシャ文字のラムダ 'λ' のように見えることから、Haskellではラムダ式を表す構文に採用されている[3]。 --let add x y = x + y -- 通常の名前付き関数addの定義。
let add = \x y -> x + y -- 2つの引数を取ってその和を返す無名関数を定義し、変数addにバインドする。
print $ add 2 3
Haskellでは変数にバインドせずにラムダ式を直接引数に作用させることもできる。 print $ (\x y -> x + y) 2 3
以下のように高階関数の引数にラムダ式を渡すこともできる。 let calc op x y = op x y
print $ calc (\x y -> x + y) 2 3
関数型ではないプログラミング言語においても、ラムダ式を言語機能として取り入れる動きが活発である。 C#ではC# 3.0にて導入された。以下に例を示す。 Func<int, int, int> add = (x, y) => x + y;
Console.WriteLine(add(2, 3));
auto add = [](int x, int y) { return x + y; };
std::cout << add(2, 3) << std::endl;
JavaではJava 8にて導入された。以下に例を示す。 import java.util.function.*;
...
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
System.out.println(add.apply(2, 3));
C#の無名関数C#には大きく分けて2種類の無名関数(匿名関数)の記法が存在する[4]。一つは、C# 2.0で導入された匿名メソッド (anonymous method) である[5]。もう一つは、C# 3.0で導入されたラムダ式である。通例、ラムダ式のほうが簡潔であり、またラムダ式は式木として扱うこともできるため、基本的にC# 3.0以降ではラムダ式を用いる。 // 匿名メソッドの例
Func<int, int, int> add = delegate(int x, int y) { return x + y; };
Console.WriteLine(add(2, 3));
C#のラムダ式と匿名メソッドを比較した場合に唯一匿名メソッドが勝っている点は、パラメーターリストを省略できることである。 // public delegate void EventHandler(object sender, EventArgs e);
EventHandler click;
// 匿名関数:引数を使用しない場合、引数リストを省略できる
click = delegate { Console.WriteLine("Clicked"); };
// ラムダ式:推論可能な場合、引数の型名を省略できる
click = (sender, e) => Console.WriteLine("Clicked");
// ラムダ式:引数を使用しない場合も、引数リストの省略はできない
// click = () => Console.WriteLine("Clicked");
なお、ラムダ式や匿名メソッドがデリゲートパラメータとして渡される場合、内部的にはコンパイラによって自動的に命名された(C#開発環境では通常命名できない名前の)クラスが生成され、ラムダ式・メソッドはそのメンバーメソッドとして自動的に命名された後、コンパイルが実行される。つまり、IL化された時点で定義済みの名前付きメソッドのデリゲートを生成して渡す操作へと置換されるため、コンパイル後は通常の(名前付きメソッドの)デリゲート呼び出しと挙動的にはほぼ変わらない扱いとなる。 例えば(実用的ではないものの)リフレクションを介して無名関数の「名前」を見つけ出せば、再度呼び出すことも可能である。 JavaScriptの無名関数JavaScriptでは var add = function(a, b){ return a + b; }; // 2つの引数を取ってその和を返す無名関数を定義し、変数addにバインドする。
alert(add(2, 3));
ECMAScript 2015を用いる場合は、「アロー関数」という記法を用いることもできる。 var add = (a, b) => { return a + b; }; //アロー関数
add = (a, b) => a + b; // 値を返すだけの関数の場合、returnと{}を同時に省略可能
alert(add(2, 3));
Luaの無名関数Luaにおける関数は第一級オブジェクトであり、すべての関数が本質的に無名関数である。名前付きの関数とは、関数オブジェクトへの参照を保持する変数にすぎない。 function add(x, y) return x + y end
というコードは、次のコードに対する糖衣構文である。 add = function(x, y) return x + y end
Pythonの無名関数Pythonでは add = lambda a, b: a + b # 2つの引数を取ってその和を返す無名関数を定義し、変数addにバインドする。
print(add(2, 3))
無名関数の特徴メリット
特にC++ではアルゴリズム関数テンプレートにおける述語 (predicate) としての関数オブジェクトの明示的な定義が不要になり、簡潔なコードを記述しやすくなる。 C++14での例を示す。 #include <iostream>
#include <algorithm>
#include <vector>
int main() {
const std::vector<int> ary { 1, 5, -1, 3, 0, -2, };
std::cout << "Count of negative numbers = " << std::count_if(ary.begin(), ary.end(), [](auto x) { return x < 0; }) << std::endl;
return 0;
}
デメリット言語にもよるが、ラムダ式には通常の関数あるいはメソッドよりも機能制限がある。C# 7.0ではラムダ式の欠点を補うことのできるローカル関数が導入された。 脚注
参考文献関連項目 |