UNB/ CS/ David Bremner/ teaching/ cs4613/ assignments/ CS4613 Assignment 3


In this assignment you will add type-inference for lists to the unification based interpreter from lecture12. The type inference should be based on the following type rule, which says that list elements can be any type, but they all have to be the same type (just like in plait).

\begin{equation} \frac{\Gamma \vdash e_1 : T\quad \Gamma \vdash e_2 : T\quad \Gamma \vdash e_3:T \;\dots\; \Gamma \vdash e_k : T}{\Gamma \vdash (\mathtt{list}\; e_1 \;e_2 \,\dots\, e_k) : (\mathrm{List} \; T)} \end{equation}

Start by downloading the skeleton interpreter This is the same as ti-interp.rkt from class, with change described in the next section.

Changes from Lecture 12

A new variant has been added to the Type type, and to the corresponding TE type representing abstract syntax for types. The function parse-type for mapping between them was also updated. A .... stub was added to unify!, that you will have to fill in in the next step.

(define-type TE
  [arrowTE (arg : TE) (result : TE)]
  [listTE (element : TE)] ;; New

(define-type Type
  [arrowT (arg : Type) (result : Type)]
  [listT (element : Type)] ;; New
  [varT (id : Number) (val : (Boxof (Optionof Type)))])

The abstract syntax has been updated to include a listE variant. A stub has been added to interp, that you will fill in below.

(define-type Exp
  [numE (n : Number)]
  [boolE (b : Boolean)]
  [notE (expr : Exp)]
  [plusE (lhs : Exp) (rhs : Exp)]
  [minusE (lhs : Exp) (rhs : Exp)]
  [timesE (lhs : Exp) (rhs : Exp)]
  [listE (elements : (Listof Exp))] ;; New
  [if0E (test-expr : Exp) (then-expr : Exp) (else-expr : Exp)]
  [recE (name : Symbol) (ty : TE) (rhs-expr : Exp) (body-expr : Exp)]
  [idE (name : Symbol)]
  [lamE (param : Symbol) (argty : TE) (body : Exp)]
  [appE (lam-expr : Exp) (arg-expr : Exp)])

A new variant has been added to the Value type to return lists.

(define-type Value
  [numV (n : Number)]
  [boolV (b : Boolean)]
  [listV (elements : (Listof Value))]
  [closureV (param : Symbol)
            (body : Exp)
            (env : ValueEnv)])

Question 1: update unify!

Update the given skeleton for unify! to handle list types. Follow the pattern for arrowT, and make sure your updated function passes the following functions.

(module+ test
  (test (unify! (listT (boolT)) (listT (boolT)) 'test) (void))
  (test/exn (unify! (listT (boolT)) (listT (numT)) 'test) "no type")
  (test/exn (unify! (boolT) (listT (numT)) 'test) "no type")
  (test/exn (unify! (listT (numT)) (boolT) 'test) "no type"))

Question 2: evaluating lists

Update the given skeleton for interp to evaluate lists. Your solution should pass (at least) the following tests

(module+ test
  (test (run `{list 1 2}) (listV (list (numV 1) (numV 2))))
  (test (run `{list false true false}) (listV (list (boolV #f) (boolV #t) (boolV #f)))))

Question 3: typechecking lists

Replace the stub in typecheck to enable typechecking of lists. Your solution should pass (at least) the following tests

(module+ test
  ;; lists of numbers
  (test/type `{list 1 2} (listT (numT)))

  ;; report error for mixed types
  (test/notype  `{list 1 true})

  ;; infer type of list
  (test/type `{lam {x : num} {list x}} (arrowT (numT) (listT (numT))))

  ;; functions taking list parameters
  (test/type `{lam {x : {listof num}} x}
             (arrowT (listT (numT)) (listT (numT))))

  ;; report error for mixed inferred types
  (test/notype `{lam {x : num} {list true x}})

  ;; infer type of function parameter from list element
  (test/type `{lam {x : ?} {list x 1}} (arrowT (numT) (listT (numT))))

  ;; complain about cyclic type (Y-combinator) inside list
  (test/notype `{lam {x : ?} {list {x x}}})

  ;; infer type of list from function application
  (test/type `{{lam {x : ?} {list x}} 2} (listT (numT)))


Referring to the grading grading rubric for guidance, add any needed tests for your solution.

As always, make sure you have complete test coverage.