第一級関数

計算機科学において、第一級関数とは、関数を第一級オブジェクトとして扱うことのできるプログラミング言語の性質、またはそのような関数のことである。その場合その関数は、型のある言語では function typeなどと呼ばれる型を持ち、またその値は関数オブジェクトなどになる。具体的にはプログラムの実行時に生成され、データ構造に含めることができ、他の関数の引数として渡したり、戻り値として返したりすることのできる関数をいう。この概念はメタプログラミングとは異なり、コンパイラ呼び出しやeval関数によって生成された関数は含まれない。無名関数も参照。

第一級関数は関数型言語には必要不可欠であり、高階関数のような形で日常的に用いられる。例として、関数とリストを引数に取り、リストの各要素に関数を適用した結果のリストを返すmap  関数が挙げられる。map関数をサポートするプログラミング言語は、何らかの形で関数を関数の引数として渡すことを許容しなければならない。

Schemeでの例: 

スタックベースのプログラミング言語では、高階関数の実装における自由変数の取り扱いに関して困難な問題が生じる。これはFunarg問題として知られている。

型理論では、型//A//の値を受け取り、型//B//の値を返す関数を//A// → //B//と書く。これは//P// → //Q//と似ているが実は同じもので、カリー・ハワード対応によれば、関数型は論理包含に関係しており、ラムダ抽象は自然演繹における仮説、関数の適用はモーダスポネンスに相当する。また多くのプログラミング言語の機能として、型理論は第一級関数が連想配列などのデータ構造をモデルするのにも用いられる。

圏論においては、第一級関数は閉圏に相当する。たとえば単純型付きラムダ計算は、カルテシアン閉圏の言語に相当する。

1. 利用
-----

HaskellやLisp、ML、Schemeのような関数型言語は第一級関数を全面的にサポートしている。他に第一級関数をサポートしているプログラミング言語としては、ECMAScript 、Io、Lua、Nemerle、Perl、PHP、Python、Ruby、Scala、Tcl/Tkなどが挙げられる。

C言語やC++、Pascalなどのプログラミング言語は関数へのポインタをサポートしており、データ構造に含めたり他の関数に引数として渡したりすることができる。しかし、関数ポインタによって第一級関数をサポートしているとみなされてはいない。

C++はoperatorを含むユーザ定義演算子をサポートしており、operatorを持つクラスは関数オブジェクトとして扱うことができる。関数オブジェクトはC++では他の第一級オブジェクトと同じように操作することができる。また、C++11では無名関数がサポートされている。

2. 各言語での例
---------

2.1. C++
--------

include
include
include auto derivative = []> f, double delta) { return [=] { return  - f) / delta; }; }; int main { double  = std::sin; auto cos = derivative; std::cout << cos << std::endl; }<WtXmlEndTag />

2.2. D
------

alias real delegate Delegate;

Delegate makeDerivative { return delegate real  { return  - f) / deltaX; }; }

void main { real mySin { return std.math.sin; }

Delegate cos = makeDerivative; writefln); }<WtXmlEndTag />

2.3. Erlang
-----------

-module. -export.

% F: 数値を受け取り数値を返す関数 % DeltaX: 小さい正の数 % Fの近似導関数を返す。

derivative -> fun ->  - F) / DeltaX end.<WtXmlEndTag />

2.4. Scheme
-----------

 )) ;変数に関数リテラルを代入 ) ;リストの要素を関数に   ))) ;2つの関数を引数として受け取り

合成関数を返す関数 -3) ;他の関数の戻り値としての関数、引数に-3を適用

結果は3 ) fns)) ;関数のリストを

sqrt関数に合成 -> 関数のリスト ) fns-squared) ;すべての関数に引数を3で適用

結果はリスト <WtXmlEndTag />

2.5. Lisp
---------

 ) ; 関数リテラル  ) 4 5) ; 関数に4と5を渡す

2.6. Lua
--------

この例では第一級関数はIPアドレスのテーブルのソート戦略を指定するのに使われている。

