関数型プログラミング

この記事を聞く

コンピュータサイエンスにおいて、関数型プログラミングとは、関数を適用・合成することでプログラムを構築するプログラミングパラダイムです。関数定義は、プログラムの 実行状態を更新する命令型の文の列ではなく、値を他の値にマッピングする式のツリー構造で表現される宣言型プログラミングパラダイムです。

関数型プログラミングでは、関数は第一級エンティティとして扱われます。つまり、他のデータ型と同様に、関数は名前(ローカル識別子を含む)に束縛され、引数として渡され、他の関数から返されます。これにより、小さな関数をモジュール方式 で組み合わせる、宣言的かつ構成可能なスタイルでプログラムを記述できます。

関数型プログラミングは、すべての関数を決定論的な数学関数、つまり純粋関数として扱う関数型プログラミングのサブセットである純粋関数プログラミングと同義に扱われることがあります。純粋関数は、指定された引数で呼び出されると、常に同じ結果を返し、変更可能な状態やその他の副作用の影響を受けません。これは、副作用(プログラムの状態を変更したり、ユーザーからの入力を取得したりするなど)を持つ可能性がある、命令型プログラミングで一般的な不純な手続きとは対照的です。純粋関数プログラミングの支持者は、副作用を制限することでプログラムのバグが少なくなり、デバッグテストが容易になり、形式検証に適したものになると主張しています。[ 1 ] [ 2 ]

関数型プログラミングは学術分野に起源を持ち、関数のみに基づいた正式な計算システムであるラムダ計算から発展しました。関数型プログラミングは歴史的に命令型プログラミングほど人気が​​ありませんでしたが、 Common LispScheme[ 3 ] [ 4 ] [ 5 ] [ 6 ] ClojureWolfram Language[ 7 ] [ 8 ] Racket 、[ 9 ] Erlang[ 10 ] [ 11 ] [ 12 ] Elixir[ 13 ] OCaml[ 14 ] [ 15 ] Haskell[ 16 ] [ 17 ] F # [ 18 ] [ 19 ]など多く関数言語今日は産業界や教育で使用されています。Lean数学の定理の検証によく使用される関数型プログラミング言語です。[ 20 ]関数型プログラミングは、WebにおけるJavaScript 、 [ 21 ]統計におけるR 、 [ 22 ] [ 23 ]金融分析におけるJK 、 Q 、 XMLXQuery / XSLTなど、特定のドメインで成功を収めた言語の鍵でもあります。[ 24 ] [ 25 ] SQLLex / Yaccなどのドメイン固有の宣言型言語は、変更可能な値を許可しないなど、関数型プログラミングの要素の一部を使用します。[ 26 ]さらに、他の多くのプログラミング言語が関数型スタイルでのプログラミングをサポートしているか、関数型プログラミングの機能を実装しています。たとえば、C++ ( C++11以降)、C#[ 27 ] Kotlin[ 28 ] Perl[29 ] PHP [ 30 ] Python [ 31 ] Go [ 32 ] Rust [ 33 ] Raku [ 34 ] Scala [ 35 ] Java Java 8以降) [ 36 ]

歴史

ラムダ計算は、1930年代にアロンゾ・チャーチによって開発された、関数適用から構築された正式な計算体系です。1937年、アラン・チューリングはラムダ計算とチューリングマシンが同等の計算モデルであることを証明し、[ 37 ]ラムダ計算がチューリング完全であることを示しました。ラムダ計算はすべての関数型プログラミング言語の基礎を形成しています。同等の理論的定式化である組合せ論理は、 1920年代から1930年代にかけてモーゼス・シェーンフィンケルハスケル・カリーによって開発されました。 [ 38 ]

チャーチは後に、より弱いシステムである単純型付きラムダ計算を開発しました。これは、すべての項にデータ型を割り当てることでラムダ計算を拡張したものです。 [ 39 ]これが静的型付き関数型プログラミングの基礎となります。

最初の高水準関数型プログラミング言語であるLisp は、1950 年代後半にマサチューセッツ工科大学(MIT)在籍中のジョン・マッカーシーによってIBM 700/7000 シリーズの科学計算用コンピュータ向けに開発されました。 [ 40 ] Lisp の関数はチャーチのラムダ記法を使用して定義され、ラベル構造によって再帰関数を可能にするよう拡張されました。[ 41 ] Lisp は関数型プログラミングの多くのパラダイム的な特徴を初めて導入しましたが、初期の Lisp はマルチパラダイム言語であり、新しいパラダイムが進化するにつれて、多数のプログラミングスタイルのサポートを取り入れました。その後のSchemeClojureなどの方言や、 DylanJuliaなどの派生言語は、明確に関数型の中核部分を中心に Lisp を簡素化、合理化しようとしましたが、Common Lispは、置き換えた多数の古い方言のパラダイム的な特徴を保持し、更新するように設計されました。[ 42 ]

1956年に開発された情報処理言語(IPL)は、コンピュータベースの最初の関数型プログラミング言語として挙げられることがあります。[ 43 ]これは、シンボルのリストを操作するためのアセンブリ言語です。IPLにはジェネレータの概念があり、これは関数を引数として受け取る関数に相当します。また、低水準プログラミング言語であるため、コードがデータになることもあり、IPLは高階関数を持つと見なすことができます。しかし、IPLは変更可能なリスト構造や同様の命令型機能に大きく依存しています。

ケネス・E・アイバーソンは1960年代初頭にAPLを開発し、1962年の著書『プログラミング言語』ISBN 978-4-8632-1111)でその詳細を説明しています。 9780471430148(APL)はジョン・バッカスFPに最も大きな影響を与えました。1990年代初頭、アイバーソンとロジャー・フイはJを開発しました。1990年代半ばには、アイバーソンと以前一緒に働いていたアーサー・ホイットニーがKを開発しました。Kは、その派生であるQと共に金融業界で商業的に利用されています。

1960年代半ば、ピーター・ランディンは関数型プログラミング言語用の最初の抽象マシンであるSECDマシン[ 44 ]を発明し、[ 45 ] ALGOL 60ラムダ計算の対応関係を記述し、[ 46 ] [ 47 ] ISWIMプログラミング言語を提案した。[ 48 ]

ジョン・バッカスは1977年のチューリング賞講演「プログラミングはフォン・ノイマン・スタイルから解放されるか?関数型スタイルとそのプログラム代数」でFPを紹介した。 [ 49 ]彼は関数型プログラムを、「プログラムの代数」を可能にする「組み合わせ形式」によって階層的に構築されるものと定義した。現代の言葉で言えば、これは関数型プログラムが構成性の原則に従うことを意味する。バッカスの論文は関数型プログラミングの研究を普及させたが、それは関数型プログラミングで現在関連付けられているラムダ計算スタイルではなく、 関数レベルのプログラミングを強調していた。

1973年の言語ML は、エディンバラ大学ロビン・ミルナーによって作成され、セント・アンドリュース大学デビッド・ターナーによって言語SASLが開発されました。同じく1970年代のエディンバラでは、バーストールとダーリントンが関数型言語NPL を開発しました。[ 50 ] NPL はクリーネ再帰方程式に基づいており、プログラム変換に関する研究で初めて導入されました。[ 51 ]その後、バーストール、マッククイーン、サンネラは ML から多態的型チェックを組み込み、言語Hopeを作成しました。[ 52 ] ML は最終的にいくつかの方言に発展し、現在最も一般的なのはOCamlStandard MLです。

1970年代、ガイ・L・スティールジェラルド・ジェイ・サスマンは、ラムダ論文集と1985年の教科書『Structure and Interpretation of Computer Programs』で説明されているように、Schemeを開発しました。Schemeは、関数型プログラミングを促進する機能である、レキシカルスコープ末尾呼び出し最適化を必要とする最初のLisp方言でした。

1980年代、ペル・マーティン=レーフは直観主義型理論構成型理論とも呼ばれる)を考案しました。これは、関数型プログラムを、依存型として表現される構成的証明と関連付ける理論です。これは対話的な定理証明への新たなアプローチにつながり、その後の関数型プログラミング言語の開発に影響を与えました。

