Task 1. Develop type-checking
algorithms for the following language constructs, along the lines of
the type-checking algorithm we developed in the lectures.
- Here is pseudo-code for typechecking
P+Q :
class Div ( lhs : Prog, rhs : Prog ) extends Prog
def check ( env : SymbolTable, p : Prog ) : Type = {
...
case Div ( l : Prog, r : Prog ) => {
if ( check ( env, l ) != Int_T () || check ( env, r ) != Int_T () )
throw new Exception ( "..." )
else
Int_T () } }
-
while0 P do Q
class While0 ( cond : Prog, body : Prog ) extends Prog
case While0 ( cond, body ) => {
val t_cond = check ( env, cond )
if ( t_cond != Int_T ) throw new Exception ( "..." )
val t_body = check ( env, body )
if ( t_body != Unit_T ) throw new Exception ( "..." )
Unit_T () }
-
repeat P until Q
class RepeatUntil ( body : Prog, cond : Prog ) extends Prog
case RepeatUntil ( body, cond ) => {
val t_body = check ( env, body )
if ( t_body != Unit_T ) throw new Exception ( "..." )
val t_cond = check ( env, cond )
if ( t_cond != Bool_T ) throw new Exception ( "..." )
Unit_T () }
- The key insight in typechecking letrec x : t = P in Q comes from
comparing the typing rules with those for let x : t = P in Q.
Γ ⊢ P : α Γ, x : α ⊢ Q : β
--------------------------------
Γ ⊢ let x : α = P in Q : β
Note that the red assumption does not contain an entry for x , unlike
here:
Γ, x : α ⊢ P : α Γ, x : α ⊢ Q : β
----------------------------------------
Γ ⊢ letrec x : α = P in Q : β
Task 2. Some languages have
features like exceptions (which can be raised using a construct
like throw ), or Java's System.exit ( ... )
that immediately aborts the calling program. Discuss how to type-check
such program constructs.
Answer: The trick is to realise that
these constructs can have any type whatsoever as return type, since
they never return. For example if e has type integer,
then System.exit ( ... ) has type t for
any type t .
This is also true
for throw , but we must have a type of exceptions in our
sets of types. Then whatever is being thrown must have be an
exception.
Task 3. Consider a function/procedure/method
as follows:
def f( x : ??? ) : ??? = { return x }
Discuss what kind of types you would give to f .
Answer: There are many
approaches to this problem. But all involve in some form or shap a
new form of type called universal type. Some programming
languages write it like this:
def [T] f( x : T ) : T = { return x }
This means: for any
type T , the procedure f has type
def f( x : T ) : T = { return x }
For example f has
type
def f( x : Int ) : Int = { return x }
and
def f( x : Bool ) : Bool = { return x }
A lot more could be said about this
topic. If you are interested, please contact me, or read the
excellent book Types and
programming languages by B. Pierce -- it's in the library.
|