私はディートリッヒエップに同意します。これは、GHCを高速化するいくつかの要素の組み合わせです。
何よりもまず、Haskellは非常に高いレベルです。これにより、コンパイラはコードを壊すことなく積極的な最適化を実行できます。
SQLについて考えてください。さて、SELECT
ステートメントを書くと、命令ループのように見えるかもしれませんが、そうではありません。指定された条件に一致する行を見つけようとして、テーブル内のすべての行をループするように見えるかもしれませんが、実際には「コンパイラ」(DBエンジン)が代わりにインデックスルックアップを実行している可能性があります。しかし、SQLは非常に高レベルであるため、「コンパイラ」は完全に異なるアルゴリズムを代用したり、複数のプロセッサやI / Oチャネル、またはサーバー全体を透過的に適用したりできます。
Haskellも同じだと思います。入力リストを2番目のリストにマップし、2番目のリストを3番目のリストにフィルター処理して、結果のアイテム数をカウントするようにHaskellに要求したと思うかもしれません。しかし、GHCが背後でストリームフュージョンの書き換えルールを適用し、全体を単一のタイトなマシンコードループに変換して、割り当てなしでデータを1回パスするだけですべての処理を実行することはありませんでした。手作業で作成するのは面倒で、エラーが発生しやすく、保守が困難です。これは、コードに低レベルの詳細がないため、本当に可能です。
それを見る別の方法は...なぜHaskellは高速であるべきではないのでしょうか?どうすれば遅くなりますか?
PerlやJavaScriptのようなインタプリタ言語ではありません。JavaやC#のような仮想マシンシステムでもありません。ネイティブマシンコードまでコンパイルできるため、オーバーヘッドはありません。
OO言語[Java、C#、JavaScript…]とは異なり、Haskellには完全な型消去があります(C、C ++、Pascalなど)。すべての型チェックはコンパイル時にのみ行われます。したがって、実行時の型チェックによって速度を低下させることもありません。(さらに言えば、nullポインターチェックはありません。たとえば、Javaでは、JVMはnullポインターをチェックし、それを参照しない場合は例外をスローする必要があります。Haskellはそのチェックに煩わされる必要はありません。)
「実行時にオンザフライで関数を作成する」のは遅いように聞こえますが、よく見ると、実際にはそうではありません。あなたのように見えるかもしれませんが、そうではありません。と言う(+5)
と、それはソースコードにハードコードされています。実行時に変更することはできません。したがって、これは実際には動的関数ではありません。カリー化された関数でさえ、実際にはパラメーターをデータブロックに保存しているだけです。すべての実行可能コードは実際にはコンパイル時に存在します。実行時の解釈はありません。(「eval関数」を持つ他のいくつかの言語とは異なります。)
パスカルについて考えてみましょう。それは古く、誰もそれを実際に使用しませんが、パスカルが遅いと文句を言う人は誰もいません。それについて嫌いなことはたくさんありますが、遅さは本当にそれらの1つではありません。Haskellは、手動のメモリ管理ではなくガベージコレクションを行うことを除いて、Pascalとはそれほど大きな違いはありません。そして、不変のデータは、GCエンジンにいくつかの最適化を許可します(これにより、遅延評価はやや複雑になります)。
Haskell は高度で洗練された高水準に見え、誰もが「すごい、これは本当に強力で、驚くほど遅いはずです!」または、少なくとも、あなたが期待する方法ではありません。はい、それは素晴らしい型システムを持っています。しかし、あなたは何を知っていますか?それはすべてコンパイル時に起こります。実行時には、それはなくなっています。はい、コード行で複雑なADTを構築できます。しかし、あなたは何を知っていますか?ADTはsの単なる普通のC union
ですstruct
。これ以上何もない。
本当のキラーは怠惰な評価です。コードの厳密性/遅延性を正しく理解すると、エレガントで美しい、愚かな高速コードを作成できます。しかし、これを間違えると、プログラムは何千倍も遅くなります。そして、これが起こっている理由は明らかではありません。
たとえば、ファイルに各バイトが出現する回数を数える簡単な小さなプログラムを作成しました。25KBの入力ファイルの場合、プログラムの実行に20分かかり、6ギガバイトのRAM を飲み込みました。それはばかげている!しかし、それから私は問題が何であるかを理解し、単一の強打パターンを追加し、実行時間が0.02秒に低下しました。
これは、Haskellが予期せずゆっくりと進むところです。そして、それに慣れるまでには確かにしばらく時間がかかります。しかし、時間が経つにつれて、本当に高速なコードを書くことがより簡単になります。
Haskellがそんなに速くなるのは何ですか?純度。静的タイプ。怠惰。しかし何よりも、コンパイラーがコードの期待に反することなく実装を根本的に変更できるほど高レベルであること。
でもそれは私の意見だと思います...