デイビッド・ターナーによって開発された遅延関数型言語、ミランダは1985年に登場し、 Haskellに大きな影響を与えました。ミランダはプロプライエタリ言語でしたが、Haskellは1987年に関数型プログラミング研究のためのオープンスタンダードを形成するという合意を得て誕生しました。実装は1990年現在も継続的にリリースされています。

最近では、CGALフレームワーク上に構築されたOpenSCAD言語のパラメトリックCADなどのニッチな分野で使用されていますが、値の再割り当てに関する制限(すべての値は定数として扱われます)により、関数型プログラミングの概念に馴染みのないユーザーの間で混乱が生じています。[ 53 ]

関数型プログラミングは商業的な場面でも引き続き使用されています。[ 54 ] [ 55 ] [ 56 ]

概念

いくつかの概念[ 57 ]やパラダイムは関数型プログラミングに特有のものであり、命令型プログラミングオブジェクト指向プログラミングを含む)では一般的に馴染みのないものです。しかし、プログラミング言語は複数のプログラミングパラダイムに対応していることが多いため、「主に命令型」の言語を使用するプログラマーは、これらの概念のいくつかを利用している可能性があります。[ 58 ]

第一級関数と高階関数

高階関数とは、他の関数を引数として取ったり、結果として返したりできる関数です。微積分学では、高階関数の例として、関数 の導関数を返す微分演算子 が挙げられます。 d/d×{\displaystyle d/dx}f{\displaystyle f}

高階関数は第一級関数と密接に関連しており、どちらも関数を他の関数の引数や戻り値として使用できます。両者の違いは微妙です。「高階」は他の関数を操作する関数という数学的な概念を表すのに対し、「第一級」は使用に制限のないプログラミング言語のエンティティを表すコンピュータサイエンス用語です(したがって、第一級関数は、数値などの他の第一級エンティティと同様に、プログラム内のどこにでも記述できます。他の関数の引数や戻り値として記述することもできます)。

高階関数は部分適用、あるいはカリー化を可能にします。これは、関数を引数に一つずつ適用し、適用するたびに次の引数を受け入れる新しい関数を返す手法です。これにより、例えばプログラマは後続関数を、自然数1に部分適用された加算演算子として簡潔に表現できます。

純粋関数

純粋関数(または式)には副作用(メモリやI/Oへの副作用)がありません。つまり、純粋関数にはいくつかの有用な特性があり、その多くはコードの最適化に利用できます。

命令型プログラミング言語用のコンパイラのほとんどは純粋関数を検出し、純粋関数呼び出しの共通部分式除去を実行しますが、プリコンパイルされたライブラリでは必ずしもこれを行うとは限りません。プリコンパイルされたライブラリは通常この情報を公開しないため、外部関数を含む最適化が妨げられます。gccなどの一部のコンパイラは、プログラマが外部関数を明示的に純粋関数としてマークするためのキーワードを追加し、このような最適化を可能にします。Fortran 95でも関数を純粋関数として指定できます。[ 59 ] C++11ではconstexpr同様のセマンティクスを持つキーワードが追加されました。

再帰

関数型言語における反復処理(ループ)は、通常、再帰によって実現されます。再帰関数は自身を呼び出し、基本ケースに到達するまで操作を繰り返します。一般的に、再帰はスタックを維持する必要があり、スタックは再帰の深さに比例して空間を消費します。そのため、命令型ループの代わりに再帰を使用すると、コストがかかりすぎる可能性があります。ただし、末尾再帰と呼ばれる特殊な形式の再帰は、コンパイラによって認識され、命令型言語で反復処理を実装するのと同じコードに最適化されます。末尾再帰の最適化は、コンパイル時にプログラムを継続渡しスタイルに変換するなどの方法で実装できます。

Scheme言語標準では実装が適切な末尾再帰をサポートすることを要求しており、アクティブな末尾呼び出しの数を無制限に許可する必要がある。[ 60 ] [ 61 ]適切な末尾再帰は単なる最適化ではなく、再帰を使用してループを表現できること、およびそうすることで領域が安全になることをユーザーに保証する言語機能である。[ 62 ]さらに、その名前に反して、末尾再帰だけでなくすべての末尾呼び出しを考慮します。適切な末尾再帰は通常、コードを命令型ループに変換することで実装されますが、実装では他の方法で実装することもできます。たとえば、Chicken は意図的にスタックを保持し、スタックがオーバーフローするようにします。ただし、これが発生すると、ガベージコレクターが領域を取り戻し、[ 63 ]末尾再帰をループに変換しないにもかかわらず、アクティブな末尾呼び出しの数を無制限に許可します。

一般的な再帰パターンは高階関数を用いて抽象化することができ、カタモルフィズムアナモルフィズム(あるいは「フォールド」と「アンフォールド」)が最も分かりやすい例です。このような再帰スキームは、命令型言語におけるループなどの組み込み制御構造と同様の役割を果たします。

ほとんどの汎用関数型プログラミング言語は無制限再帰を許可しており、チューリング完全である。そのため停止問題は決定不能となり方程式推論の不健全性を引き起こす可能性があり、一般に言語の型システムによって表現されるロジックに矛盾が生じる必要がある。Rocqなどの一部の特殊用途言語は、整列再帰のみを許可し、強く正規化される(停止しない計算は、 codataと呼ばれる無限の値のストリームでのみ表現できる)。結果として、これらの言語はチューリング完全ではなく、特定の関数を表現することは不可能であるが、無制限再帰によってもたらされる問題を回避しながら、幅広い興味深い計算を表現することができる。整列再帰に限定され、他のいくつかの制約がある関数型プログラミングは、完全関数型プログラミングと呼ばれる。[ 64 ]

厳密な評価と非厳密な評価

関数型言語は、厳密評価(積極的評価)非厳密評価(遅延評価)のどちらを使用するかによって分類できます。これらの概念は、式の評価時に関数の引数がどのように処理されるかを指します。技術的な違いは、失敗する計算や発散する計算を含む式の表示的意味にあります。厳密評価では、失敗する部分項を含む項の評価は失敗します。例えば、次のPython文は、

print ( len ([ 2 + 1 , 3 * 2 , 1 / 0 , 5 - 4 ]))

厳密な評価では、リストの3番目の要素がゼロ除算されているため、関数は失敗します。遅延評価では、length関数は4(つまり、リスト内の項目数)を返します。これは、関数の評価ではリストを構成する項を評価しないためです。つまり、厳密な評価では、関数を呼び出す前に関数の引数を常に完全に評価します。遅延評価では、関数の引数の値が関数呼び出し自体の評価に必要でない限り、関数の引数は評価されません。

関数型言語における遅延評価の通常の実装戦略はグラフ削減である。[ 65 ]遅延評価は、 MirandaCleanHaskellなどのいくつかの純粋関数型言語でデフォルトで使用されている。

ヒューズ(1984)は、データストリームの生産者と消費者の独立した実装を容易にすることで、関心の分離を通じてプログラムのモジュール性を向上させるメカニズムとして遅延評価を主張している。 [ 2 ] Launchbury(1993)は、特にプログラムの記憶域要件の分析において、遅延評価がもたらすいくつかの困難について説明し、そのような分析を支援する操作的意味論を提案している。 [ 66 ] Harper(2009)は、言語の型システムを使用してそれらを区別し、厳密な評価と遅延評価の両方を同じ言語に含めることを提案している。[ 67 ]

型システム

特に1970 年代のHindley-Milner 型推論の開発以来、関数型プログラミング言語は、コンパイル時にすべての無効なプログラムを拒否し、偽陽性エラーのリスクがある型付きラムダ計算を使用する傾向にあり、これは、コンパイル時にすべての有効なプログラムを受け入れ、有効なプログラムを拒否しないだけの情報がある場合に実行時にすべての無効なプログラムを拒否するため、偽陰性エラーのリスクがある型なしラムダ計算は対照的です。代数的データ型の使用により、複雑なデータ構造の操作が容易になります。強力なコンパイル時型チェックの存在により、テスト駆動開発などの他の信頼性技術がない場合でもプログラムの信頼性が向上します。一方、型推論により、ほとんどの場合、プログラマがコンパイラに対して手動で型を宣言する必要がなくなります。

