高階関数
高階関数(こうかいかんすう、英: higher-order function)とは、第一級関数をサポートしているプログラミング言語において、関数を引数にしたり、あるいは関数を戻り値とするような関数のことである。引数や戻り値の関数もまた高階関数となり得る。これは主に関数型言語やその背景理論であるラムダ計算において多用される。数学でも同様の概念はあり、汎関数と呼ばれる。
例
関数を引数にとる関数
例えば LISPの1方言であるScheme を使って、次のようなコードを書く。
(define (add x y) ;加算する関数
(+ x y))
(define (mul x y) ;乗算する関数
(* x y))
(define (calc f) ;計算する関数
(f 2 3))
3つめの calc
は、他の2引数関数を受けとり、その関数の引数として2と3を渡して計算させる関数である。即ち、これは関数を引数にとる高階関数となる。以下は実行例である。
> (calc add) ;2+3
5
> (calc mul) ;2*3
6
関数を戻り値とする関数
上で示した add
を次のように書き直す。
(define (add x)
(lambda (y) (+ x y)))
これを使って加算をするには、次のように書く。
> ((add 2) 3)
5
ここで、まず (add 2)
の戻り値は1つ引数をとって2を足す関数になる。そして、戻り値として返ってきた関数に、更に3を渡して最終的な計算結果を得ている。つまり、add
自身は関数を戻り値とする高階関数となっている。上記のような、n引数ある関数を、1引数だけの高階関数に変換する操作をカリー化と呼ぶ。
ほとんどの型付き関数型言語においては、関数は最初からカリー化して与えるのが一般的である(つまりn引数関数を、n個の引数の直積を取る関数とするのではなく、1引数の高階関数をn個並べたような型で定義する。)例えばHaskellにおいて、
(2 +)
と記述すると、これは先ほどの (add 2)
と同じく、2を足す関数になる。加算演算子('+')が既にカリー化されているため、1引数を適用するだけで関数として機能するのである。以下は実行例。
Prelude> 2 + 3
5
Prelude> (2 +) 3
5
手続き型言語における高階関数
手続き型言語や、手続き型をベースにしたオブジェクト指向言語でも、同等かそれに近い機能を実現させる機構を備えているものがある。C/C++における関数ポインタなどがその一例である。またC#にはデリゲートという機能がある。
例えばCで関数を引数にとる関数を書くと次のようになる。
#include <stdio.h>
int
add (int x, int y) /* 加算する関数 */
{
return x + y;
}
int
mul (int x, int y) /* 乗算する関数 */
{
return x * y;
}
int
calc (int (*f) (int, int)) /* 計算する関数 */
{
return (*f) (2, 3);
}
int
main (void)
{
printf ("%d\n", calc (add)); /* 2+3 */
printf ("%d\n", calc (mul)); /* 2*3 */
return 0;
}
一方、関数を戻り値とする関数を書くことは難しい。これは戻り値となる関数の実行時にその関数を定義した時点での環境が必要になる(クロージャ)ためである。