%%% 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{23} %% Lecture number
\title{Typed Lambda Calculus}   %% Title of lecture
\author{Leonid Meyerguz, Stephen Chong, Prakash Linga, Andrew Myers}
%% name of scribe
\date{24 October 2005}    %% Date of lecture
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% See 611.sty for a variety of macros that will be helpful in
% typesetting the lecture
%
% quotes can be used for typewriter font
% <> can be used for angle brackets

\begin{document}

\maketitle

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% CS611: SCRIBE NOTES GO HERE!
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
_Type checking_ is a lightweight technique for proving
simple properties of programs.  Unlike theorem-proving
techniques based on axiomatic semantics,
type checking usually cannot determine if a program will
produce the correct output; instead, it is a way to test
whether a program is _well-formed_, with the idea that a
well-formed program satisfies certain simple
properties. The traditional application of type checking
is to show that a program cannot get stuck; that is,
that a type-correct program will
never reach a non-final configuration in its operational
semantics from which its behavior is undefined.  This is a
very weak notion of program correctness, but it turns out to
be very useful in practice for catching bugs. Type systems
are a powerful technique; in the past couple
of decades, researchers have figured out how to use type systems
for an amazing variety of different purposes.

We have already seen some typed languages in class this semester.
For example, ML and the metalanguage used in class for denotational
semantics are both
typed.  We will now explore the idea of type checking itself:
we will introduce a typed variant of lambda calculus,
show how to construct operational and denotational semantics for
this language, and discover some interesting properties that give
some insight about more complex languages.

\section{Syntax}

A typed lambda calculus ($\lambda^\to$) program is an expression containing
no free variables.  The syntax is virtually identical to that of
untyped lambda calculus, with the exception of $\lambda$-terms.
Since lambda abstraction defines a function expecting an argument,
$\lambda$-terms in $\lambda^\to$ programs should expect arguments of a
certain type.  In addition, $\lambda^\to$ will allow a kind of expressions,
corresponding to base values, such as integers, booleans, and unit
values.  Finally, $\lambda^\to$ will define set of base types, corresponding
to the base values.  So, the complete syntax is given below:
\begin{eqnarray*}
e & ::= & x \bnf e_1~e_2 \bnf \lam{x\ty\tau}e \bnf b \\
b & ::= & 0 \bnf 1 \bnf 2 \bnf \ldots \bnf "true" \bnf "false"
        \bnf "null" \\
\tau\in\Set{Type} & ::= & B \bnf \tau _1 \rightarrow \tau _2 \\
B & : = & "int" \bnf "bool" \bnf 1 \\
v\in\Set{Value} & ::= & b \bnf \lam{x\ty\tau}e
\end{eqnarray*}

The key difference between a the typed and untyped Lambda calculus
is that every $\lambda^\to$ expression has an associated type.  For
example, the expression $"1"$ has the type "int", which we can
write as "1: int". The _type_ "1" has nothing to do with integers; it
is the type of the single unit value "null".
Likewise, the function $\nm{TRUE}\sub{int} =
\lambda x:"int" . "\lambda" y:"int" . x$ has the type $"int"
\rightarrow ("int" \rightarrow "int")$.  Since the $\rightarrow$
operator is right-associative, we can write
\begin{eqnarray*}
\nm{TRUE}\sub{int} = ("\lambda" x:"int" ."\lambda" y:"int" . x) :
"int" \rightarrow "int" \rightarrow "int" \\
\end{eqnarray*}

\section{Small-Step Operational Semantics and Type Correctness}

The small-step operational semantics in $\lambda^\to$ are no different from
those in untyped $\lambda$-calculus.  The presence of types does
not alter the evaluation rules for expressions, but merely limits
on the kinds of expressions that may be evaluated. 
The evaluation contexts and small step operational semantics for
$\lambda^\to$ are unchanged from the untyped lambda calculus:

\[ E ::= E~e \bnf v~E \bnf [\cdot] \]
\[ E[(\lam{x\ty\tau}e)v] \stepsone E[\subst{e}{v}{x}] \]