RocqAgdaCayenneEpigramなどの研究指向の関数型言語は、型が項に依存できる直観主義型理論に基づいています。このような型は依存型と呼ばれます。これらの型システムには決定可能な型推論がなく、理解してプログラムするのが困難です。[ 68 ] [ 69 ] [ 70 ] [ 71 ]しかし、依存型は高階論理で任意の命題を表現できます。そのため、カリー–ハワード同型性を通じて、これらの言語の型付けされたプログラムは、コンパイラが認証されたコードを生成することができる形式的な数学的証明を書く手段になります。これらの言語は主に学術研究(形式化された数学を含む)で関心を集めていますが、工学でも使用され始めています。Compcert、言語Cのサブセット用のコンパイラで、 Rocqで書かれ、形式的に検証されています。[ 72 ]

一般化代数データ型(GADT)と呼ばれる依存型の限定的な形式は、依存型プログラミングの利点の一部を提供しながら、その不便さのほとんどを回避する方法で実装することができます。[ 73 ] GADTはグラスゴーHaskellコンパイラOCaml [ 74 ]Scala [ 75 ]で利用可能であり、JavaやC#などの他の言語への追加として提案されています。[ 76 ]

参照透明性

関数型プログラムには代入文がありません。つまり、関数型プログラム内の変数の値は、一度定義されると決して変更されません。これにより、変数は実行時にいつでも実際の値に置き換えられるため、副作用の可能性が排除されます。したがって、関数型プログラムは参照透過的です。[ 77 ]

Cの代入文を考えてみましょうx = x * 10。これは変数 に代入された値を変更しますx。 の初期値がxだったとする1と、変数 を2回連続して評価すると、それぞれ と がx生成されます。明らかに、を または に置き換えるとプログラムに異なる意味が与えられ、したがって式は参照透過的ではありません。実際、代入文は決して参照透過的ではありません。 10100x = x * 1010100

ここで、入力 x を暗黙的に変更しないため、副作用がないため透過的である別の関数を考えてみましょう。関数型プログラムはこの種の関数のみを使用するため、参照透過的です。 intplusOne(intx){returnx+1;}

データ構造

純粋関数型データ構造は、命令型のデータ構造とは異なる方法で表現されることが多い。[ 78 ]例えば、アクセスと更新時間が一定である配列は、ほとんどの命令型言語の基本構成要素であり、ハッシュテーブルバイナリヒープなどの多くの命令型データ構造は配列に基づいている。配列は、純粋関数型の実装が可能なマップやランダムアクセスリストに置き換えることができるが、アクセスと更新時間は対数的である。純粋関数型データ構造には永続性があり、これはデータ構造の以前のバージョンを変更せずに保持する特性である。Clojureでは、永続的データ構造は命令型のデータ構造の機能的な代替として使用される。例えば、永続ベクターは部分的な更新のためにツリーを使用する。挿入メソッドを呼び出すと、すべてのノードが作成されるのではなく、一部のノードが作成される。[ 79 ]

命令型プログラミングとの比較

関数型プログラミングは命令型プログラミングとは大きく異なります。最も大きな違いは、関数型プログラミングでは副作用を回避できる点にあります。命令型プログラミングでは副作用は状態やI/Oの実装に使用されます。純粋関数型プログラミングは副作用を完全に排除し、参照の透明性を実現します。

高階関数は、古い命令型プログラミングではほとんど使用されません。従来の命令型プログラムでは、リストを走査したり変更したりするためにループが使用されることがあります。一方、関数型プログラムでは、関数とリストを受け取り、各リスト項目に関数を適用することで新しいリストを生成して返す高階「map」関数が使用されることが多いでしょう。

命令型プログラミングと関数型プログラミング

次の 2 つの例 ( Javaで記述) は同じ効果を実現します。配列内のすべての偶数を 10 倍にしてすべてを加算し、最終的な合計を変数に格納しますresult

従来の命令型ループ:

int [] numList = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int result = 0 ; for ( int i : numList ) { if ( i % 2 == 0 ) { result += i * 10 ; } }

高階関数を使った関数型プログラミング:

java.util.Arraysをインポートしますint [] numList = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 }; int result = Arrays . stream ( numList ) . filter ( n -> n % 2 == 0 ) . map ( n -> n * 10 ) . reduce ( 0 , Integer :: sum );

場合によっては、関数型プログラミングによって提供される抽象化によって、 off-by-one エラーなどの大量の複雑な命令型コードを構築する際に発生する可能性のある特定の問題を回避する、より堅牢なコードの開発が可能になることがあります(グリーンスパンの 10 番目のルールを参照)。

状態のシミュレーション

銀行口座の残高管理など、状態を使って実装するのが最も自然なタスクがいくつかあります。純粋関数型プログラミングでは、これらのタスクや、ユーザー入力の受信や画面への出力といったI/Oタスクを、異なる方法で実行します。

純粋関数型プログラミング言語Haskellは、圏論から派生したモナドを用いてこれらを実装している。[ 80 ]モナドは、純粋性を損なうことなく、命令型で変更可能な状態(およびI/Oなどの副作用)を持つ計算のモデル化など(ただしこれに限定しない)、特定の種類の計算パターンを抽象化する手段を提供する。既存のモナドは、適切なテンプレートと例があればプログラムに簡単に適用できるかもしれないが、多くの学生は、例えば新しいモナドを定義するように求められた場合(特定の種類のライブラリでは必要な場合がある)、概念的に理解するのが難しいと感じている。[ 81 ]

関数型言語は、不変の状態を渡すことで状態をシミュレートします。これは、関数に状態をパラメータの一つとして受け入れさせ、結果と共に新しい状態を返すことで実現できます。古い状態は変更されません。[ 82 ]

非純粋関数型言語は通常、可変状態を管理するためのより直接的な方法を備えています。例えば、 Clojureは、現在の状態に純粋関数を適用することで更新できるマネージド参照を使用しています。このようなアプローチは、計算を表現するための好ましい方法として純粋関数の使用を促進しつつ、可変性を実現します。

プログラム内の副作用を追跡するために、ホーア論理一意性といった代替手法が開発されてきた。現代の研究言語の中には、副作用の存在を明示的に示すために効果システムを使用しているものもある。 [ 83 ]

効率性の問題

関数型プログラミング言語は一般に、 CPascalなどの命令型言語に比べてCPUとメモリの利用効率が低い。[ 84 ] これは、配列などの一部の可変データ構造が、現在のハードウェアを使用して非常に簡単に実装できるという事実に関係している。フラット配列は、深くパイプライン化されたCPUを使用すれば非常に効率的にアクセスできるし、キャッシュを介して効率的にプリフェッチすることも(複雑なポインタ追跡なしで)、SIMD命令で処理することもできる。同様に効率的な汎用の不変配列を作成することも簡単ではない。純粋関数型言語の場合、最悪のケースの速度低下は、使用されるメモリセルの数に対して対数的になる。これは、可変メモリが、アクセス時間が対数的な純粋関数型データ構造(バランスツリーなど)で表現できるためである。[ 85 ]ただし、このような速度低下は普遍的ではない。集中的な数値計算を実行するプログラムの場合、 OCamlCleanなどの関数型言語は、The Computer Language Benchmarks Gameによると、Cよりもわずかに遅いだけである。[ 86 ]大規模な行列や多次元データベースを扱うプログラムのために、配列関数型言語( JKなど)は速度の最適化を考慮して設計されました。