network = { {name = "grauna", IP = "210.26.30.34"}, {name = "arraial", IP = "210.26.30.23"}, {name = "lua", IP = "210.26.23.12"}, {name = "derain", IP = "210.26.23.20"}, }

テーブルのホスト名を辞書順の逆でソートするには、次のように書く。

table.sort return  end)

2.7. ALGOL 68
-------------

PROC newton =  REAL f, f prime) REAL:

ニュートン法 #IF f <= error THEN x ELSE newton  / f prime , error, f, f prime) FI;

print REAL: x3 - 2*x2 + 6,  REAL: 3*x2 - 4x), newline ));

2.8. JavaScript
---------------

JavaScriptは第一級関数をサポートする。関数はレキシカルスコープを作り出す。

// 関数リテラル function{ print; };

// 関数リテラルをコールバックに代入 SomeObject.SomeCallBack = function{ print; };<WtXmlEndTag />

arguments.calleeプロパティを使うとJavaScriptでも無名再帰関数を書くことができる。なお、ECMAScript5のstrict modeではarguments.calleeの使用は禁じられている。

// f: 数値を受け取って数値を返す関数 // deltaX: 微小な正の数 // fの近似導関数を返す関数 function makeDerivative  { return function  { return  - f ) / deltaX; }; } var cos = makeDerivative; // cos ~> 1 // cos ~> 0

2.9. Perl
---------

my $divisor = 10; my $checker = sub { my $val = shift; if  { return 0; } else { return 1; } };

これはPerlにおける第一級関数だけでなく、クロージャの例にもなっている。また留意すべきこととして、オブジェクト指向Perlにおいてはクラスに関数のリファレンスをblessすることが可能である。

2.10. Python
------------

Pythonではdef文またはlambda式によって関数を生成する。第一級関数としては十分柔軟であるが、lambda式によって定義できる関数の本体は式に限られ、文を含む関数を生成することはできない。

>>> #いくつかの組み込み関数とそれらの逆関数 >>> from math import sin, cos, acos, asin >>> # ユーザ定義関数とそれらの逆関数を追加 >>> cube = lambda x: x * x * x >>> croot = lambda x: x   >>> # 関数の戻り値から関数を生成する第一級関数 >>> # compose == f) >>> compose = lambda f1, f2: ) ) >>> # 第一級関数は配列の要素として扱える >>> funclist = [sin, cos, cube] >>> funclisti = [asin, acos, croot] >>> # 整数のように自然にリストから関数を適用 >>> [compose for f, inversef in zip] [0.5, 0.49999999999999989, 0.5] >>>

2.11. C#
--------

C# 2.0から匿名メソッド  を、またC# 3.0からラムダ式を、それぞれサポートする。

using System; class Program { // f: doubleを受け取ってdoubleを返す関数 // deltaX: 微小な正の数 // fの導関数の近似を返す関数 static Func<double, double> MakeDerivative { return  =>  - f) / ; } static void Main { var cos = MakeDerivative; Console.WriteLine); // 1 Console.WriteLine); // 0 } }

2.12. Ruby 1.9
--------------

def deriv ->{  / dx } end

sin = ->{ Math.sin }

cos = deriv

puts sin[Math::PI / 2] puts cos[Math::PI / 2]<WtXmlEndTag />

2.13. Scala
-----------

import Math._

def deriv =  =>  - f) / dx

val cos = deriv

Console.println) Console.println)<WtXmlEndTag />

2.14. Haskell
-------------

derivative f delta = \x ->  - f x) / delta

main = do let sin' = derivative sin 0.00000001 let x = pi / 3 print  print <WtXmlEndTag />

2.15. PHP 5.3
-------------

<?php

$greet = function { echo "Hello $name"; };

$greet; // Hello Worldを出力

<WtXmlEndTag />

3. 関連項目
-------

無名関数
クロージャ
関数オブジェクト
第一級オブジェクト

4. 参考文献
-------

5. 外部リンク
--------

[1]