%%% This is the scribe notes template for CS611
%%% There are several comments preceded by CS611: and boxed in %%%%'s 
%%% which indicate where macros should be altered to set up the header
%%% for the paper.  Your Notes should go at the comment SCRIBE NOTES GO HERE!.

%%% In the various .sty files that accompany this .tex file you will    
%%% find LaTeX macros that make it easier to typeset inference rules    
%%% and programming language constructs.  You must make sure that the   
%%% file proof.sty is in a path searched by LaTeX when you try to       
%%% use this file.  Take a look to see what macros are available--it    
%%% will save you time and make the notes look better.  Feel free to    
%%% extend the set of macros--post them to the newsgroup and contact    
%%% the course staff if you come up with some good ones so they can be  
%%% added to the template.                                              

%%% This template includes examples of how to use some of the macros
%%% to give you an idea of how they work.  (Delete the examples when
%%% you do your scribing.)

\documentclass{article} \usepackage{611-lecture}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% CS611: Please fill in these macros as appropriate:
\lecture{28}                  %% Lecture number
\title{Type Unification}   %% Title of lecture
\author{Kevin Markman and Ryan Peterson}       %% name of scribe
\date{11 November 2005}     %% Date of lecture, e.g., 1 January 2001
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% See 611.sty for a variety of macros that will be helpful in
% typesetting the lecture. Here are a few of particular interest:
%
% "x"	 	x in keyword font (e.g., "if", "#t")
% _x_	 	x in italics
% \nm{n}   	n in slanted font (used for abbreviations)
% <e> 	 	e in angle brackets
% \lt 	 	less-than sign
% \gt 	 	greater-than sign
% \SB{x}	x in semantic brackets
% \Tr x{y} 	x[[y]] with x in calligraphic font
%          	(if x is more than a single character, use \Tr{x}{y})

\begin{document}

\maketitle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% CS611: SCRIBE NOTES GO HERE!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Last lecture we saw whether it would be possible to unify types, but
we never showed how to actually see the result.  We change our
definition of "unify" from last lecture to be:
\[
"unify"(T=\tau, E)="unify"(E\{\tau/T\})\circ\{T\mapsto\tau\}
\]


\section{Type Checker}

We can code this up our type inference in pseudo-SML:
\begin{quote}
"datatype type = Int$\bnf$Bool$\bnf$Arrow of type~*~type$\bnf$TypeVar of type option ref"
\end{quote}
\begin{quote}
"fun tcheck($\Gamma$, e):type ="\\
\phantom{dd}"case e of"\\
\phantom{dd}"Num n" $\Rightarrow$ "Int"\\
\phantom{dd}$\bnf$"Var x" $\Rightarrow \Gamma$"(x)"\\
\phantom{dd}$\bnf$"App($e_0$, $e_1$) $\Rightarrow$"\\
\phantom{dddd}"let"\\
\phantom{dddddd}"$t_0$ = tcheck($\Gamma, e_0$)"\\
\phantom{dddddd}"$t_1$ = tcheck($\Gamma, e_1$)"\\
\phantom{dddddd}"$T_2$ = freshType()"\\
\phantom{dddd}"in"\\
\phantom{dddddd}"(unify($t_0$, Arrow($t_1$, $T_2$)); $T_2$)"\\
\phantom{dd}$\bnf$ "Lambda(x, e) $\Rightarrow$"\\
\phantom{dddd}"let"\\
\phantom{dddddd}"$T_1$ = freshType()"\\
\phantom{dddddd}"$t_2$ = tcheck(extend($\Gamma$, x, $T_1$), e)"\\
\phantom{dddd}"in"\\
\phantom{dddddd}"Arrow($T_1$, $t_2$)"
\end{quote}
Now we have to define our "freshType" function:
\begin{quote}
"fun freshType () ="\\
\phantom{dd}"TypeVar(ref NONE)"
\end{quote}
Next we have to resolve our types:
\begin{quote}
"fun resolve(t:type):type ="\\
\phantom{dd}"case t of"\\
\phantom{dddd}"TypeVar(r as ref(SOME t')) $\Rightarrow$"\\
\phantom{dddddd}"let t'' = resolve(t') in (r := t''; t'')"\\
\phantom{dd}$\bnf$"_ $\Rightarrow$ t"
\end{quote}
Next we have to unify the types:
\begin{quote}
"fun unify($t_1$, $t_2$) ="\\
\phantom{dd}"case(resolve($t_1$), resolve($t_2$)) of"\\
\phantom{dddd}"(Int, Int) $\Rightarrow$ ()"\\
\phantom{dd}$\bnf$"(Bool, Bool) $\Rightarrow$ ()"\\
\phantom{dd}$\bnf$"(Arrow($t_1$, $t_2$), Arrow($t_3$, $t_4$)) $\Rightarrow$"
"(unify($t_1$, $t_3$); unify($t_2$, $t_4$))"\\
\phantom{dd}$\bnf$"(TypeVar(r as ref NONE), $t_2$) $\Rightarrow$"\\
\phantom{dddddd}"if not_in(r, $t_2$) then r := $t_2$ else raise Fail ``Error''"\\
\phantom{dd}$\bnf$"($t_1$, TypeVar(r as ref NONE)) $\Rightarrow$"\\
\phantom{dddddd}"if not_in(r, $t_1$) then r := $t_1$ else raise Fail ``Error''"\\
\phantom{dd}$\bnf$"_ $\Rightarrow$ raise Fail ``Error''"\\
\end{quote}


\section{Type Schemas}

