web-dev-qa-db-ja.com

コンパイラを関数型言語で書く方が簡単なのはなぜですか?

私はこの質問について長い間考えていましたが、Stackoverflowで同様の質問をGoogleで見つけることはできませんでした。重複している場合は、ごめんなさい。

多くの人は、OCamlやHaskellなどの関数型言語でコンパイラやその他の言語ツールを書く方が、命令型言語で書くよりもはるかに効率的で簡単だと言っているようです。

これは本当ですか?そして、もしそうなら、なぜCのような命令型言語ではなく関数型言語でそれらを書くことがそれほど効率的で簡単なのでしょうか?また、関数型言語の言語ツールは、Cのような低水準言語よりも遅くありませんか?

86
wvd

多くの場合、コンパイラーはツリーで多くのことを行います。ソースコードが構文木に解析されます。次に、そのツリーは、タイプチェックを実行するためにタイプアノテーションを持つ別のツリーに変換されます。次に、そのツリーを、コア言語要素のみを含むツリーに変換します(構文上の砂糖のような表記を砂糖を含まない形に変換します)。これで、基本的にツリーの変換であるさまざまな最適化を実行できます。その後、おそらく通常の形式でツリーを作成し、そのツリーを反復処理してターゲット(アセンブリ)コードを作成します。

関数型言語には、パターンマッチングや効率的な再帰のサポートなどの機能があり、ツリーを簡単に操作できるため、コンパイラを書くのに一般的に優れた言語と見なされています。

99
sepp2k

多くのコンパイラタスクは、ツリー構造のパターンマッチングです。

OCamlとHaskellはどちらも、強力で簡潔なパターンマッチング機能を備えています。

パターンを照合するために評価または抽出される値には副作用がないため、命令型言語にパターンマッチングを追加することは困難です。

38
Pete Kirkham

考慮すべき重要な要素の1つは、コンパイラプロジェクトの大部分は、コンパイラをセルフホストして「自分のドッグフードを食べる」ことができることです。このため、言語研究用に設計されたOCamlなどの言語を見ると、コンパイラタイプの問題に対して優れた機能を備えている傾向があります。

私の最後のコンパイラー風のジョブでは、Cコードを操作しているときにまさにこの理由でOCamlを使用しましたが、それはタスクに最適なツールでした。 INRIAの人々が異なる優先度でOCamlを構築していた場合、それはそれほど適切ではなかったかもしれません。

とは言っても、関数型言語はあらゆる問題を解決するための最良のツールであるため、論理的には、この特定の問題を解決するための最良のツールであると言えます。 QED。

/ me:私のクロールバックJavaタスクが少し楽しくない...

15
Ukko

基本的に、コンパイラーは、あるコードセットから別のコードセットへの変換です。ソースからIR、IRから最適化されたIR、IRからアセンブリーなどです。これは、関数型言語が設計されたものとまったく同じです。純粋な関数はあるものから別のものへの単なる変化。命令型関数にはこの品質はありません。この種のコードは命令型言語で記述できますが、関数型言語はそのために特化されています。

9
Chuck

こちらもご覧ください

F#デザインパターン

OOは「タイプ」で物事をグループ化するのに対し、FPは物事を「操作」でグループ化し、「操作で」はコンパイラー/インタープリターにとってより自然です。

6
Brian

1つの可能性としては、コンパイラーがホストケースのホスト全体を非常に注意深く処理しなければならない傾向があることです。多くの場合、コードを正しく実装するには、実装するルールに対応する方法で実装を構造化する設計パターンを使用します。多くの場合、命令型(シーケンス、「いつ」)の設計ではなく、宣言型(パターンマッチング、「どこ」)になり、宣言型言語で実装するのが容易になります(ほとんどの機能は機能します)。

6
BCS

誰もが別の重要な理由を見逃したようです。通常のコードで(E)BNFによく似たパーサー用の組み込みドメイン固有言語(EDSL)を書くのは非常に簡単です。 Parsecのようなパーサーコンビネーターは、高階関数と関数構成を使用して、関数型言語で非常に簡単に記述できます。簡単なだけでなく、非常にエレガントです。

基本的に、最も単純な汎用パーサーを単なる関数として表し、特別な操作(通常は高階関数)を使用して、composeこれらのプリミティブパーサーを文法用のより複雑でより具体的なパーサーに変換します。

これはコースの枠組みをパーラーする唯一の方法ではありません。

4
snk_kid