Now, we are ready to revisit the concept of correctness that
we touched upon at the beginning of the lecture.
We use the notation $\vdash e:\tau$ to mean that $e$ is well-typed with the
type $\tau$. This assertion is also called a _typing_ for $e$.
If a program $e$ is
well-formed (i.e., well-typed) then it cannot become stuck at any point during
its execution.  Thus, if a well-typed program $e$ evaluates to some
expression $e'$ such that $e'$ is not a base value or a $\lambda$-term,
then $e'$ must itself evaluate to some other expression $e''$. Formally,

\[
\vdash e:\tau \wedge e\rightarrow^* e' \Rightarrow (e'\in
\Set{Value} \vee \exists e''. e' \rightarrow e'')
\]

A language that satisfies this property is strongly typed, because
legal programs cannot get stuck. And unlike some strongly typed
languages we saw earlier in the semester, this language can be
implemented without any run-time checking!

By now, it is natural to inquire about what a type-incorrect $\lambda^\to$
program would look like, and how it may get stuck.  In answer to
this question, recall our function definition for
$\nm{TRUE}\sub{int}$ above, and consider the following additional
definition:
\begin{eqnarray*}
\nm{IF}\sub{int} = \lam{"t"\ty "int" \rightarrow "int" \rightarrow
"int"}{\lam{a\ty"int"}{\lam{"b"\ty"int"}{t~a~b}}}
\end{eqnarray*}
Clearly, $\nm{IF}\sub{int}(\nm{TRUE}\sub{int}~2~3)$ will evaluate to 2.
However, consider the expression $\nm{IF}\sub{int}("true"~2~3)
\rightarrow (("true"~ 2)~3)$.  The expression $("true"~2)$ is
meaningless, since "true" is not a function term. Therefore, the
program gets stuck at this point.

\section{Static Semantics and Type Checking}

In order to analyze programs written in typed languages, we introduce
a new kind of semantics called a _static semantics_.  The name is a
bit misleading -- it's not really a semantics for the language, but
rather a set of rules that define which programs are legal, usually
expressed as a set of inference rules that defines the relationship
between expressions and types of a language.  In a moment, we will give
the static semantics of typed lambda calculus, but prior to this, we
must introduce the notion of _typing context_.

A typing context $\Gamma$ is an environment
that maps variables to types. We can view it as a partial
function that takes a variable and returns the variable's type:
$\Gamma\in\Set{Var} \rightharpoonup \Set{Type}$. The notation $\dom(\Gamma)$
is used to refer to the finite
subset of the domain \Set{Var} on which $\Gamma$ is
defined.  The typing context $\emptyset$ is the empty typing context
where $\dom(\emptyset)$ is empty.

We are now ready to give the static semantics for typed Lambda
calculus.  We write $\Gamma \vdash e:\tau$ to signify that the
expression $e$ is correct with respect to type $\tau$ within the
typing context $\Gamma$. The assertion $\vdash e:\tau$ we define as
$\emptyset \vdash e:\tau$. Below, we give the inference rules for
well-typed $\lambda^\to$ programs:
\bigskip

