「関数型言語」の版間の差分

編集の要約なし
{{プログラミング言語|index=かんすうかたけんこ}}
[[ファイル:Orange lambda.svg|境界|右|フレームなし|209x209ピクセル]]
'''関数型プログラミング'''(かんすうがたプログラミング、{{lang-en-short|''functional programming''}})は、[[プログラミングパラダイム]]の一つであり、[[ソフトウェア工学]]における主にプログラムリスト作成とコード記述の分野で用いられる考え方である。一説には[[数理論理学]]の[[ラムダ計算]]を起源モデルにして考案されたと言われる
 
プログラムデータ構成基本要素である値(''value'')を限りなく抽象化して、入力と出力の同時表現体すると共にその変換式も併せ持たせておりたものがこれがターム的に'''関数'''(''function'')と定義されている。関数は同時に入力の引数と出力の関数参照にもなるので演算の連鎖が可能であり、この仕組みの能動側は'''[[高階関数]]'''(''high-order'')、受動側は'''[[第一級関数]]'''(''first-class'')と呼ばれている。変換式はプログラムデータに一切の影響を与えず、また一切の影響を受けない事が保証されており、この原則は'''[[参照透過性]]'''(''referential transparency'')と定義され、仕組み的には'''純粋関数'''(''pure'')と呼ばれている。このコードとデータを完全に分離する設計が関数型プログラミングの大きな特徴である。値は関数の他に'''[[構造体]]'''(''data structure'')としても抽象化され、これも関数の引数または返値となる。プログラムは値の宣言(''declaration'')とそれらを演算子で繋いだ式(''expression'')の連続で構成され、これが順次処理となる。値は数値、構造体、関数、関数連鎖に随時抽象化される。分岐処理は一般に条件式を引数にしてthen式またはelse式のどちらかを引数にする関数参照を返す'''[[無名関数]]'''(''anonymous function'')の一形態で行なわれる事が多い。反復処理は関数の'''[[再帰]]'''(''recursion'')として行なわれる。再帰はその関数内の評価(''eval'')が変わらなくなるまで繰り返される。これらの特徴を持ったものが関数型プログラミングと見なされる。
 
== コンセプト ==
プログラムは値の宣言(''declaration'')とそれらを演算子で繋いだ式(''expression'')の連続で構成され、これが順次処理となる。値は数値、構造体、関数、関数連鎖に随時抽象化される。分岐処理は一般に条件式を引数にしてthen式またはelse式のどちらかを引数にする関数参照を返す'''[[無名関数]]'''(''anonymous function'')の一形態で行なわれる事が多い。反復処理は関数の'''[[再帰]]'''(''recursion'')として行なわれる。再帰はその関数内の評価(''eval'')が変わらなくなるまで繰り返される。これらの特徴を持ったものが関数型プログラミングと見なされる。
何をもって関数型プログラミングとするか、ということに関して、関数型プログラミングのコミュニティ内でも正確な定義や合意というものは存在しない。したがって関数型言語の定義も明確な境界はない。ただし、[[手続き型プログラミング]]が命令実行の列としてプログラムを記述していくのに対し、関数型プログラミングは複数の式を関数の適用によって組み合わせていくプログラミングスタイルである<ref name="faq">{{cite web | url = http://www.cs.nott.ac.uk/~gmh/faq.html | title = Frequently Asked Questions for comp.lang.functional | accessdate = May 14, 2015}}</ref>。手続き型プログラミングの発端は計算機の命令 (instruction/command) や構造に密接にかかわりがある一方、関数型プログラミングは数学の理論を発端としている。
 
==== 第一級関数と高階関数 ====
== 実例 ==
何をもって関数型プログラミングとするか、ということに関して、関数型プログラミングのコミュニティ内でも正確な定義や合意というものは存在しない。したがって関数型言語の定義も明確な境界はない。ただし、[[手続き型プログラミング]]が命令実行の列としてプログラムを記述していくのに対し、関数型プログラミングは複数の式を関数の適用によって組み合わせていくプログラミングスタイルである<ref name="faq">{{cite web | url = http://www.cs.nott.ac.uk/~gmh/faq.html | title = Frequently Asked Questions for comp.lang.functional | accessdate = May 14, 2015}}</ref>。手続き型プログラミングの発端は計算機の命令 (instruction/command) や構造に密接にかかわりがある一方、関数型プログラミングは数学の理論を発端としている。
 
==== 純粋関数 ====
 
==== 再帰 ====
たとえば、1 から 10 までの整数を足し合わせるプログラムを考える<ref>本来は[[等差数列]]の和の公式を用いて定数時間で問題を解く方法が最適解だが、ここではプログラミングスタイルの比較のため数値計算的手法を用いる。</ref>とき、手続き型プログラミングでは以下のように[[ループ (プログラミング)|ループ]]文を使って一時変数に数値を足していく(一時変数の内容を書き換える)命令を繰り返し実行するという形を取る。
 
ただし再帰呼び出しは[[スタックオーバーフロー]]の危険性やオーバーヘッドを伴うため、注意深く使用しなければならない<ref>[https://msdn.microsoft.com/ja-jp/library/dd233229(v=vs.120).aspx 関数 (F#) | MSDN]</ref>。通例、関数型言語では、[[末尾再帰]]呼び出し (tail-recursive call) の形で書かれた関数をループに展開する[[コンパイラ最適化]]により、スタックオーバーフローの危険性および再帰のオーバーヘッドを解消する。[[Scheme]]など、関数型言語の中には末尾再帰呼び出しの最適化を仕様で保証するものもある。
 
==== 厳格評価と遅延評価 ====
また、関数型言語は文 (statement) よりも式 (expression) を中心とした言語仕様となっていることも特徴である。前述の例において、再帰関数<code>sum</code>を[[束縛 (情報工学)|束縛]]する<code>let</code>は式である。また、条件分岐の<code>if-then-else</code>も式である。文よりも式で書けることが多いほうが都合がよい。
 
==== 型推論 ====
関数型言語は関数型プログラミングをサポートする言語ではあるが、手続き型プログラミングを行なうことも可能である。例えばF#では以下のようなPascal風の書き方もできる。
 
<source lang="fsharp">
==== 参照透過性 ====
let mutable total = 0
for i = 1 to 10 do
total <- total + i
printfn "%d" total
</source>
 
==== データ構造体 ====
ただし[[Haskell]]のようにループ構文をサポートせず、従来の手続き型プログラミングが難しいケースもある。
 
==== ファンクタ、モナド、アプリカティブ ====
逆に手続き型言語を使って関数型プログラミングを行なうことも可能であるが、末尾再帰呼び出しの最適化がサポートされるかどうかはコンパイラ次第である。
 
== 概要 ==
1,463

回編集