データの不変性は、多くの場合、命令型言語では安全ではない仮定をコンパイラに許すことで実行効率を高め、インライン展開の機会を増やすことができる。[ 87 ]永続的な不変データ構造を扱う際に暗黙的と思われるコピーが計算コストが高いように見える場合でも、Clojureなどの関数型プログラミング言語では、形式的に不変なデータ間で安全にメモリを共有するためのメカニズムを実装することでこの問題を解決している。 [ 88 ] Rustは、不変参照[ 89 ]とライフタイムと呼ばれる概念を含むデータ不変性へのアプローチによって他とは一線を画している[ 90 ]

不変データとアイデンティティと状態の分離、およびシェアード・ナッシング・スキームは、同時実行操作は通常アトミックであり、ロックの必要性を排除できるため、特定の同時実行ハザードのリスクを軽減または排除することで、同時実行プログラミングや並列プログラミングにより適している可能性もあります。 これは、例えばクラスが実装される方法であり、クラスの一部は同時使用に適さない、対応するクラスの不変バリアントです。[ 91 ]関数型プログラミング言語には、多くの場合、共有状態と同期の代わりにメッセージ・パッシング・メカニズムを活用する同時実行モデルがあります(アクター・モデルなど、各アクターは状態、動作、子アクター、およびメッセージ・キューのコンテナーです)。[ 92 ] [ 93 ]このアプローチは、 Erlang / ElixirAkkaで一般的です。 java.util.concurrent

遅延評価はプログラムを漸近的に高速化する可能性がある一方で、最大で定数倍の速度低下を引き起こす可能性がある(ただし、不適切に使用するとメモリリークを引き起こす可能性がある)。Launchbury 1993 [ 66 ]は遅延評価によるメモリリークに関する理論的な問題について議論しており、O'Sullivan et al. 2008 [ 94 ]はそれらの分析と修正に関する実践的なアドバイスを提供している。しかし、参照解除されたコードとデータを多用する遅延評価の最も一般的な実装は、深いパイプラインと多段キャッシュを備えた最新のプロセッサ(キャッシュミスで数百サイクルのコストがかかる可能性がある)ではパフォーマンスが低下する。

抽象化コスト

一部の関数型プログラミング言語では、「 map」や「filter 」といった高階関数といった抽象化を、基礎となる命令型演算ほど効率的に最適化できない場合があります。例として、 Clojureで5が偶数かどうかをチェックする以下の2つの方法を考えてみましょう。

(偶数? 5 ) ( .equals ( mod 5 2 ) 0 )

Java VMバージョン 22 および Clojure バージョン 1.11.1 で実行されているLeiningen REPL 2.11.2のRyzen 7900X GNU/Linux PCでCriteriumツールを使用してベンチマークしたところ、次のように実装された最初の実装が見つかりました。

( defn even? "n が偶数の場合は true を返し、n が整数でない場合は例外をスローします" { :added "1.0" :static true } [ n ] ( if ( integer? n ) ( zero? ( bit-and ( clojure.lang.RT/uncheckedLongCast n ) 1 )) ( throw ( IllegalArgumentException. ( str "引数は整数でなければなりません: " n )))))

の平均実行時間は 4.76 ミリ秒であるのに対し、基礎となるJava.equalsメソッドを直接呼び出す2 番目の平均実行時間は 2.8 μs で、約 1700 倍高速です。その理由の一部は、 の実装に含まれる型チェックと例外処理に起因すると考えられます。例えば、Golo ライブラリは、ジェネリクスを使用して関数型プログラミング言語で一般的なさまざまな高階関数を実装しています。ライブラリの作者が提供したベンチマークでは、 の呼び出しは同等のループよりも 4% 遅く、割り当てプロファイルは同じです[ 95 ]。これは、のインライン展開などのさまざまなコンパイラの最適化に起因すると考えられます[ 96 ]even?mapfor

Rustの特徴的な機能の一つは、ゼロコスト抽象化です。つまり、これらを使用しても実行時に追加のオーバーヘッドが発生しません。これは、コンパイラがループアンローリングを使用することで実現されます。ループアンローリングでは、命令型ループであれ反復子型ループであれ、ループの各反復処理が独立したアセンブリ命令に変換され、ループ制御コードのオーバーヘッドは発生しません。反復操作で配列に書き込む場合、結果の配列要素は特定のCPUレジスタに格納されるため、実行時に定数時間でアクセスできます[ 97 ]

非関数型言語における関数型プログラミング

従来関数型言語とは考えられていない言語でも、関数型プログラミングスタイルを使用することは可能である。[ 98 ]例えば、D [ 99 ]Fortran 95 [ 59 ]はどちらも純粋関数を明示的にサポートしている。

JavaScriptLua[ 100 ] PythonGo [ 101 ]は誕生当初からファーストクラス関数を備えていました。 [ 102 ] Pythonは1994年に「 lambda」、「map」、「reduce」、「filter 」をサポートし、Python 2.2ではクロージャもサポートしていましたが、 [ 103 ] Python 3では「reduce」がfunctools標準ライブラリモジュールに移行しました。[ 104 ]ファーストクラス関数は、1994年のPerl 5.0、 PHP 5.3、Visual Basic 9C# 3.0、C++11Kotlinなどの他の主流言語にも導入されています。[ 28 ]

Perlでは、lambdamapreducefilter、そしてクロージャが完全にサポートされており、頻繁に使用されています。2005年に出版された書籍『Higher-Order Perl』は、関数型プログラミングにおけるPerlの使用に関する包括的なガイドを提供するために執筆されました。

PHPでは、匿名クラスクロージャ、ラムダが完全にサポートされています。関数型プログラミングを支援するために、不変データ構造のためのライブラリや言語拡張が開発されています。

Javaでは、匿名クラスはクロージャをシミュレートするために使われることがあります。[ 105 ]しかし、匿名クラスは機能が制限されているため、必ずしもクロージャの適切な代替品とは限りません。[ 106 ] Java 8では、一部の匿名クラスの代替としてラムダ式をサポートしています。[ 107 ]

C#では、クロージャとラムダが完全にサポートされているため、匿名クラスは必要ありません。C#の関数型プログラミングを支援するために、不変データ構造用のライブラリと言語拡張が開発されています。

多くのオブジェクト指向設計パターンは、関数型プログラミングの用語で表現できます。たとえば、戦略パターンは単純に高階関数の使用を指示し、ビジターパターンはカタモルフィズムまたはフォールドにほぼ相当します。

同様に、関数型プログラミングの不変データの概念は命令型プログラミング言語にもよく取り入れられており、[ 108 ]例えばPythonのタプルは不変配列であり、JavaScriptのObject.freeze()もその一つである。[ 109 ]

論理プログラミングとの比較

論理プログラミングは関数型プログラミングの一般化と見なすことができ、関数は関係の特殊なケースです。[ 110 ] 例えば、関数 mother(X) = Y (すべての X は唯一の母 Y を持つ)は、関係 mother(X, Y) で表すことができます。関数は引数の入出力パターンが厳密であるのに対し、関係は任意の入出力パターンで問い合わせることができます。次の論理プログラムを考えてみましょう。

チャールズエリザベス)。ハリーダイアナ)。

このプログラムは関数型プログラムのようにクエリを実行して、子から母親を生成することができます。

?-(ハリーX )。X =ダイアナ? -(チャールズX ) 。X =エリザベス

しかし、逆方向にクエリして子を生成することもできます。

?-母親( X エリザベス) 。X =チャールズ?-母親( X ダイアナ) 。X =ハリー

これを使用して、母関係のすべてのインスタンスを生成することもできます。

?-母親( X Y )。X =チャールズY =エリザベスX =ハリーY =ダイアナ

関係構文と比較して、関数構文はネストされた関数をより簡潔に記述できます。例えば、関数構文における母方の祖母の定義は、ネストされた形式で次のように記述できます。

母方の祖母( X ) =(( X ) )。

リレーショナル表記法での同じ定義は、ネストされていない形式で記述する必要があります。

母方の祖母( X Y ) :-( X Z )、( Z Y )。

ここで は:-を意味し、の場合は , を意味し、は を意味します。

しかし、この2つの表現の違いは単に構文上のものです。Ciao Prologでは、関数型プログラミングにおける関数のように、関係を入れ子にすることができます[ 111 ]

