I am writing a compiler in a functional style. Type checking is pretty simple right now: it is (basically) just a function from Exprto Type.
Now I want to add a step to a workflow that saves type information for later steps. There are several ways to do this (symbol tables, etc.), but the simple way is to translate to IR, which looks like an AST but contains type information. For example, if the AST data type is:
datatype Expr = Literal of int
| Add of Expr * Expr
| ...
Then the typed IR will be:
type TExpr = Type * TExpr'
datatype TExpr' = TLiteral of int
| TAdd of TExpr * TExpr
| ...
So now my goal is to convert my type check into a type annotator: function Expr -> TExprinstead Expr -> Type. Here's my question: how would you do this without adding confusion with the messy pattern to the type checking function?
, , . , Add :
let lhs_t = check lhs in
let rhs_t = check rhs in
case (lhs_t, rhs_t) of
(Int, Int) => Int
| (_, _) => Error
! ! âĪïļð
, ( check Expr -> TExpr):
(* Recursive calls to translate the children. *)
let lhs_typed = check lhs in
let rhs_typed = check rhs in
(* We don't care about the expression for checking, just the resulting
* type. So extract that from each child. *)
let lhs_t, _ = lhs_typed in
let rhs_t, _ = rhs_typed in
case (Int, Int) =>
(* Construct a TExpr with the new type. *)
(Int, TAdd (lhs_typed, rhs_typed))
| (_, _) => Error
TExpr. ðŽðĐ
? , , ? , - , .
: " IR" . " AST" . aa " " , . , SO: