関数型言語

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

関数型言語(かんすうがたげんご、functional language)は、関数型プログラミングに向いた特徴を持つプログラミング言語、関数型プログラミング言語(functional programming language)の略称である。引数に関数を作用(applicate)させて計算をおこなうことから、作用型言語(applicational language)ともいう。データフロープログラミング言語も関数型言語の一種である[1]

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

ここでの「関数」とは、数学でいう「関数」である。手続き型プログラミングなどにおける「関数」も同じ機能を持つ。原則としては副作用がないものを関数と呼ぶ。副作用がある関数を認めるかどうかは、プログラミングで何がしたいかによる。空間的には副作用がないという関数も、瞬時に計算を終わることはできず、時間を浪費するという時間軸での副作用がある。時間と空間を含めた関数について考えるとよい。数学では時間を考慮しないが、プログラミングでは時間を考慮する必要がある。空間的な副作用がない関数、空間的な副作用がある関数という具合に厳密に分類するとよい。システム理論では、入力を出力に変換するものをシステムと呼び、関数と同じ機能を持つ。システムでは、出力だけある湧き出し点、入力だけあるブラックホールを仮設としてシステムに含めている。関数も、システム理論に習い、出力だけある関数、入力だけある関数も含めて、広義の関数理論を形成するとよい。

Pascalでは「手続き」と呼ぶ値を返さないルーチンもC言語では「関数」と呼ぶ。C言語の値を返さない言語は、void(何もないもの)を返すという記述をしている。0が数であるのと同様、voidも型であり、void型を返すと理解するとよい。Pascalは手続き型言語で、C言語は関数型言語というのは明らかに誤りである。[2]

関数への引数がプログラムへの入力で、関数を引数に作用させて評価して得られる値がプログラムからの出力であるとすると、コンピュータプログラムはある種の関数であると考えることができる。ここで、入力や出力は記憶装置中のファイルのようなものばかりではなく、マウスの動きの情報といった入力や、画面への表示といった出力も考えられる。極端には、一般的な機械語の命令も、レジスタやメモリのようなコンピュータの内部状態の、命令実行前の全状態を入力とし命令実行後の全状態を出力とする関数である。これはシステム理論と同じ考え方である。ここで「全状態」としているのは、入出力の線をどこで引くかによる。ある時間の全状態を入力とし、次の時間の全状態を出力とすれば、BASIC言語の poke() 関数によるメモリの書き換えは、メモリの状態は引数にも返す値にも含まなないが、メモリの状態そのものを全状態に含むため、副作用による作用ではなく関数である。全状態を出力に含めなければ、引数にも返す値にも含まない poke() 関数は全状態を考えない場合の「関数」ではない。

複雑なコンピュータプログラムに相当する関数を作るために、第一級関数を扱えることが関数型言語に有用である。概要の節で詳説する。

他のプログラミングパラダイムとの関連としては、関数型プログラミングは論理型プログラミングと同じく宣言型プログラミング非手続き型プログラミングで、手続き型プログラミング命令型プログラミングと分類を異にする。

概要[編集]

関数型プログラミング言語には、関数型プログラミングのために、第一級関数を定義する。カリー化などの機能を持つ。静的型付けの言語は型推論の機能がある。理論的な計算モデルとしてはラムダ計算項書き換えを基礎とする。

純粋関数型プログラミング言語では、参照透過性が常に保たれるという意味において、全てのや関数は副作用を持たない。入出力などのために、多くの純粋関数型プログラミング言語は正格性に関して非正格であり、引数はデフォルトで遅延評価である。また入出力などを参照透過性を保ったまま実現するために、たとえばHaskellではモナドCleanでは一意型英語版という特殊な型を通してでのみ入出力などを扱えるようにしている。

非純粋関数型言語では、参照透過性を壊す、副作用があるような式や関数も存在する。Lispなどでデータ構造の破壊的変更などの副作用を多用したプログラミングをおこなうと、それはもはや手続き型プログラミングと同じである。非純粋関数型言語は多くが正格性に関して正格であり、評価戦略としては正格評価(先行評価)である。無限リストのような技巧を使うために、明示して遅延評価をおこなわせるための機構を持つ。

JavaScriptなど近年の高水準言語には、関数型言語の機能や特徴を取り入れているものがある。変数の値やオブジェクトの状態を書き換えるプログラミングスタイルを通常とするため、関数型言語とはしない。一方LISPは、その多くが副作用のある式や関数が多数あり、手続き型スタイルでのプログラミングも可能だが、理論的なモデル(「純LISP」)の存在や副作用を使わないプログラミングが基本であること、歴史的理由などから、関数型プログラミング言語に含む。

歴史[編集]

FORTRANには、関数(ここでは副作用のあるものを含む意味で)を定義できる、「ADD A, 1」のような形ではなく「A = A + 1」のように式で計算を指示できる、といった特徴もあったが、基本的には手続き型プログラミング言語であった。

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[3]と題した受賞記念講演で関数型プログラミングの重要性を訴えた。講演ではFPという関数型プログラミング言語の紹介もした(サブタイトルの後半の「プログラムの代数」はこれを指す)が、これはAPL(特に、高階関数の意味がある記号(APLの用語ではoperator(作用素)という))の影響を受けている(APL自体はふつう関数型とはされない)。

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

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

21世紀に入ると、Java仮想マシンCLIに関数型言語を実装しようという動きがあらわれ、ScalaClojureF#などが登場した。

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

純粋関数型言語[編集]

非純粋関数型言語[編集]

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

外部リンク[編集]

参考文献[編集]

  1. ^ 『岩波情報科学辞典』pp. 138-139
  2. ^ 共立出版『ANSI C/C++辞典』ISBN 4-320-02797-3 など
  3. ^ 「プログラミングはフォン・ノイマン・スタイルから解放されうるか?: 関数型プログラミング・スタイルとそのプログラム代数」、米澤明憲訳『ACMチューリング賞講演集』(共立出版)pp. 83-156