祖父母( X ) :=(( X ) )。( X ) :=( X )。( X ) :=( X )。(チャールズ) :=エリザベス(チャールズ) :=フィリップ(ハリー) :=ダイアナ(ハリー) :=チャールズ?-祖父母( X Y )。X =ハリーY =エリザベスX =ハリーY =フィリップ

Ciao は関数のような表記法をリレーショナル形式に変換し、標準の Prolog 実行戦略を使用して結果のロジック プログラムを実行します。

アプリケーション

テキストエディタ

高度に拡張可能なテキストエディタファミリーであるEmacsは、プラグインの作成に独自のLisp方言を使用しています。最も人気のあるEmacs実装であるGNU EmacsとEmacs Lispのオリジナルの作者であるリチャード・ストールマンは、Lispを最も好きなプログラミング言語の一つと考えています。[ 112 ]

スプレッドシート

スプレッドシートは、純粋なゼロ階厳密評価関数型プログラミングシステムの一種と考えることができます。 [ 113 ]しかし、スプレッドシートは一般的に高階関数やコードの再利用性に欠けており、実装によっては再帰も欠いています。高階関数や再利用関数を可能にするためのスプレッドシートプログラムの拡張機能はいくつか開発されていますが、今のところ主に学術的な性質にとどまっています。[ 114 ]

マイクロサービス

関数型プログラミングパラダイムは、その構成可能性により、マイクロサービスベースのアーキテクチャに適している可能性がある。[ 115 ]

学術界

関数型プログラミングは、プログラミング言語理論の分野において活発な研究分野です。関数型プログラミングに特化した査読付きの出版物としては、International Conference on Functional ProgrammingJournal of Functional ProgrammingSymposium on Trends in Functional Programmingなど、いくつかあります。

業界

関数型プログラミングは、幅広い産業用途で採用されてきました。例えば、1980年代後半にスウェーデンのEricsson社が開発したErlangは、もともとフォールトトレラントな通信システムの実装に使用されていましたが[ 11 ] 、その後NortelFacebookÉlectricité de FranceWhatsAppなどの企業でさまざまなアプリケーションの構築に人気が高まっています。[ 10 ] [ 12 ] [ 116 ] [ 117 ] [ 118 ] Lispの方言であるSchemeは、初期のApple Macintoshコンピューター上のいくつかのアプリケーションの基盤として使用され[ 3 ] [ 4 ] 、トレーニングシミュレーションソフトウェア[ 5 ]望遠鏡の制御などの問題に適用されてきました。[ 6 ] 1990年代半ばに導入されたOCamlは、金融分析、 [ 14 ]ドライバー検証、産業用ロボットプログラミング、組み込みソフトウェアの静的解析などの分野で商用利用されてきました。[ 15 ] Haskellは、当初は研究用言語として意図されていましたが、[ 17 ]航空宇宙システム、ハードウェア設計、ウェブプログラミングなどの分野にも応用されています。[ 16 ] [ 17 ]

業界で使用されている他の関数型プログラミング言語には、Scala [ 119 ] F # [ 18 ] [ 19 ] Wolfram Language [ 7 ] Lisp [ 120 ] Standard ML [ 121 ] [ 122 ] Clojure [ 123 ]などがあります。Scalaデータサイエンスで広く使用されており、[ 124 ] ClojureScript [ 125 ] Elm [ 126 ]またはPureScript [ 127 ]は、プロダクションで使用されている関数型フロントエンドプログラミング言語の一部です。ElixirのPhoenixフレームワークは、 Font AwesomeAllegro(ポーランド最大のeコマースプラットフォームの1つ)[ 128 ]分類広告プラットフォームAllegro Lokalnieなど、比較的人気のある商用プロジェクトでも使用されています[ 129 ]

関数型「プラットフォーム」は、金融分野(特に大手投資銀行)におけるリスク分析に広く利用されています。リスク要因は、市場変動における相関関係を測定するための相互依存グラフ(カテゴリ)を形成する関数としてコード化されます。これはグレブナー基底最適化に類似しているだけでなく、包括的資本分析・審査(CRCA)などの規制枠組みにも適用されています。金融分野におけるOCamlおよびCamlのバリエーションの使用を考えると、これらのシステムはカテゴリカル抽象機械( CAT)に関連すると考えられることがあります。関数型プログラミングは、圏論(Categorical Abstract Machine)の影響を強く受けています。

教育

多くの大学では関数型プログラミングを教えています。[ 130 ] [ 131 ] [ 132 ] [ 133 ]関数型プログラミングをプログラミングの入門概念として扱う大学もあれば[ 133 ]、最初に命令型プログラミング手法を教える大学もあります。[ 132 ] [ 134 ]

コンピュータサイエンス以外では、関数型プログラミングは問題解決、代数、幾何学の概念を教えるために使われています。[ 135 ]また、古典力学の構造と解釈という書籍で古典力学を教えるためにも使われてきました。

特にSchemeは長年にわたりプログラミング教育において比較的人気のある選択肢となってきました。[ 136 ] [ 137 ]

参照

