Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing...

34
Cse321, Programming Languages and Compilers 1 06/23/22 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing programs Handling errors Guessing types Declarations Let expressions
  • date post

    22-Dec-2015
  • Category

    Documents

  • view

    215
  • download

    1

Transcript of Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing...

Page 1: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

104/19/23

Lecture #14, Feb. 28, 2007

• Writing type-checkers in ML

•Role of type rules

•Representing types

•Representing programs

•Handling errors

•Guessing types

•Declarations

•Let expressions

Page 2: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

204/19/23

Type Checkers in ML• To build type-checkers in ML we need

– A datatype to represent types– A datatype (or datatypes) to represent programs (whose type we

are checking)» Expressions» Statements» Declarations

– A means for computing equality over types– A means for expressing type errors

• We build type checkers as attribute computations– We need to think ahead.– An attribute computation for each datatype representing programs– What are the inherited and synthesized attributes for each

datatype– What will the type of the functions that implement each attribute

computation.– Will we simply compute a type, or will we decorate the syntax

tree?

Page 3: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

304/19/23

The role of type rules

• Type rules play an important role.• They are short and concise• They are used as a communication

mechanism.

S |- x : a

S |- f : a -> t

------------------

S |- f x : t

Normally, the context is an inherited attribute, and the result is a synthesized attribute

Page 4: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

404/19/23

Representing Typesdatatype MLtype =

Unit

| Int

| Char

| Bool

| Product of MLtype list

| Arrow of (MLtype * MLtype);

Page 5: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

504/19/23

Representing Programs 1

datatype Op = Plus | Less | And

datatype Constant

= Cint of int (* 5 *)

