型推論(パート1)
型推論は、すべてのプログラマが気に入るべき機能です。コードに型を指定する必要がなくなり、非常に便利です。
ここでは、Crystalがプログラムの型をどのように推論するかについての基礎を説明します。また、型推論を理解するためのドキュメントも少し作成します。
ほとんどの型推論アルゴリズムと同様に、この説明はAST(抽象構文木)に基づいています。各ASTノードには、式に対応する型が関連付けられます。
プログラマが型を検出するために行う推論を模倣するために、型推論はASTノードを順番にバインドしながら、プログラム全体のASTをトラバースします。
リテラル
これらは簡単です。ブール値、数値、文字、明示的に記述された値は、構文によって直接型が決まります。
true # : Boolean
1 # : Int32
変数
コンパイラは、各変数の型を知る必要があります。変数は、評価できるコンテキストも持っています。
型推論アルゴリズムは、存在する変数を各コンテキストに登録します。そのため、コンパイラはそれらを明示的に宣言できます。
変数の型を決定する最も基本的なステートメントは、代入です。
v = true
代入のASTノードには、1)ターゲット(左辺)、2)式(右辺)があります。右辺の型が決まると、型推論アルゴリズムは、左辺はその型の値を格納できる必要があると述べます。
(より複雑なシナリオをサポートするために) バックトラッキング方式で計算する代わりに、このアルゴリズムはASTノード間の依存関係のグラフを作成することで動作します。
次の図は、ASTノード、変数とその型が保持されるコンテキスト、および部分を間の型依存関係を強調する青い矢印を示しています。
条件文(いわゆるIf文)
Crystalはユニオン型をサポートしています。同じコンテキスト内で(しかし異なる分岐で)変数が複数回代入されると、その期待される型はすべての代入を処理できる型になります。そのため、次のコードが与えられると
if false
v = false
else
v = 2
end
最終的にv
の型はInt32 | Boolean
になります。
もう一度、ASTノード、変数とその型が保持されるコンテキスト、および部分を間の型依存関係を強調する青い矢印を示します。
コンテキスト内の変数に新しい型が到着すると、これは「進行中の」既知の型に追加されます。そのため、ユニオンが表示されます。
まだ表示されていないものがあります。変数のすべての出現には、コンテキストへの依存関係があります。これは次の図に示されています。
このように、各代入は、Boolean
をInt32 | Boolean
に、またはInt32
をInt32 | Boolean
に代入することを目的としていることがわかります。この情報はコード生成で使用されます。