注釈と参考文献

  1. ^ Hudak, Paul (1989年9月). 「関数型プログラミング言語の概念、進化、そして応用」(PDF) . ACM Computing Surveys . 21 (3): 359– 411. doi : 10.1145/72551.72554 . S2CID 207637854. 2016年1月31日時点のオリジナル(PDF)からアーカイブ。 2013年8月10日閲覧 
  2. ^ a bヒューズ、ジョン(1984年)「関数型プログラミングが重要な理由」
  3. ^ a b Clinger, Will (1987). 「MultiTasking and MacScheme」 . MacTech . 3 (12) . 2008年8月28日閲覧。
  4. ^ a b Hartheimer, Anne (1987). 「MacScheme+Toolsmithでのテキストエディタのプログラミング」 . MacTech . 3 (1). 2011年6月29日時点のオリジナルよりアーカイブ2008年8月28日閲覧。
  5. ^ a b Kidd, Eric. Terrorism Response Training in Scheme . CUFP 2007. 2010年12月21日時点のオリジナルよりアーカイブ2009年8月26日閲覧。
  6. ^ a b Cleis, Richard. Scheme in Space . CUFP 2006. 2010年5月27日時点のオリジナルよりアーカイブ2009年8月26日閲覧。
  7. ^ a b「Wolfram言語ガイド:関数型プログラミング」 . 2015年. 2015年8月24日閲覧
  8. ^ 「関数型プログラミング言語と手続き型プログラミング言語」コロラド大学応用数学科。 2007年11月13日時点のオリジナルよりアーカイブ。 2006年8月28日閲覧
  9. ^ 「アンチャーテッド 2 における状態ベーススクリプティング」(PDF) 。 2012年12月15日時点のオリジナル(PDF)からアーカイブ。 2011年8月8日閲覧
  10. ^ a b「製品開発にErlangを使用しているのは誰ですか?」 Erlangに関するよくある質問。 2018年4月27日閲覧
  11. ^ a b Armstrong, Joe (2007年6月). 「Erlangの歴史」.第3回ACM SIGPLANプログラミング言語の歴史に関する会議議事録. 第3回ACM SIGPLANプログラミング言語の歴史に関する会議. サンディエゴ、カリフォルニア州. doi : 10.1145/1238844.1238850 . ISBN 9781595937667
  12. ^ a bラーソン, ジム (2009年3月). 「並行プログラミングのためのErlang」 . Communications of the ACM . 52 (3): 48. doi : 10.1145/1467247.1467263 . S2CID 524392 . 
  13. ^ 「Elixirプログラミング言語」 。 2021年2月14日閲覧
  14. ^ a bミンスキー、ヤロン、ウィークス、スティーブン(2008年7月)。Caml Trading — ウォール街での関数型プログラミングの経験」。Journal of Functional Programming。18 ( 4 ): 553– 564。doi : 10.1017/S095679680800676X。S2CID 30955392 
  15. ^ a b Leroy, Xavier. Some uses of Caml in Industry (PDF) . CUFP 2007.オリジナル(PDF)から2011年10月8日にアーカイブ。 2009年8月26日閲覧
  16. ^ a b「Haskellの産業界における活用」 . Haskell Wiki . 2009年8月26日閲覧. Haskellは、航空宇宙・防衛、金融、Webスタートアップ、ハードウェア設計会社、芝刈り機メーカーなど、幅広い分野で商業的に利用されています。
  17. ^ a b c Hudak, Paul ; Hughes, J.; Jones, SP; Wadler, P. (2007年6月). Haskellの歴史:クラスを怠惰にする. Third ACM SIGPLAN Conference on History of Programming Languages. サンディエゴ、カリフォルニア州. doi : 10.1145/1238844.1238856 . 2013年9月26日閲覧。
  18. ^ a b Mansell, Howard (2008). Quantitative Finance in F# . CUFP 2008. 2015年7月8日時点のオリジナルよりアーカイブ。 2009年8月29日閲覧
  19. ^ a b Peake, Alex (2009). The First Substantial Line of Business Application in F# . CUFP 2009. 2009年10月17日時点のオリジナルよりアーカイブ。 2009年8月29日閲覧
  20. ^ de Moura, Leonardo; Ullrich, Sebastian (2021年7月). 「Lean 4定理証明器とプログラミング言語」.人工知能講義ノート. 自動演繹会議. 第12699巻. pp.  625– 635. doi : 10.1007/978-3-030-79876-5_37 . ISSN 1611-3349 . 
  21. ^ Banz, Matt (2017年6月27日). 「JavaScriptにおける関数型プログラミング入門」 . Opensource.com . 2021年1月9日閲覧。
  22. ^ 「useR! 2006カンファレンススケジュールには、Rの商用利用に関する論文が含まれています」 R-project.org、2006年6月8日。 2011年6月20日閲覧
  23. ^ Chambers, John M. (1998). 『データを使ったプログラミング:S言語ガイド』 Springer Verlag. pp.  67– 70. ISBN 978-0-387-98503-9
  24. ^ Novatchev, Dimitre. 「関数型プログラミング言語XSLT — 例による証明」 . 2006年5月27日閲覧
  25. ^ Mertz, David. 「XMLプログラミングパラダイム(パート4):XML処理への関数型プログラミングアプローチ」 IBM developerWorks . 2006年5月27日閲覧
  26. ^チャンバーリン, ドナルド・D. ;ボイス, レイモンド・F. (1974). 「SEQUEL: 構造化英語クエリ言語」. 1974 ACM SIGFIDET Proceedings : 249–264 .
  27. ^ C#による関数型プログラミング - Simon Painter - NDC Oslo 2020、2021年8月8日、2021年10月30日時点のオリジナルよりアーカイブ、 2021年10月23日取得
  28. ^ a b「関数型プログラミング - Kotlinプログラミング言語」Kotlin . 2019年5月1日閲覧
  29. ^ Dominus, Mark J. (2005). Higher-Order Perl . Morgan Kaufmann . ISBN 978-1-55860-701-9
  30. ^サイモン・ホリウェル (2014). PHP での関数型プログラミング。 php[アーキテクト]。ISBN 9781940111056
  31. ^ The Cain Gang Ltd. 「Pythonメタクラス:誰が?なぜ?いつ?」(PDF) 。 2009年5月30日時点のオリジナル(PDF)からアーカイブ。 2009年6月27日閲覧
  32. ^ 「GopherCon 2020: Dylan Meeus - Goを使った関数型プログラミング」 YouTube 2020年12月22日。
  33. ^ 「関数型言語機能:イテレータとクロージャ - Rustプログラミング言語」 . doc.rust-lang.org . 2021年1月9日閲覧
  34. ^ Vanderbauwhede, Wim (2020年7月18日). 「関数型プログラミングによるよりクリーンなコード」 . 2020年7月28日時点のオリジナルよりアーカイブ2020年10月6日閲覧。
  35. ^ 「Effective Scala」 . Scala Wiki . 2012年6月19日時点のオリジナルよりアーカイブ2012年2月21日閲覧。Effective Scala.
  36. ^ 「Java 8(別名Java 1.8)以降のパッケージjava.util.functionのドキュメント」 。 2021年6月16日閲覧
  37. ^チューリング, AM (1937). 「計算可能性とλ-定義可能性」.記号論理学ジャーナル. 2 (4). ケンブリッジ大学出版局: 153–163 . doi : 10.2307/2268280 . JSTOR 2268280. S2CID 2317046 .  
  38. ^ Haskell Brooks Curry; Robert Feys (1958). Combinatory Logic . North-Holland Publishing Company . 2013年2月10日閲覧
  39. ^ Church, A. (1940). 「単純な型理論の定式化」. Journal of Symbolic Logic . 5 (2): 56– 68. doi : 10.2307/2266170 . JSTOR 2266170. S2CID 15889861 .  
  40. ^ McCarthy, John (1978年6月). 「LISPの歴史」.プログラミング言語の歴史に関する第1回ACM SIGPLAN会議 - HOPL-1 (PDF) . ロサンゼルス, カリフォルニア州. pp.  173– 185. doi : 10.1145/800025.808387 .{{cite book}}: CS1 メンテナンス: 場所の発行元が見つかりません (リンク)
  41. ^ John McCarthy (1960). 「記号式の再帰関数と機械による計算、第1部」(PDF) . Communications of the ACM . 3 (4): 184– 195. doi : 10.1145/367177.367199 . S2CID 1489409 . 
  42. ^ Guy L. Steele、Richard P. Gabriel (1996年2月). 「Lispの進化」.プログラミング言語の歴史---II (PDF) . pp.  233– 330. doi : 10.1145/234286.1057818 . ISBN 978-0-201-89502-5. S2CID  47047140 .
  43. ^ハーバート・A・サイモンの回想録(1991年)、 Models of My Life pp.189-190 ISBN 0-465-04640-1彼、アル・ニューウェル、そしてクリフ・ショーは、プリンキピア・マテマティカの定理を自動証明するプログラム「Logic Theorist」を開発したことで、「人工知能(分野)の生みの親と一般的にみなされている」と主張している。これを実現するために、彼らは、振り返ってみると関数型プログラミングを組み込んだ言語とパラダイムを発明しなければならなかった。
  44. ^ Landin, Peter J. (1964). 「式の機械的な評価」 .コンピュータジャーナル. 6 (4).英国コンピュータ協会: 308–320 . doi : 10.1093/comjnl/6.4.308 .
  45. ^ Diehl, Stephan; Hartel, Pieter; Sestoft, Peter (2000). 「プログラミング言語実装のための抽象マシン」. Future Generation Computer Systems . 第16巻. pp.  739– 751.
  46. ^ Landin, Peter J. (1965a年2月). 「ALGOL 60とChurchのラムダ記法の対応:パートI」 Communications of the ACM . 8 (2). Association for Computing Machinery : 89–101 . doi : 10.1145/363744.363749 . S2CID 6505810 . 
  47. ^ Landin, Peter J. (1965b年3月). 「ALGOL 60とChurchのラムダ記法の対応:パートII」 . Communications of the ACM . 8 (3). Association for Computing Machinery : 158–165 . doi : 10.1145/363791.363804 . S2CID 15781851 . 
  48. ^ Landin, Peter J. (1966年3月). 「次の700のプログラミング言語」 . Communications of the ACM . 9 (3). Association for Computing Machinery : 157–166 . doi : 10.1145/365230.365257 . S2CID 13409665 . 
  49. ^ Backus, J. (1978). 「プログラミングはフォン・ノイマン型から解放されるか?:関数型プログラミングスタイルとそのプログラム代数」 Communications of the ACM . 21 (8): 613– 641. doi : 10.1145/359576.359579 .
  50. ^ RM Burstall. 関数型プログラミング言語の設計上の考慮事項. 招待論文, Proc. Infotech State of the Art Conf. "The Software Revolution", コペンハーゲン, 45–57 (1977)
  51. ^ RM BurstallとJ. Darlington. 再帰プログラム開発のための変換システム. Journal of the Association for Computing Machinery 24(1):44–67 (1977)
  52. ^ RM Burstall, DB MacQueen, DT Sannella. HOPE: 実験的応用言語. Proceedings 1980 LISP Conference, Stanford, 136–143 (1980).
  53. ^ 「assign() の発見を簡単に!」 OpenSCAD . 2023年4月19日時点のオリジナルよりアーカイブ
  54. ^ Peter Bright (2018年3月13日). 「開発者は流行の新しい言語を好むが、関数型プログラミングの方が収入が高い」 Ars Technica .
  55. ^ John Leonard (2017年1月24日). 「関数型プログラミングのひそやかな台頭」 . Computing.
  56. ^ Leo Cheung (2017年5月9日). 「関数型プログラミングはスタートアップにとってより良いのか?InfoWorld .
  57. ^ Sean Tull - 形式概念分析のためのモノイドカテゴリー。
  58. ^ Pountain, Dick. 「関数型プログラミングの成熟」 Byte ( 1994年8月) . 2006年8月27日時点のオリジナルよりアーカイブ。 2006年8月31日閲覧
  59. ^ a b「ISO/IEC JTC 1/SC 22/WG5/N2137 – Fortran 2015 委員会草案 (J3/17-007r2)」(PDF) 。国際標準化機構(ISO)。2017年7月6日。336 338頁 
  60. ^ 「アルゴリズム言語スキームに関する改訂版^6レポート」 R6rs.org 2013年3月21日閲覧
  61. ^ 「アルゴリズム言語スキームに関する改訂版^6レポート - 根拠」 R6rs.org 2013年3月21日閲覧
  62. ^ Clinger, William (1998). 「適切な末尾再帰と空間効率」. ACM SIGPLAN 1998 プログラミング言語の設計と実装に関する会議論文集 - PLDI '98 . pp.  174– 185. doi : 10.1145/277650.277719 . ISBN 0897919874. S2CID  16812984 .
  63. ^ Baker, Henry (1994). 「CONS Should Not CONS Its Arguments, Part II: Cheney on the MTA」 2006年3月3日時点のオリジナルよりアーカイブ2020年4月29日閲覧。
  64. ^ Turner, DA (2004-07-28). 「Total Functional Programming」 . Journal of Universal Computer Science . 10 (7): 751– 768. doi : 10.3217/jucs-010-07-0751 .
  65. ^関数型プログラミング言語の実装サイモン・ペイトン・ジョーンズ著、Prentice Hall出版、1987年
  66. ^ a b Launchbury, John (1993年3月).遅延評価のための自然な意味論. プログラミング言語の原理に関するシンポジウム. サウスカロライナ州チャールストン: ACM . pp.  144– 154. doi : 10.1145/158511.158618 .
  67. ^ Robert W. Harper (2009). 『プログラミング言語の実践的基礎』(PDF) . 2016年4月7日時点のオリジナル(PDF)からのアーカイブ
  68. ^ Huet, Gérard P. (1973). 「三階述語論理における統一の決定不可能性」.情報制御. 22 (3): 257– 267. doi : 10.1016/s0019-9958(73)90301-x .
  69. ^ジェラール、ユエ (1976 年 9 月)。Resolution d'Equations dans des Lagages d'Ordre 1,2,...ω (Ph.D.) (フランス語)。パリ第 7 大学。
  70. ^ Huet, Gérard (2002). 「高階統一 30年後」(PDF) . Carreño, V.; Muñoz, C.; Tahar, S. (編). Proceedings, 15th International Conference TPHOL . LNCS. Vol. 2410. Springer. pp.  3– 12.
  71. ^ Wells, JB (1993). 「2階ラムダ計算における型付け可能性と型検査は同値かつ決定不能である」. Tech. Rep. 93-011 : 176– 185. CiteSeerX 10.1.1.31.3590 . 
  72. ^ Leroy, Xavier (2018年9月17日). 「Compcert検証済みコンパイラ」 .
  73. ^ペイトン・ジョーンズ、サイモン、ヴィティニオティス、ディミトリオス、ウェイリッヒ、ジェフリー・ウォッシュバーン(2006年4月)。「GADTのためのシンプルなユニフィケーションベースの型推論」 ICFP 200650-61
  74. ^ 「OCamlマニュアル」 . caml.inria.fr . 2021年3月8日閲覧。
  75. ^ 「代数的データ型」 . Scalaドキュメント. 2021年3月8日閲覧
  76. ^ Kennedy, Andrew; Russo, Claudio V. (2005年10月).一般化代数的データ型とオブジェクト指向プログラミング(PDF) . OOPSLA. サンディエゴ、カリフォルニア州: ACM . doi : 10.1145/1094811.1094814 . ISBN 97815959303162006年12月29日時点のオリジナルよりアーカイブ。
  77. ^ヒューズ、ジョン. 「関数型プログラミングが重要な理由」(PDF) .チャルマース工科大学.
  78. ^純粋関数型データ構造、クリス・オカサキ著、ケンブリッジ大学出版局、1998年、 ISBN 0-521-66350-4
  79. ^ L'orange, Jean Niklas. 「polymatheia - Clojureの永続ベクトルを理解する、パート1」 . Polymatheia . 2018年11月13日閲覧
  80. ^ Michael Barr、Charles Well - コンピュータサイエンスのためのカテゴリー理論。
  81. ^ Newbern, J. 「All About Monads: A comprehensive guide to the theory and practice of monadic programming in Haskell」 . 2008年2月14日閲覧
  82. ^ 「カメを見る13の方法」楽しみと利益のためのfF# 。 2018年11月13日閲覧
  83. ^ Hartmanis, Juris; Hemachandra, Lane (1986). 「機械なしの計算量クラス:UPのための完全言語について」.オートマトン、言語、プログラミング. コンピュータサイエンス講義ノート. 第226巻. ベルリン、ハイデルベルク: Springer Berlin Heidelberg. pp.  123– 135. doi : 10.1007/3-540-16761-7_62 . ISBN 978-3-540-16761-7. 2024年12月12日閲覧
  84. ^ポールソン、ラリー・C.(1996年6月28日)『ML for the Working Programmer』ケンブリッジ大学出版局。ISBN 978-0-521-56543-1. 2013年2月10日閲覧
  85. ^ Spiewak, Daniel (2008年8月26日). 「Scalaで永続ベクトルを実装する」 . Code Commit . 2015年9月23日時点のオリジナルよりアーカイブ2012年4月17日閲覧。
  86. ^ 「どのプログラムが最速か? | コンピュータ言語ベンチマークゲーム」 benchmarksgame.alioth.debian.org. 2013年5月20日時点のオリジナルよりアーカイブ。 2011年6月20日閲覧
  87. ^ Igor Pechtchanski; Vivek Sarkar (2005). 「不変性の仕様とその応用」.並行性と計算:実践と経験. 17 ( 5–6 ): 639–662 . doi : 10.1002/cpe.853 . S2CID 34527406 . 
  88. ^ 「Clojureコレクションの詳細な考察」InfoQ2024年4月29日閲覧
  89. ^ 「参照と借用 - Rustプログラミング言語」 . doc.rust-lang.org . 2024年4月29日閲覧
  90. ^ 「ライフタイムによる参照の検証 - Rustプログラミング言語」 . doc.rust-lang.org . 2024年4月29日閲覧
  91. ^ 「並行コレクション(Java™チュートリアル > 基本的なJavaクラス > 並行性)」 . docs.oracle.com . 2024年4月29日閲覧。
  92. ^ 「アクターモデルを理解してノンブロッキングで高スループットの分散システムを構築する - Scaleyourapp」scaleyourapp.com 20231月28日 2024年4月29日閲覧
  93. ^ Cesarini, Francesco; Thompson, Simon (2009). Erlangプログラミング:ソフトウェア開発への並行アプローチ(第1版). O'Reilly Media, Inc. (2009年6月11日発行). p. 6. ISBN 978-0-596-55585-6
  94. ^ 「第25章 プロファイリングと最適化」 Book.realworldhaskell.org . 2011年6月20日閲覧
  95. ^ Berthe、Samuel (2024-04-29)、samber/lo2024-04-29取得
  96. ^ 「Go Wiki: コンパイラとランタイムの最適化 - Goプログラミング言語」 . go.dev . 2024年4月29日閲覧
  97. ^ 「パフォーマンスの比較:ループとイテレータ - Rustプログラミング言語」 . doc.rust-lang.org . 2024年4月29日閲覧
  98. ^ Hartel, Pieter; Henk Muller; Hugh Glaser (2004年3月). 「The Functional C experience」(PDF) . Journal of Functional Programming . 14 (2): 129– 135. doi : 10.1017/S0956796803004817 . S2CID 32346900. 2011年7月19日時点のオリジナル(PDF)からのアーカイブ。 2006年5月28日閲覧 David Mertz. 「Pythonによる関数型プログラミング、パート3」IBM developerWorks . 2007年10月16日時点のオリジナルよりアーカイブ。 2006年9月17日閲覧パート1パート2
  99. ^ 「関数 — Dプログラミング言語2.0」 Digital Mars、2012年12月30日。
  100. ^ 「Lua 非公式 FAQ (uFAQ)」
  101. ^ 「Goのファーストクラス関数 - Goプログラミング言語」 . golang.org . 2021年1月4日閲覧
  102. ^ Eich, Brendan (2008年4月3日). 「人気」 .
  103. ^ van Rossum, Guido (2009-04-21). 「Pythonの「関数型」機能の起源」 . 2012年9月27日閲覧
  104. ^ "functools — 呼び出し可能オブジェクトに対する高階関数と操作" . Python Software Foundation. 2011年7月31日. 2011年7月31日閲覧
  105. ^ Skarsaune, Martin (2008). SICS Java移植プロジェクト「大規模オブジェクト指向システムのSmalltalkからJavaへの自動翻訳
  106. ^ Gosling, James. 「Closures」 . James Gosling: on the Java Road . Oracle. 2013年4月14日時点のオリジナルよりアーカイブ。 2013年5月11日閲覧
  107. ^ Williams, Michael (2013年4月8日). 「Java SE 8 Lambdaクイックスタート」 .
  108. ^ブロッホ、ジョシュア (2008). 「項目15:可変性の最小化」. Effective Java (第2版). Addison-Wesley. ISBN 978-0321356680
  109. ^ "Object.freeze() - JavaScript | MDN" . developer.mozilla.org . 2021年1月4日閲覧。Object.freeze () メソッドはオブジェクトを凍結します。凍結されたオブジェクトは変更できなくなります。オブジェクトを凍結すると、新しいプロパティの追加、既存のプロパティの削除、既存のプロパティの列挙可能性、設定可能性、書き込み可能性の変更、および既存のプロパティの値の変更ができなくなります。さらに、オブジェクトを凍結すると、そのプロトタイプの変更もできなくなります。freeze() は渡されたオブジェクトと同じオブジェクトを返します。
  110. ^ダニエル・フリードマン、ウィリアム・バード、オレグ・キセリョフ、ジェイソン・ヘマン (2018). 『理性ある策略家』第2版. MITプレス.
  111. ^ A. Casas, D. Cabeza, MV Hermenegildo. LPシステムにおける関数型表記法、遅延評価、高階表現の統合に対する構文的アプローチ. 第8回国際関数型・論理プログラミングシンポジウム (FLOPS'06)、142-162ページ、2006年4月.
  112. ^ 「How I do my Computing」 . stallman.org . 2024年4月29日閲覧。
  113. ^ Wakeling, David (2007). 「スプレッドシート関数型プログラミング」(PDF) . Journal of Functional Programming . 17 (1): 131– 143. doi : 10.1017/S0956796806006186 . ISSN 0956-7968 . S2CID 29429059 .  
  114. ^ペイトン・ジョーンズ、サイモンバーネットアラン・ブラックウェル(2003年3月)。「世界で最も人気のある関数型言語の改良:Excelのユーザー定義関数」 。2005年10月16日時点のオリジナルよりアーカイブ
  115. ^ロジャー、リチャード(2017年12月11日)『マイクロサービスの道』マニング社、ISBN 9781638351733
  116. ^ Piro, Christopher (2009). Facebookにおける関数型プログラミング. CUFP 2009. 2009年10月17日時点のオリジナルよりアーカイブ2009年8月29日閲覧。
  117. ^ 「Sim-Diasca: Erlangによる大規模離散イベント同時実行シミュレーションエンジン」 2011年11月. 2013年9月17日時点のオリジナルよりアーカイブ。 2011年11月8日閲覧
  118. ^ 100万というのは2011年の数字です。 2014年2月19日にWayback Machineアーカイブされました。// WhatsAppブログ、2012年1月6日:「私たちのインフラの最後の重要な部分はErlangです」
  119. ^ Momtahan, Lee (2009). Scala at EDF Trading: デリバティブ価格設定のためのドメイン特化言語 Scala の実装. CUFP 2009. 2009年10月17日時点のオリジナルよりアーカイブ2009年8月29日閲覧。
  120. ^グレアム、ポール (2003). 「平均を超える」 . 2009年8月29日閲覧
  121. ^ Sims, Steve (2006). 「Standard MLによるスタートアップの構築」(PDF) . CUFP 2006. 2009年8月29日閲覧
  122. ^ Laurikari, Ville (2007).通信セキュリティにおける関数型プログラミング. CUFP 2007. 2010年12月21日時点のオリジナルよりアーカイブ2009年8月29日閲覧。
  123. ^ Lorimer, RJ (2009年1月19日). 「ライブプロダクションClojureアプリケーション発表」 . InfoQ .
  124. ^ Bugnion, Pascal (2016). Scala for Data Science (第1版). Packt . ISBN 9781785281372
  125. ^ 「開発者がClojureScriptを好む理由」 . StackShare . 2024年4月29日閲覧。
  126. ^ Herrick, Justin (2024-04-29), jah2488/elm-companies2024年4月29日閲覧
  127. ^ 「開発者がPureScriptを好む理由」 . StackShare . 2024年4月29日閲覧。
  128. ^チーム、社説 (2019年1月8日). 「ALLEGRO - ポーランド最高のオンラインマーケットプレイスについて知っておくべきことすべて」 . E-commerce Germany News . 2024年4月29日閲覧
  129. ^ 「Phoenix Frameworkを使用しているウェブサイト - Wappalyzer」www.wappalyzer.com . 2024年4月29日閲覧
  130. ^ 「関数型プログラミング:2019-2020」オックスフォード大学コンピュータサイエンス学部2020年4月28日閲覧。
  131. ^ 「プログラミング I (Haskell)」インペリアル・カレッジ・ロンドン 計算機科学科. 2020年4月28日閲覧
  132. ^ a b「コンピュータサイエンスBSc - モジュール」 。 2020年4月28日閲覧
  133. ^ a bアベルソン、ハルサスマン、ジェラルド・ジェイ(1985). 「第2版への序文」 .コンピュータプログラムの構造と解釈(第2版). MITプレス.書誌コード: 1985sicp.book.....A .
  134. ^ John DeNero (2019年秋). 「Computer Science 61A, Berkeley」 . 電気工学・コンピュータサイエンス学部, Berkeley . 2020年8月14日閲覧
  135. ^ Bootstrapのエマニュエル・シャンツァーがTWiT.tvネットワークのテレビ番組「Triangulation」でインタビューを受ける
  136. ^ 「なぜ入門プログラミングにSchemeを選ぶのか?」 home.adelphi.edu . 2024年4月29日閲覧
  137. ^スタッフ、IMACS (2011年6月3日). 「Schemeとは何か?なぜ学生にとって有益なのか?」 IMACS – 人生を通してより良い思考者を育てる. 2024年4月29日閲覧。

さらに読む