関数型言語

出典: フリー百科事典『ウィキペディア(Wikipedia)』
移動: 案内検索

関数型言語(かんすうがたげんご、functional language)は、以下に述べる関数型プログラミングを基本スタイルとして推奨する機能を持つプログラミング言語、関数型プログラミング言語(functional programming language)の略称である。

関数型プログラミング[編集]

何をもって関数型プログラミングとするか、関数型プログラミングを行っているコミュニティ内でも正確な定義や合意というものは存在しないが、一般的には、手続き型プログラミングがコマンド実行の列としてプログラムを記述していくのに対し、関数型プログラミングは複数の式を関数の適用によって組み合わせていくプログラミングスタイルである、ということは広く認められている。[1]

たとえば、手続き型プログラミングでは 1 から 10 までの整数を足し合わせるプログラムは、以下のように一時変数に数値を足していくコマンドの繰返し実行という形を取るのが一般的である:

total = 0;
for i = 0 to 10 do
  total = total + i;
done;

一方、関数型プログラミングでは、同じプログラムを一時変数を使わずに関数の再帰呼出しを使い、全体として一つの式として書くことが多い:

let    
    sum x = if x == 0 then  0
            else  x + sum (x - 1)
in
sum 10

関数型言語とは関数型プログラミングを推奨するが、多くの場合、手続き型プログラミングを用いたプログラムを書くことは可能であるし、逆に手続き型言語を使って関数型プログラミングを行うことも可能である。

概要[編集]

関数型プログラミングではプログラムの構成に関数を多用するため、ほとんどの関数型言語では関数を第一級オブジェクトとして扱い、その理論的な計算モデルとして第一級オブジェクトとしての関数を扱えるラムダ計算項書き換えを採用している。

関数への引数がプログラムへの入力で、関数を引数に作用させて評価して得られる値がプログラムからの出力であるとすると、コンピュータプログラムはある種の関数であると考えることができる。ここで、入力や出力は記憶装置中のファイルのようなものばかりではなく、マウスの動きの情報といった入力や、画面への表示といった出力も考えられ、関数型プログラミングにおいては実際にそれらを扱う関数としてモデル化する。

純粋関数型言語では、参照透過性が常に保たれるという意味において、全てのや関数の評価時に副作用を生まない。純粋関数型言語であるHaskellやCleanは非正格な評価を基本としており、引数はデフォルトで遅延評価される。一方、Idrisは純粋だが正格評価を採用している。入出力などを参照透過性を保ったまま実現するために、たとえばHaskellではモナドCleanでは一意型英語版という特殊な型を通して一貫性のある表現を提供する。

非純粋関数型言語では、参照透過性を壊す、副作用があるような式や関数も存在する。Lispなどでデータ構造の破壊的変更などの副作用を多用したプログラミングを行うと、それはもはや手続き型プログラミングである。多くの場合、非純粋関数型言語の評価戦略は正格評価(先行評価)であるが、遅延評価する部分を明示することで、無限リストなどを扱えるものもある。

JavaScriptJavaなど近年の高水準言語には、関数型言語の機能や特徴を取り入れているものがある。変数の値やオブジェクトの状態を書き換えるプログラミングスタイルを通常とするため、関数型言語とは分類されない。一方LISPは、その多くが副作用のある式や関数が多数あり、手続き型スタイルでのプログラミングがされることが多いが、理論的なモデル(「純LISP」)の存在や副作用を使わないプログラミングが基本であること、歴史的理由などから、関数型プログラミング言語に含む。Pascalでは「手続き」と呼ばれる値を「返さない」ルーチンも、C言語ではvoid型の値を返す関数と捉える。しかし、Pascalは手続き型言語で、C言語は関数型言語というのは明らかに誤りである[2]。なお、OCamlHaskellなどでは、「自明な値(例えば())を返す」と、値を返さない(Voidなど)はより明確に区別され、後者は停止しないか例外を出す(そのため結果がない)ようなプログラムを表す。

なお、「関数型言語である」と「関数型プログラミングをする」は同値ではなく、関数型には分類されない言語で関数型プログラミングをすることや、関数型プログラミングを基本とする言語の上で他のパラダイムを実現する例もある[3]

データフロープログラミング言語も関数型言語と共通した特徴を部分的に持つ。

歴史[編集]

LISPは、その基本機能のモデルとして関数型の純LISPを持つなどといった特徴がある、最初の関数型言語である。今日広く使われているLisp方言のうち特にSchemeは関数型としての特徴が強い。

現代的な関数型プログラミング言語の祖としてはアイディアが1966年に発表されたISWIMが挙げられるが、1970年前後までは関数型プログラミング言語の歴史はLispの発展が主である。1970年代にプロジェクトが開始されたw:Logic for Computable Functionsのための言語としてMLが作られている。

またLISPにおいて、変数のスコープに静的スコープを採用したSchemeが誕生したのが1975年である。

1977年、FORTRANの設計とBNFの発明の業績でこの年のチューリング賞を受賞したジョン・バッカスは、Can Programming Be Liberated From the von Neumann Style?: A Functional Style and Its Algebra of Programs[4]と題した受賞記念講演で関数型プログラミングの重要性を訴えた。講演ではFPという関数型プログラミング言語の紹介もした(サブタイトルの後半の「プログラムの代数」はこれを指す)が、これはAPL(特に、高階関数の意味がある記号(APLの用語ではoperator(作用素)という))の影響を受けている。

バッカスのFPは広く使用されることはなかったが、この後関数型プログラミング言語の研究・開発は広まることとなった。1985年にMirandaが登場した。1987年に、遅延評価の純粋関数型プログラミング言語の標準の必要性が認識されHaskellの策定が始まった。1990年にHaskell 1.0仕様がリリースされた。同じく1990年にはMLの標準であるStandard MLもリリースされている。

Cleanは1987年に登場したが、発展の過程でHaskellの影響を受けている。1996年に、ML処理系のひとつであったCamlにオブジェクト指向を追加したOCamlが登場した。また日本ではSMLに独自の拡張を施したSML#が開発されている。

21世紀に入ると、Java仮想マシンCLIをランタイムとする関数型プログラミング言語を実装しようという動きが現れ、ScalaClojureF#などが登場した。

代表的な関数型言語[編集]

純粋[編集]

非純粋[編集]

その他の関数的性質を持つ言語など[編集]

外部リンク[編集]

参考文献[編集]

  1. ^ Frequently Asked Questions for comp.lang.functional”. 2015年5月14日閲覧。
  2. ^ 共立出版『ANSI C/C++辞典』ISBN 4-320-02797-3 など
  3. ^ Oleg Kiselyov, Ralf Lämmel. “Haskell's overlooked object system”. 2005年9月10日閲覧。
  4. ^ 「プログラミングはフォン・ノイマン・スタイルから解放されうるか?: 関数型プログラミング・スタイルとそのプログラム代数」、米澤明憲訳『ACMチューリング賞講演集』(共立出版)pp. 83-156