The problem with the above code is that we do not quite have as much
polymorphism as we expect to have.  Consider, for example, binding the
identity function to a variable and then applying it to an "Int" and
then to a "Bool".  The type checker encounters the Int first and says
that the function is of type "Int"$\to$"Int" and then it gives
us an error when we try and use the identity function on the bool
parameter.  We have to do something special for this, so we go use
\emph{type schemas} and \emph{type variables} instead. Type schemas
are patterns for types that can be instantiated to create actual
types.
\[
\forall X.~X\to X
\]
Similarly for multivariate expressions:
\[
\forall X,Y.~X\to Y
\]
To do this we have to modify $\Gamma$.  It is now a mapping from
variables to type schemas:
\[
\Gamma = x_1:\sigma_1, x_2:\sigma_2, \ldots
\]
We now have to modify our "tcheck" function in order to accommodate
for our new $\Gamma$.  We change the "Var" case in "tcheck" to be:
\begin{quote}
$\bnf$"Var x $\Rightarrow$ let s = $\Gamma$(x) in instantiate(s)"
\end{quote}
We also have to provide an extra case for the "Let" statement:
\begin{quote}
$\bnf$"Let(x, $e_1$, $e_2$) $\Rightarrow$"\\
\phantom{dddd}"let $t_1$ = tcheck($\Gamma$, $e_1$) in"\\
\phantom{dddddd}"tcheck(extend($\Gamma$, x, generic($t_1$, $\Gamma$)), $e_2$)"
\end{quote}
Now we have to show what our schema is and the definitions for
"generic" and "instantiate":
\begin{quote}
"schema = Typepar list * type"\\[8pt]
"generic($\tau$, $\Gamma$):Typepar = FTV($\tau$) $\setminus$
FTV($\Gamma$)"\\[8pt]
"instantiate(s:schema):type = replace all Typepar of s with fresh TypeVar"
\end{quote}
Note that schemas are only created inside "Let" expressions. For this
reason, this approach is called \emph{let-polymorphism}. In theory, it
can cause the type checker to run in exponential time, but in practice
this is not a problem.


\section{Polymorphic Lambda-Calculus}

We can add support for type schemas to the $\lambda$-calculus.  The
resulting language is called the \emph{polymorphic
  $\lambda$-calculus}, or the \emph{second-order $\lambda$-calculus}
because the supported type operations are much like the regular
expressions, but at a higher level. In this new language,
\[
e ::= \cdots \bnf \Lambda X.e \bnf e[\tau]
\]
where the new expressions are type abstraction and type
application. The supported types are now
\[
\tau ::= b \bnf \tau_1 \to \tau_2 \bnf X \bnf \forall X.~\tau.
\]
The addition to the operational semantics should look familiar:
\[
\infer{(\Lambda X.e)\tau \to e\{\tau / X \}}{}
\]
This just gives the rule for instantiating type schema. Since this
only affects the types, it can be performed at compile time. In order
to write the new typing rules, we need a notion of well-formed
types. We introduce a new context $\Delta$ that maps type variable
names to their _kinds_ (for now, there is only one kind: type).
\[
\Delta = X_1::\mbox{type}, X_2::\mbox{type}, \ldots
\]
where we use double colons to remind ourselves that this is not
just a typing context; we're at a higher
level than the types we've seen before (remember, second order!). Now
we can formalize new higher-order rules for determining the legal
types:
\[
\begin{array}{ccc}
\infer{\Delta, X::\mbox{type} \proves X::\mbox{type}}{}
\phantom{ddddd} &
\infer{\Delta \proves \tau_1 \to \tau_2::\mbox{type}}{\Delta
  \proves \tau_1::\mbox{type} \quad \Delta \proves
  \tau_2::\mbox{type}} \phantom{ddddd} &
\infer{\Delta \proves \forall X.\tau::\mbox{type}}{\Delta,
  X::\mbox{type} \proves \tau::\mbox{type}} \\
\end{array} 
\]
The form of the typing judgement is modified to use the new typing
context $\Delta$:
\[
\Delta; \Gamma \proves e:\tau
\]
\noindent
where we will only try to construct such judgements when the
context $\Gamma$ contains well-formed types:
\[
\forall \tau \in \Gamma.~\Delta \proves \tau::\mbox{type}
\]
\noindent
or as a shorthand,
\[
\Delta \proves \Gamma.
\]
Here are the language's new typing rules, taking $\Delta$ into
account:
\[
\begin{array}{ccc}
\infer{\Delta; \Gamma, x:\tau \proves x:\tau}{} \phantom{ddddd} &
\infer{\Delta; \Gamma \proves e_0~e_1:\tau}{\Delta; \Gamma \proves
  e_0:\tau_1 \to \tau \quad \Delta; \Gamma \proves
  e_1:\tau_1} \phantom{ddddd} &
\infer{\Delta; \Gamma \proves \lambda x.e:\tau \to
  \tau'}{\Delta; \Gamma, x:\tau \proves e:\tau' \quad \Delta \proves
  \tau::\mbox{type}} \\
\end{array}
\]
\[
\begin{array}{cc}
\infer{\Delta; \Gamma \proves e[\tau]:\tau'\{\tau/X\}}{\Delta; \Gamma
  \proves e:\forall X.\tau' &
  \Delta \proves \tau
  } \phantom{ddddd} &
\infer{\Delta; \Gamma \proves \Lambda X.e:\forall X.\tau}{\Delta,
  X::\mbox{type}; \Gamma \proves e:\tau \quad X \notin \Delta} \\
\end{array}
\]
To finish up, here are a few properties of the polymorphic
$\lambda$-calculus:
\begin{enumerate}
\item it's possible to give a type schema for $\lambda x.~x~x$, but
  not for $\Omega$, which has a recursive type,
\item it can only implement primitive recursive functions,
\item it is still strongly normalizing (not obvious, but not proved
  here),
\item it is still not Turing Complete,
\item type inference is undecidable, so the programmer must provide
  types.
\end{enumerate}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\end{document}