| Cchar of char (* #”z” *)

| Cbool of bool (* true *)

and Dec

= Valdec of string*Exp

(* let val x = 5 in x end *)

| Fundec of string*string*MLtype*Exp

(* let fun f (x:int) = x + 1 in f end *)

Page 6: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

604/19/23

Representing Programs 2

datatype Exp

= Lit of Constant (* 5 *)

| Var of string (* x *)

| App of Exp*Exp (* f x *)

| Tuple of Exp list (* (x,3,true) *)

| Infix of Exp*Op*Exp (* x+3 *)

| Stmt of Exp list (* (print x; 3) *)

| If of Exp * Exp * Exp (* if x then y else 3 *)

| While of Exp * Exp (* while x do (f x) *)

| Anonfun of string * MLtype * Exp

(* (fn x => x+1) *)

| Let of Dec*Exp (* let val x = 1 in x end *)

Page 7: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

704/19/23

Type Equalityfun typeeq (x,y) =

case (x,y) of

(Void,Void) => true

| (Int,Int) => true

| (Char,Char) => true

| (Bool,Bool) => true

| (Arrow(d1,r1),Arrow(d2,r2)) => typeeq(d1,d2) andalso

typeeq(r1,r2)

| (Product(ss),Product(ts)) => (listeq ss ts)

| (_,_) => false

and listeq (x::xs) (y::ys) =

typeeq(x,y) andalso listeq xs ys

| listeq [] [] = true

| listeq _ _ = false

Page 8: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

804/19/23

Expressing Errors

• In ML we are lucky to have a rich exception mechanism.

1. We could use one exception for each kind of type error.

2. Or we could have a general purpose exception that carried specific information about the error.

3. Or something in between.

• We use the second approach

exception TypeError of Exp*string;

fun error e s = raise(TypeError (e,s));

Page 9: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

904/19/23

Functions to report errorsfun showt Unit = "()" | showt Int = "int" | showt Char = "char" | showt Bool = "bool" | showt (Product ts) = let fun showeach [] = "" | showeach [x] = showt x | showeach (x::xs) = (showt x)^"*"^(showeach xs) in "("^(showeach ts)^")" end;

fun unexpected r t1 t2 = error r ("Found type "^ (showt t1)^ " expecting type "^ (showt t2));

Page 10: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1004/19/23

Thinking ahead• We have 4 different datatypes that

represent programs– Op

– Constant

– Exp

– Dec

• What attributes will each have?– Two kinds of attributes in this case: types and contexts

– Types === MLtyp

– Context === (string*MLtype) list

• Inherited or Synthesized?– Op synthesized: (MLtype * MLtype * MLtype)

– Constant synthesized: MLtype

– Exp inherited (string*MLtype) list

synthesized: MLtype

– Dec inherited (string*MLtype) list

synthesized: ( MLtype * (string*MLtype) list)

Page 11: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1104/19/23

Types of programs implementing the attribute computations

• TCOp:: OP -> (MLtype * MLtype * MLtype)

• TCConstant:: Constant -> MLtype

• TCExp Exp ->

(string*MLtype) list ->

MLtype

• TCDec:: Dec ->

(string*MLtype) list ->

(MLtype * (string*MLtype) list)

Page 12: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1204/19/23

Operators

fun TCOp Plus = (Int,Int,Int)

| TCOp Less = (Int,Int,Bool)

| TCOp And = (Bool,Bool,Bool);

Left argument

Right argument

Result type

Page 13: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1304/19/23

Constants

fun TCConstant (Cint n) = Int

| TCConstant (Cchar c) = Char

| TCConstant (Cbool t) = Bool;

Note that the value of the constant, has nothing to do

with its type.

E.g. Both 4 and 12 have type Int

Page 14: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1404/19/23

Variables

(S x) = t --------------------- S |- x : t (where x = is a variable)

fun TCExp x cntxt =

case x of

Var s =>

(case List.find (fn (nm,t) => nm=s) cntxt of

SOME(nm,t) => t

| NONE => error x "Undeclared variable")

Page 15: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1504/19/23

ConstantsS |- n : int (where n = an integer constant like 5 or 23)

S |- c : char (where c = character constant like #”a” )

S |- b : bool (where b = boolean like true or false)

fun TCConstant (Cint n) = Int | TCConstant (Cchar c) = Char | TCConstant (Cbool t) = Bool;

fun TCExp x cntxt = case x of Lit c => TCConstant c

Page 16: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1604/19/23

Infix expressions

S |- x : t1 S |- y : t2

(S <+>)= t1 * t2 -> t3

----------------------------- where <+> is a binary operator like + or *S |- x <+> y : t3

fun TCExp x cntxt = case x of| Infix(l,x,r) => let val ltype = TCExp l cntxt val rtype = TCExp r cntxt val (lneed,rneed,result) = TCOp x in case (typeeq(ltype,lneed) ,typeeq(rtype,rneed)) of (true,true) => result | (true,false) => unexpected r rtype rneed | (false,true) => unexpected l ltype lneed | (false,false) => unexpected l ltype lneed end

Notice how sub expressions are type-checked first, then the result type is computed

from those results

Page 17: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1704/19/23

The Big picturefun TCExp x cntxt = case x of Lit c => TCConstant c | Var s => (case List.find (fn (nm,t) => nm=s) cntxt of SOME(nm,t) => t | NONE => error x "Undeclared variable") | Infix(l,x,r) => let val ltype = TCExp l cntxt val rtype = TCExp r cntxt val (lneed,rneed,result) = TCOp x in case (typeeq(ltype,lneed) ,typeeq(rtype,rneed)) of (true,true) => result | (true,false) => unexpected r rtype rneed | (false,true) => unexpected l ltype lneed | (false,false) => unexpected l ltype lneed end

Page 18: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1804/19/23

Function calls S |- x : a S |- f : a -> t---------------------- S |- f x : t

fun TCExp x cntxt = case x of| App(f,x) => let val ftype = TCExp f cntxt val xtype = TCExp x cntxt in case ftype of Arrow(dom,rng) => if ( typeeq(dom,xtype) ) then rng else unexpected x xtype dom | other => error f ("the type "^ showt other^ " is not a function") end

Note how the domain of the function must have the same type as the

actual argument.,

Page 19: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

1904/19/23

ML statement typesS |- ei : ai S |= en : t

--------------------------------------

S |- (e1; … ;en) : t

fun TCExp x cntxt =

case x of

| Stmt xs =>

let val xstypes = List.map

(fn x => TCExp x cntxt) xs

fun last [x] = x

| last (x::xs) = last xs

| last [] = error x "Tuple with no elements"

in last xstypes end

Page 20: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2004/19/23

ML tuples

S |- ei : ti

--------------------------------------

S |- (e1, … ,en) : (t1 * … * tn)

fun TCExp x cntxt =

case x of

| Tuple xs =>

let val xstypes =

List.map (fn x => TCExp x cntxt) xs

in Product xstypes end

Page 21: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2104/19/23

If expressions

S |- x : bool S |= y : t S |- z : t--------------------------------------- S |- if x then y else z : t

fun TCExp x cntxt = case x of | If(x,y,z) => let val xtype = TCExp x cntxt val ytype = TCExp y cntxt val ztype = TCExp z cntxt in case xtype of Bool =>if (typeeq(ytype,ztype)) then ytype else unexpected y ytype ztype | other => error x ("the type "^ showt other^ " is not boolean") end

Page 22: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2204/19/23

ML while stmt

S |- e : bool S |- s : a ------------------------------ S |- while e do s : unit

fun TCExp x cntxt = case x of| While(test,body) => let val ttype = TCExp test cntxt val btype = TCExp body cntxt in case ttype of Bool => Unit | other => unexpected test ttype Bool end

Page 23: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2304/19/23

ML anonymous function types

S+(x,a) |- e : b ------------------------------ S |- (fn (x:a) => e) : a -> b

fun TCExp x cntxt = case x of | Anonfun(x,t,body) => let val btype = TCExp body ((x,t)::cntxt) in Arrow(t,btype) end

S+(x,a) means add the mapping of variable x to the type a to the table S.

If S already has a mapping for x, then overwrite it with a

Note, how for the first time, the context, which is an inherited

attribute, gets bigger as it flows down the syntax tree into the body

Page 24: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2404/19/23

Handling declarations• Declarations are interesting because they have

contexts as both synthesized and inherited attributes.

• Consider

Let fun f x = x + 9

In 3 * f 4 end

The context flows into (fun f x = x+9), but a new context also flows out of it with a new typing for f so that the new context can flow into (3 * f 4)

• TCDec:: Dec ->

(string*MLtype) list ->

(MLtype * (string*MLtype) list)

Page 25: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2504/19/23

and TCDec (Valdec(nm,exp)) cntxt =

let val nmtype = TCExp exp cntxt

in (nmtype,(nm,nmtype)::cntxt) end

| TCDec (Fundec(nm,arg,argtype,body)) cntxt =

let val bodytype = TCExp body

((arg,argtype)::cntxt)

val nmtype = Arrow(argtype,bodytype)

val newcntxt = (nm,nmtype)::cntxt

in (nmtype,newcntxt) end

Note, recursive functions would need a

different strategy

Page 26: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2604/19/23

Let expressions

fun TCExp x cntxt =

case x of

| Let(d,b) =>

let val (_,cntxt2) = TCDec d cntxt

val btype = TCExp b cntxt2

in btype end

Page 27: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2704/19/23

Guessing types

• Recall the type constructor for anonymous functions

• Anonfun(x,t,body)

• Note in real ML the type of the argument is not given.

• The type is computed from the context it is used inside of body.

• In order to guess we must initialize the table with an empty slot, and then fill it in later.

Page 28: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2804/19/23

Represent types

datatype MLtype =

Unit

| Int

| Char

| Bool

| Product of MLtype list

| Arrow of (MLtype * MLtype)

| Tvar of (MLtype option) ref;

Think of the ref as a pointer (ref NONE) is a null pointer. (ref (SOME x)) is a pointer to x

A mutable reference we can overwrite later.

Page 29: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

2904/19/23

We must be careful

Tvar(ref (SOME _ ))

Tvar(ref (SOME _ ))

Tvar(ref (SOME _ ))

Tvar(ref (SOME Int ))

Tvar(ref (SOME _ ))

Tvar(ref (SOME _ ))

Tvar(ref (SOME _ ))

Tvar(ref (SOME Int ))

Page 30: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

3004/19/23

prunefun prune (Tvar(r as (ref(SOME x)))) = let val last = prune x in r := SOME last; last end | prune x = x;

Makes all references in a chain point to the very last type.

Also returns the very last type.

Will never return a Tvar unless it is unbound. I.e. it is a reference to NONE

Page 31: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

3104/19/23

Implement type equalityfun typeeq (x,y) =

case (prune x,prune y) of

(Unit,Unit) => true

| (Int,Int) => true

| (Char,Char) => true

| (Bool,Bool) => true

| (Arrow(d1,r1),Arrow(d2,r2)) =>

typeeq(d1,d2) andalso typeeq(r1,r2)

| (Product(ss),Product(ts)) => (listeq ss ts)

| (Tvar(r as (ref NONE)),t) => (r := SOME t; true)

| (t,Tvar(r as (ref NONE))) => (r := SOME t; true)

| (_,_) => false

Overwrite a null pointer once we know what it is supposed to

be equal to.

Page 32: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

3204/19/23

Whenever we case over an MLtype| App(f,x) => let val ftype = TCExp f cntxt val xtype = TCExp x cntxt in case prune ftype of Arrow(dom,rng) => if (typeeq(dom,xtype)) then rng else unexpected x xtype dom | other => error f ("the type "^ showt other^ " is not a function") end

Page 33: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

3304/19/23

A Second try

fun TCExp x cntxt =

case x of

| Anonfun(x, _ ,body) =>

let val t = Tvar(ref NONE)

val btype =

TCExp body ((x,t)::cntxt)

in Arrow(prune t,btype) end

Generate a new fresh empty slot.

I.e. guess the type

Hopefully typing the body will

force the slot to be filled in.Get rid of the

indirect reference if there is one

Page 34: Cse321, Programming Languages and Compilers 1 7/15/2015 Lecture #14, Feb. 28, 2007 Writing type-checkers in ML Role of type rules Representing types Representing.

Cse321, Programming Languages and Compilers

3404/19/23

CS321 Prog Lang & Compilers Assignment #10Assigned: Feb. 28, 2006 Due: Wednesday. March 7, 2007

1) The goal of this assignment is to extend the type checker discussed in lecture 14 to handle refereces and assinments. To do this you will need to

A) Add a new constructed type to MLtype to represent reference types. Do this by adding a new type constructor to MLtype called "Ref".

B) Add two new type constructors to "Exp" called "Init" and "Assign". They should coorespond to the underlined ML expressions in the examples below:

val x = ref 5 -------

val y = ( x := 6 ; print x) --------

C) Extend the function "typeeq" to handle the new "Ref" type.

D) Extend the function "TCExp" to handle the two new kinds of expressions. The cases should correspond to the type rules below.

S |- x : t ref S |- y : t--------------------------------- S |- x := y : unit

S |- x : t------------------------ S |- ref x : t ref

You may copy and paste the code from the lecture to get started. Test your code, and highlight all the additions to the lecture code you made in what you hand in.