Haskellを使ったコンパイラ構築を勉強しています。固定小数点データ型の再帰を使用して抽象構文木 (ast) を表現しています。
単純な式 (数値定数と論理定数、二項演算、ローカル変数宣言) を持つおもちゃの言語の型チェッカーを作成する方法を調査しています。
型チェッカーは read-write-state ( RWS
) モナドです:
- リーダーは、シンボル定義 (シンボルとそのタイプの連想リスト) を含む環境から構成されるコンテキストを使用するためです。
- エラーメッセージのリストを生成するためのライター。
- state は後で名目上の型の等価性を実装するために必要になりますが、今はプログラムで定義されている変数の数を数えているだけです (その使用方法のデモンストレーションとして)。
モナドによって返される値は、型 (式の場合) または環境 (宣言の場合) で注釈が付けられた ast です。
この関数checker
は入力プログラムの ast を受け取り、RWS
実行時に型 (ast が式の場合) または環境 (ast が宣言の場合) を与えるモナド アクションで注釈が付けられた新しい ast を生成します。
たとえば、入力プログラムを考えてみましょう
let x = 2 + 3 in 1 + x
対応する ast:
Let
|
-----------------------
| |
VarDec: x Bin Add
| |
| ------------
| | |
Bin Add Num 1.0 Var x
|
-----------
| |
Num 2.0 Num 3.0
型チェックを行うと、次の ast が生成されます。
action1
Let
|
-----------------------
| |
action2 action3
VarDec: x Bin Add
| |
| ------------
| | |
action4 action5 action6
Bin Add Num 1.0 Var x
|
-----------
| |
action7 action8
Num 2.0 Num 3.0
RWS
モナドアクションで再帰的に注釈が付けられています。
コンパイラの後のフェーズでは、ast (およびその子、再帰的に) の注釈によって生成された情報を知る必要があります。したがって、それを取得するには、対応するアクションを実行する必要があります。
ルート アクションは、言語の規則に従って、子のアクションを構成することによって構築されます。
たとえば、ルート式 ( let 式) の型を取得するには、を実行する必要があります。これは、作成時に and を使用したため、 action1
makeaction2
およびaction3
も実行されます。action1
action2
action3
追加のタイプ1+x
が必要な場合action3
は、それを取得するために実行する必要があります。
したがって、アクションは繰り返し実行されます。型チェッカーが (RWS
モナド アクションを使用して) 構造化される方法では、ast の各ノードの計算された情報の共有が失われます。
この共有を回復して、アクションを再計算する必要をなくす手法はありますか?