This page includes the inference rules that we use for typing judgments and semantic judgments. We will typically try to update it on a per-abstraction basis.
A typing judgment is of the form \Gamma \vdash e : \tau, where
\Gamma is a contexte is an expression\tau is a typeIt reads "in the context \Gamma, the expression e has type \tau."
A context is a set of typed variables written, for example, as
\{ \texttt{x} : \texttt{int}, \texttt{y} : \texttt{string}\}which is a context which has a variable \texttt{x} of type \texttt{int} and a variable \texttt{y} of type \texttt{string}. It's a set in the sense that a variable can appear at most once, e.g.,
\{\texttt{x} : \texttt{int}, \texttt{x} : \texttt{string}\}is not a valid context.
This rule says that if the variable x has type \tau in \Gamma then we can derive (without premises) that x has type \tau. The requirement that x : \tau appears in \Gamma is called a side condition, and is not included in a typing derivation (you can tell side-conditions by the fact that they are premises which are not typing judgments).
\frac
{x : \tau \in \Gamma}
{\Gamma \vdash x : \tau}
\ \textsf{(Var)}
These rules say that all literals (e.g., \texttt{2}, \texttt{3.234}, \texttt{"word"}) have the appropriate type in any context without premises.
\frac
{n \text{ is an integer literal}}
{\Gamma \vdash n : \texttt{int}}
\ \textsf{(IntLit)}
\qquad
\frac
{n \text{ is an integer literal}}
{\Gamma \vdash n : \texttt{float}}
\ \textsf{(FloatLit)}
\qquad
\frac
{s \text{ is an integer literal}}
{\Gamma \vdash s : \texttt{string}}
\ \textsf{(StrLit)}
\frac{}{\Gamma \vdash \texttt{true} : \texttt{bool}}
\ \textsf{(TrueLit)}
\qquad
\frac{}{\Gamma \vdash \texttt{false} : \texttt{bool}}
\ \textsf{(FalseLit)}
These rules express that integer operations apply only to integers and return integers.
\frac
{\Gamma \vdash e_1 : \texttt{int}
\qquad
\Gamma \vdash e_2 : \texttt{int}
}
{\Gamma \vdash e_1 \ \texttt{+} \ e_2 : \texttt{int}}
\ \textsf{(IntAdd)}
\qquad
\frac
{\Gamma \vdash e_1 : \texttt{int}
\qquad
\Gamma \vdash e_2 : \texttt{int}
}
{\Gamma \vdash e_1 \ \texttt{-} \ e_2 : \texttt{int}}
\ \textsf{(IntSub)}
\frac
{\Gamma \vdash e_1 : \texttt{int}
\qquad
\Gamma \vdash e_2 : \texttt{int}
}
{\Gamma \vdash e_1 \ \texttt{*} \ e_2 : \texttt{int}}
\ \textsf{(IntMul)}
\qquad
\frac
{\Gamma \vdash e_1 : \texttt{int}
\qquad
\Gamma \vdash e_2 : \texttt{int}
}
{\Gamma \vdash e_1 \ \texttt{/} \ e_2 : \texttt{int}}
\ \textsf{(IntDiv)}
\frac
{\Gamma \vdash e_1 : \texttt{int}
\qquad
\Gamma \vdash e_2 : \texttt{int}
}
{\Gamma \vdash e_1 \ \texttt{mod} \ e_2 : \texttt{int}}
\ \textsf{(IntMod)}
\frac
{\Gamma \vdash e_1 : \texttt{float}
\qquad
\Gamma \vdash e_2 : \texttt{float}
}
{\Gamma \vdash e_1 \ \texttt{+.} \ e_2 : \texttt{float}}
\ \textsf{(FloatAdd)}
\qquad
\frac
{\Gamma \vdash e_1 : \texttt{float}
\qquad
\Gamma \vdash e_2 : \texttt{float}
}
{\Gamma \vdash e_1 \ \texttt{-.} \ e_2 : \texttt{float}}
\ \textsf{(FloatSub)}
\frac
{\Gamma \vdash e_1 : \texttt{float}
\qquad
\Gamma \vdash e_2 : \texttt{float}
}
{\Gamma \vdash e_1 \ \texttt{*.} \ e_2 : \texttt{float}}
\ \textsf{(FloatMul)}
\qquad
\frac
{\Gamma \vdash e_1 : \texttt{float}
\qquad
\Gamma \vdash e_2 : \texttt{float}
}
{\Gamma \vdash e_1 \ \texttt{/.} \ e_2 : \texttt{float}}
\ \textsf{(FloatDiv)}
\frac
{\Gamma \vdash e_1 : \texttt{bool}
\qquad
\Gamma \vdash e_2 : \texttt{bool}
}
{\Gamma \vdash e_1 \ \texttt{\&\&} \ e_2 : \texttt{bool}}
\ \textsf{(And)}
\qquad
\frac
{\Gamma \vdash e_1 : \texttt{bool}
\qquad
\Gamma \vdash e_2 : \texttt{bool}
}
{\Gamma \vdash e_1 \ \texttt{||} \ e_2 : \texttt{bool}}
\ \textsf{(Or)}
\frac
{\Gamma \vdash e : \texttt{bool}}
{\Gamma \vdash \texttt{not} \ e : \texttt{bool}}
\ \textsf{(Not)}
Note that comparison operators are polymorphic, they can be apply to any type.
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{=} \ e_2 : \texttt{bool}}
\ \textsf{(Equal)}
\qquad
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{<>} \ e_2 : \texttt{bool}}
\ \textsf{(NotEqual)}
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{<} \ e_2 : \texttt{bool}}
\ \textsf{(LessThan)}
\qquad
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{<=} \ e_2 : \texttt{bool}}
\ \textsf{(LTE)}
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{>} \ e_2 : \texttt{bool}}
\ \textsf{(GreaterThan)}
\qquad
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash e_1 \ \texttt{>=} \ e_2 : \texttt{bool}}
\ \textsf{(GTE)}
The left rule reads
e_1 is of type \tau in the context \Gamma ande_2 is of type \tau' in the context \Gamma with x : \tau added, then\texttt{let} \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 is of type \tau' in \Gamma.\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma, x : \tau \vdash e_2 : \tau'
}
{\Gamma \vdash \texttt{let} \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 : \tau'
}
\ \textsf{(Let)}
\qquad
\frac
{\Gamma, x : \tau \vdash e_1 : \tau_1
\qquad
\Gamma, f : \tau \ \texttt{->} \ \tau_1 \vdash e_2 : \tau_2
}
{\Gamma \vdash \texttt{let} \ f \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 : \tau_2
}
\ \textsf{(LetFun)}
\frac
{\Gamma \vdash e_1 : \tau_1 \ \texttt{*} \ \tau_2 \ \texttt{*} \dots \texttt{*} \ \tau_n
\qquad
\Gamma, x_1 : \tau_1, x_2 : \tau_2, \dots, x_n : \tau_n \vdash e_2 : \tau'
}
{\Gamma \vdash \texttt{let (} x_1 \texttt, x_2 \texttt,\dots\texttt,x_n \texttt{) =} \ e_1 \ \texttt{in} \ e_2 : \tau'
}
\ \textsf{(LetTuple)}
\frac
{\Gamma \vdash f : \tau \to \tau_1
\qquad
\Gamma \vdash e : \tau
}
{\Gamma \vdash f \ e : \tau_1}
\ \textsf{(App)}
\frac
{\Gamma \vdash e : \texttt{bool}
\qquad
\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
}
{\Gamma \vdash \texttt{if} \ e \ \texttt{then} \ e_1 \ \texttt{else} \ e_2 : \tau}
\ \textsf{(If)}
\frac
{\Gamma \vdash e : \tau
\qquad
\Gamma \vdash p_1 : \tau
\ \dots \
\Gamma \vdash p_n : \tau
\qquad
\Gamma \vdash e_1 : \tau'
\ \dots \
\Gamma \vdash e_n : \tau'
}
{\Gamma \vdash \texttt{match} \ e \ \texttt{with} \ p_1 \ \texttt{->} \ e_1 \ \texttt{|} \ \dots \ \texttt{|} \ p_n \ \texttt{->} \ e_n : \tau'}
\ \textsf{(Pattern)}
Note. This rule is slightly informal because we haven't defined exactly what a pattern is. You won't be expected to write a typing derivation with this rule.
\frac
{\Gamma \vdash e_1 : \tau_1
\qquad
\Gamma \vdash e_2 : \tau_2
\qquad
\dots
\qquad
\Gamma \vdash e_n : \tau_n
}
{\Gamma \vdash \texttt{(}e_1\texttt{,} e_2\texttt{,} \dots \texttt{,} e_n \texttt{)} :
\tau_1 \ \texttt{*} \ \tau_2 \ \texttt{*} \dots \texttt{*} \ \tau_n}
\ \textsf{(Tuple)}
\frac
{}
{\Gamma \vdash \texttt{[]} : \alpha \ \texttt{list}}
\ \textsf{(Nil)}
\qquad
\frac
{\Gamma \vdash e : \tau
\qquad
\Gamma \vdash l : \tau \ \texttt{list}
}
{\Gamma \vdash (e \ \texttt{::} \ l) : \tau \ \texttt{list}
}
\ \textsf{(Cons)}
\frac
{\Gamma \vdash e_1 : \tau
\qquad
\Gamma \vdash e_2 : \tau
\qquad
\dots
\qquad
\Gamma \vdash e_n : \tau
}
{\Gamma \vdash \texttt{[} e_1 \texttt{;} e_2\texttt{;}\dots\texttt;e_n\texttt{]} : \tau \ \texttt{list}}
\ \textsf{(ListLit)}
\frac
{\Gamma \vdash e : \tau \ \texttt{list}
\qquad
\Gamma \vdash e_1 : \tau'
\qquad
\Gamma, h : \tau, t : \tau \ \texttt{list} \vdash e_2 : \tau'
}
{\Gamma \vdash \left(\texttt{match} \ e \ \texttt{with [] -> } e_1 \ \texttt{|} \ h \ \texttt{::} \ t \texttt{ -> } e_2 \right) : \tau'
}
\ \textsf{(ListMatch)}
We read e \Downarrow v as "the expression e evaluates to the value v.
This rules says that a variable evaluates to itself, without any premises.
\frac
{x \text{ is a variable}}
{x \Downarrow x}
\ \textsf{(VarEval)}
This rule says that any literal evaluates to itself, without any premises.
\frac
{v \text{ is an integer/float/string/Boolean literal}}
{v \Downarrow v}
\ \textsf{(LitEval)}
We will treat all operators for now as built-in. When we evaluate an expression, we have to evaluate its operands and the apply the operator.
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
v_1 \ \mathsf{op} \ v_2 = v
}
{e_1 \ \texttt{op} \ e_2 \Downarrow v}
\ \textsf{(OpEval)}
So for, example, these rules express that floating-point operators behave as expected. Note that in expressions we use typewriter font (e.g., \texttt{+.}) to represent an operator, whereas for values we use mathematical font (e.g., +).
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
v_1 + v_2 = v
}
{e_1 \ \texttt{+.} \ e_2 \Downarrow v}
\ \textsf{(FloatAddEval)}
\qquad
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
v_1 - v_2 = v
}
{e_1 \ \texttt{-.} \ e_2 \Downarrow v}
\ \textsf{(FloatSubEval)}
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
v_1 * v_2 = v
}
{e_1 \ \texttt{*.} \ e_2 \Downarrow v}
\ \textsf{(FloatMulEval)}
\qquad
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
v_1 / v_2 = v
}
{e_1 \ \texttt{/.} \ e_2 \Downarrow v}
\ \textsf{(FloatDivEval)}
Also note that premises like 'v_1 + v_2 = v' are not a part of a derivation, they are like the side-conditions above. For example, we would write
\frac
{\texttt{2} \Downarrow \texttt{2}
\qquad
\texttt{3} \Downarrow \texttt{3}
}
{\texttt{2 + 3} \Downarrow \texttt{5}}
for a particular case of the rule for adding two integers.
The rule on the left reads
e_1 evaluates to v_1e_2 with v_1 substituted for x evaluates to v_2, then\texttt{let} \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 evaluates to v_2.\frac
{e_1 \Downarrow v_1
\qquad
[v_1/x]e_2 \Downarrow v_2
}
{\texttt{let} \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 \Downarrow v_2}
\ \textsf{(LetEval)}
\frac
{e_1 \Downarrow \texttt{(} v_1\texttt{,} v_2\texttt{,} \dots \texttt{,} v_n \texttt{)}
\qquad
[v_1 / x_1, v_2 / x_2, \dots, v_n / x_n]e_2 \Downarrow v_2
}
{\texttt{let (} x_1 \texttt, x_2 \texttt,\dots\texttt,x_n \texttt{) =} \ e_1 \ \texttt{in} \ e_2 \Downarrow v_2
}
\ \textsf{(LetTupleEval)}
\frac
{e \Downarrow \texttt{true}
\qquad
e_1 \Downarrow v_1
}
{\texttt{if} \ e \ \texttt{then} \ e_1 \ \texttt{else} \ e_2 \Downarrow v_1}
\ \textsf{(IfTrue)}
\qquad
\frac
{e \Downarrow \texttt{false}
\qquad
e_2 \Downarrow v_2
}
{\texttt{if} \ e \ \texttt{then} \ e_1 \ \texttt{else} \ e_2 \Downarrow v_2}
\ \textsf{(IfFalse)}
\frac
{e \Downarrow v
\qquad
v \text{ matches } p_i
\qquad
\forall j < i.(v \text{ does not match } p_j)
\qquad
e_i \Downarrow v_i
}
{\texttt{match} \ e \ \texttt{with} \ p_1 \ \texttt{->} \ e_1 \ \texttt{|} \ \dots \ \texttt{|} \ p_n \ \texttt{->} \ e_n \Downarrow v_i}
\ \textsf{(PatternEval)}
Note. This rule is slightly informal because we haven't defined exactly what a pattern is. You won't be expected to write a derivation of a semantic judgment with this rule.
\frac
{e_1 \Downarrow v_1
\qquad
e_2 \Downarrow v_2
\qquad
\dots
\qquad
e_n \Downarrow v_n
}
{\texttt{(} e_1\texttt{,} e_2\texttt{,} \dots \texttt{,} e_n \texttt{)}
\Downarrow
\texttt{(} v_1\texttt{,} v_2\texttt{,} \dots \texttt{,} v_n \texttt{)}
}
\ \textsf{(TupleEval)}
\frac{}{\texttt{[]} \Downarrow \texttt{[]}}
\ \textsf{(NilEval)}
\qquad
\frac
{e \Downarrow v
\qquad
l \Downarrow \texttt{[} v_1 \texttt{;} v_2\texttt{;}\dots\texttt;v_n\texttt{]}
}
{e \ \texttt{::} \ l \Downarrow
\texttt{[} v \texttt{;} v_1 \texttt{;} v_2\texttt{;}\dots\texttt;v_n\texttt{]}
}
\ \textsf{(ConsEval)}
\frac
{e \Downarrow \texttt{[]}
\qquad
e_1 \Downarrow v_1
}
{\left(\texttt{match} \ e \ \texttt{with [] -> } e_1 \ \texttt{|} \ h \ \texttt{::} \ t \texttt{ -> } e_2 \right)
\Downarrow
v_1
}
\ \textsf{(ListMatchNilEval)}
\frac
{e \Downarrow (v \ \texttt{::} \ v')
\qquad
[v / h][v' / t]e_2 \Downarrow v_2
}
{\left(\texttt{match} \ e \ \texttt{with [] -> } e_1 \ \texttt{|} \ h \ \texttt{::} \ t \texttt{ -> } e_2 \right)
\Downarrow
v_2
}
\ \textsf{(ListMatchConsEval)}
\frac
{e_1 \Downarrow v_1 \qquad e_1 \Downarrow v_2 \qquad \dots \qquad e_n \Downarrow v_n}
{\texttt{[} e_1 \texttt{;} e_2 \texttt{;}\dots\texttt;e_n\texttt{]} \Downarrow \texttt{[} v_1 \texttt{;} v_2 \texttt{;}\dots\texttt;v_n\texttt{]}}
\ \textsf{(ListLitEval)}