まず、警告: Haskell の基本的な特性の 1 つは、コンパイラがコンパイル中にコードの非常に根本的な変換を実行する可能性が高いことです。そのため、実際に実行されるコードは、作成したものとまったく似ていない可能性があります。
その警告はさておき、最初の概算では、すべての変数とすべてのデータ フィールドがヒープ オブジェクトへのポインターであると期待できます。これらのヒープ オブジェクトには、データ (整数、ブール値、文字、リスト ノードなど) を表すものもあれば、遅延のためにまだ実行されていない Haskell コードを表すものもあります。長く複雑な式を記述すると、すべてのサブ式がヒープ オブジェクトになり、最上位の式が下位の式を指します。したがって、プログラムの式グラフ全体がヒープ上のオブジェクト グラフになります。
(グラフ /= ツリー。ツリーには「ループ」がありません。Haskell では再帰が許可されているため、Haskell 式は必ずしも式ツリーではありません。)
大きな Haskell 式は、ヒープ オブジェクトの集まりになります。複雑なネストされたパターン マッチは、最適な順序で一連の単層パターンに脱糖されます。残りのプリミティブが 6 つになるまで、言語の他のすべてのシンタックス シュガーが取り除かれます。
- 変数を作成
- 変数を使用
- 関数の作成
- 通話機能
- データレコードの作成
- データレコードの検査
実際のビットとバイトがどのように機能するかを知りたい場合、それはコンパイラ次第です。GHC を意味する場合、おおよそ次のように機能します。
すべてのヒープ オブジェクトは、コードまたはデータのいずれかです。
データの場合は、値コンストラクター ID 番号と、そのコンストラクターのフィールドごとに 1 つのポインターが含まれます。
コード (つまり、まだ実行されていない部分式) の場合、関数のマシン コード ブロックへのポインターが 1 つと、関数の各引数 (カリー化なし) へのポインターが 1 つ含まれます。
条件分岐、I/O 操作、またはヒープ オブジェクトで実行しようとするとseq
、ランタイムはヒープ オブジェクトが指すコードにジャンプします。
オブジェクトがデータを表す場合、すぐに返されるコードを指します。
オブジェクトがコードを表す場合、関数を実際に実装するコードを指します。このコードは、関数の答えを計算し、答えを表すデータ オブジェクトで元のヒープ オブジェクトを上書きします。
いずれにせよ、制御が呼び出し元に戻ると、ヒープ オブジェクトは間違いなくデータ オブジェクトになり、コンストラクター ID やその他の必要なことを検査できるようになります。