CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Programs as Data:

Assignments and Iteration

Expressions, Results, and Types

If expressions can have more than one type, how does this change our “little programming language” implementation?

Need a type to represent values in the program, e.g. 5, true

Need a type to represent types of program expressions, such as int, bool.

type result = IntR of int | BoolR of bool
type expType = BoolT | IntT
val eval : expr -> (string*result) list -> result

So the expression IntC 5 has value IntR 5 and type IntT.

Imperative features

Representing programs:

type expr = <arith> | <bool> | <compare> | <let> | <if>
type expType = IntT | BoolT
type result = IntR | BoolR

What about supporting imperative programs?

Assignment Set of string * expr (* variable, value *)
Loops While of expr * expr (* condition, body *)
Sequences Seq of expr list (* exprs to execute *)
{ int x = 1;
  x = x+1;
  int y = x;
  return y;
}
let p1 =
  Let ("x",IntC 1, Seq([
  Set ("x",Add(Name "x",IntC 1));
  Let ("y",Name "x",
  Name "y")]))
let rec eval e env = match e with
| Set(n,v) -> let vr = eval v env in
  (* what does assignment "return?" *)

Lexical environment becomes a store that is part of the result of each operation:

let rec assign name value store =
  match store with
  | [] -> failwith "assign to unbound name"
  | (n,v)::t when n=name -> (name,value)::t
  | b::t -> b::(assign name value t)
let rec eval exp store = match exp with ...
| Set(name,v) ->
  let (vr,st') = (eval v store) in
     (UnitR, assign name vr st')

The store is then given as an argument to the next operation:

let rec eval exp store = match exp with ...
| Seq (elist) -> evalSeq elist store
...
and evalSeq elist st = match elist with
  | [] -> (UnitR, st)
  | e::[] -> eval e st
  | e::t -> let (_,st') = (eval e st) in evalSeq t st'
    (* hey look, tail recursion *)

While

let rec eval exp state = match exp with ...
| While(cond,body) -> evalWhile cond body st
...
and evalWhile cond body st =
  let (cond_res,st') = eval cond st in let (BoolR b) = cond_res in
  if (not b) then (UnitR, st')
  else let (_,st'') = eval body st' in
    evalWhile cond body st''
    (* tail recursion again *)

What should the “result” of a while loop be?

Consider eg. While (BoolC false, <anything>)

Types

Type checking…

While:

c : BoolT    b : τ
While (c, b) : UnitT

Set:

(n : τ) ⊦ (v : τ)
Set (n, v) : Unit

Seq:

Seq []: UnitT
e : τ ⇒ Seq([e]) : τ
h : τ ∧ Seq(t) : τ₁ ⇒ Seq (h::t) : τ₁

Examples:

let p2 = Let("x", IntC 1,
  While (BoolC true,
  Seq[
    Set("x", Add(Name "x", IntC 1));
    Set("x", Mul(Name "x", Name "x"))
  ]))
typeof p2 [];;
eval p2 [];;

Note: Because type (and name) analysis is static, type checking halts even though the program does not…

cs2041.org

// reveal.js plugins