\begin{tabular}{ccccc}
\infer{ \Gamma \vdash n:"int" } { } & ~~~ & \infer{ \Gamma \vdash
"true":"bool" } { } & ~~ & \infer{ \Gamma \vdash "null":1 } { }
\\
\\
\infer{ \Gamma[x\mapsto\tau] \vdash x:\tau} {} & ~~~ & \infer{
\Gamma \vdash e_0~e_1 : \tau' } { \Gamma \vdash e_0 : \tau
\rightarrow \tau' & \Gamma \vdash e_1:\tau } & ~~ & \infer {
\Gamma \vdash (\lam{x\ty\tau}{e}) : \tau \rightarrow \tau'}
{\Gamma[x\mapsto\tau] \vdash e:\tau'}
\end{tabular}
\bigskip

Let us explain these inference rules in more detail. If $e$
is an expression consisting of a single variable $x$, then $\Gamma
\vdash e:\tau$ requires that $x$ have type $\tau$ in the
typing context; that is, we must be able to find a context $\Gamma$
such that the current typing context can be described as
$\Gamma[x\mapsto\tau]$. (Often, as in Pierce's book, this
is written as $\Gamma, x\ty\tau$.)
If $e$ is an application of $e_0$ to $e_1$ that
has the type $\tau'$ , then $e_0$ must be a function from $\tau$
to $\tau'$, and $e_1$ must have the type $\tau$.  Finally, if the
lambda-abstraction $\lam{x\ty\tau}{e}$ is a function of type $\tau
\rightarrow\ \tau'$, then $e$ must have the type $\tau'$ within
the typing context $(\Gamma[x\mapsto\tau]$, which we modify in
order to account for the possibility that the variable $x$ of type
$\tau$ may legally appear among the free variables of $e$.

To type-check a $\lambda^\to$ program, we can attempt to construct its proof
tree.  For example, consider the program $(\lam{x\ty"int"}x)~2$,
which evaluates to "2". So we expect its type is "int".
We can construct a proof tree for this program as follows:
\bigskip

\begin{tabular}{c}
\infer{ \Gamma \vdash (\lambda x:"int".~x)~2 : "int"} {
   \infer { \Gamma \vdash (\lambda x:"int".~x) : "int" \rightarrow
   "int"} {
        \infer { (\Gamma, x:"int") \vdash x:"int" }
               {x:"int" \in (\Gamma, x:"int") }
    }
& \Gamma \vdash 2:"int" }
\end {tabular}
\bigskip

The above is a valid proof tree for our program. An automated type
checker effectively constructs proof trees like this one in order
to test whether a program is type-correct.

\section{Expressive Power of Typed Lambda Calculus}

By now you may be wondering if we have lost any of the expressive power
of lambda calculus by introducing types.  The answer to this
question is a resounding yes.  First of all, we have lost generic
function composition.  We can no longer compose any two arbitrary
functions, since they may have mismatched types.  The
$\nm{IF}\sub{int}$ function above is a good example of this.

Second, and perhaps more importantly, we have lost the ability to
write loops.  To convince ourselves of that, recall
the term $\Omega$ that we defined as
\begin{eqnarray*}
\Omega = (\lambda x~(x~x))~(\lambda x~(x~x))
\end{eqnarray*}

Let us attempt to construct a derivation of a typing for the
$\lambda^\to$ expression $(\lam{x\ty\tau}{x~x})$:
\bigskip

\begin{tabular}{c}
\infer{\Gamma \vdash (\lam{x\ty\tau}{x~x}) : \tau \rightarrow
\tau'} {
    \infer {\Gamma[x\mapsto\tau] \vdash (x~x) : \tau' } {
        \Gamma[x\mapsto\tau] \vdash x:\tau \rightarrow \tau' &
        \Gamma[x\mapsto\tau] \vdash x:\tau
    }
}
\end{tabular}
\bigskip

From the above, we see that $x:\tau \rightarrow \tau'$ and
$x:\tau$. Therefore, we conclude that $\tau = \tau \rightarrow
\tau'$. It is not possible to write down any finite type expression that
satisfies this equation and therefore, we conclude that the
expression $(\lam{x:\tau}{(x~x)})$ cannot be typed.
In fact, a little later we will see
that we cannot write down _any_ nonterminating program in $\lambda^\to$,
at least according to a denotational model of what programs mean. This
will turn out be true from an operational perspective as well.
Fortunately, as we will see in later lectures, we can extend our type
system to allow nonterminating programs.

\section{Denotational Semantics for lambda calculus}

Before we can give the denotational semantics for $\lambda^\to$,
we need to define a new meaning function ${\cal T}$.
The function ${\cal T}$ takes a type $\tau$, and returns the
domain associated with that type.  For this type system, we can define
${\cal T}$ in a straightforward way:
\begin{eqnarray*}
\Te{"int"}  & = & {\mathbb Z}
\\
\Te{"bool"} & = & \{"true", "false"\}
\\
\Te{1} & = & {\mathbb U}
\\
\Te{\tau_1 \rightarrow \tau_2} & = & \Te{\tau_1} \rightarrow
\Te{\tau_2}
\end{eqnarray*}

Note that ${\cal T}$ returns an entire domain corresponding to a
type, not just an element of a domain. For the semantics of $\lambda^\to$,
the domains will not need to have any ordering properties: they are just
sets. So we have $\Tr T\cdot \in \nm{Type}\to\nm{Set}$. If a program $e$ can
be given type $\tau$, then we expect that the denotation of $e$ is an
element of $\Tr T{\tau}$.  Formally,
\begin{eqnarray*}
\vdash e:\tau \Rightarrow \C{e}\rho_0 \in \Te{\tau}
\end{eqnarray*}

It only makes sense to ask what the meaning of an expression $e$
is in a context in which the values of the free variables
correspond to the types of free variables
against which $e$ was type-checked. Therefore, we need to establish
a constraint on what environments $\rho$ we use, based on the typing context
$\Gamma$. We say that the environment $\rho$ satisfies a typing
context $\Gamma$, written as $\rho \models \Gamma$, if for every
variable-type mapping $x\mapsto\tau$ in $\Gamma$, $\rho(x)$ is in the
domain corresponding to $\tau$.  That is,
\begin{eqnarray*}
\rho \models \Gamma \stackrel {def}\Leftrightarrow
\forall x \in \nm{dom}(\Gamma)~.~\rho(x)\in\Tr T{\Gamma(x)}
\end{eqnarray*}

Finally, we need to modify the notation we use for the meaning
function ${\cal C}$ to account for the presence of types. It only
makes sense to take the meaning of well-formed (i.e., well-typed)
expressions. A convenient way to ensure this is to change the
meaning function to map _typing derivations_ to meanings rather than
_expressions_. Instead of writing $\Cr{e}$,
we will use the notation $\Cr{\Gamma \vdash
e:\tau}$, where $e$ has the type $\tau$ in the context
$\Gamma$.  We will not write the entire typing
derivation inside the semantic brackets, but it is implied. Therefore
the expression $e$ must be well-formed.

This kind of semantics---where we do not ascribe any meaning
to ill-formed terms---is known as a Church-style semantics.
Semantics follow typing. The alternative is a Curry-style
semantics, where we give a meaning even to programs that are
not well-typed. Our operational semantics, for example,
talks about how even ill-typed terms evaluate.

We expect that our denotational model satisfies the following
soundness condition for all $\rho, \Gamma, e, \tau$:
\begin{eqnarray*}
\rho \models \Gamma ~ \wedge ~ \Gamma \vdash e:\tau ~~\Rightarrow
~~ \C{\Gamma \vdash e:\tau}\rho \in \Tr T{\tau}
\end{eqnarray*}

We are now ready to give the long-awaited denotational semantics
for typed lambda calculus expressions:
\begin{eqnarray*}
\Cr{\Gamma \vdash n:"int"} & = & n
\\
\Cr{\Gamma \vdash "true":"bool"} & = & "true"
\\
\Cr{\Gamma \vdash "null": 1} & = & "unit"
\\
\Cr{\Gamma[x\mapsto \tau] \vdash x:\tau} & = & \rho(x)
\\
\Cr{\Gamma \vdash e_0~e_1:\tau'} & = & (\Cr{\Gamma \vdash
e_0:\tau \rightarrow \tau'})~(\Cr{\Gamma \vdash e_1:\tau})
\\
\Cr{\Gamma \vdash (\lam{x\ty\tau}e):\tau \rightarrow \tau') } & =
& \lm v{\Te{\tau}}{\C{\Gamma[x\mapsto\tau] \vdash e:\tau'}\rho[x \mapsto v]}
\end{eqnarray*}

Note that the definition $\C\cdot$ is well-founded; it is
defined by induction on the structure of the typing derivation that
is its argument. By construction, we can see that $\C\cdot$ satisfies
the soundness condition given above. The only interesting step in this
proof by induction on the typing derivation is the case of a lambda
term, which requires that we observe that:
\[
\rho\models\Gamma \wedge v\in\Tr T\tau
\Rightarrow \rho[x\mapsto v] \models \Gamma[x\mapsto \tau]
\]

Note that $\bot$ does not appear anywhere within this
semantics for typed lambda calculus. We didn't need to introduce it
because we never took a fixed point. Therefore, we conclude that
all typed lambda calculus programs terminate, at least according to
this model. Of course, we'll want to see that the operational semantics
are adequate with respect to this model to ensure that our evaluation
relation can actually find the meanings that this denotational model
advertises are there.

Another question we might naturally ask is whether our
operational semantics and our denotational semantics agree
with one another. For example, we can express the idea that
they agree on integers using the following adequacy condition:

\[
\vdash e : "int" \Rightarrow ((e \stepsone^* n) \Leftrightarrow
(\C{\vdash e : "int"}\emptyset = n))
\]

This can be proved using the technique of logical relations,
which we'll see soon.


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