2.18 Type Checker
Complete this assignment with Team Three.
You must submit this in an archive named "typec.zip".
You must submit this in a file named "typec.ss".
You must complete this assignment in the PLAI Scheme language. You can do so by choosing it from the Language|Choose Language... menu in DrScheme or via the language chooser at the bottom-left. You can also choose the Module language and have the following as the first line of your program:
In this assignment, you will work with a typed language that includes numbers, booleans, conditionals, functions, and numeric lists. The concrete syntax for the language is given by the following BNF grammars:
| expr | = | num | ||
| | | true | |||
| | | false | |||
| | | (+ expr expr) | |||
| | | (- expr expr) | |||
| | | (* expr expr) | |||
| | | (iszero expr) | |||
| | | (bif expr expr expr) | |||
| | | id | |||
| | | (with (id expr) expr) | |||
| | | (fun (id : type) : type expr) | |||
| | | (expr expr) | |||
| | | nempty | |||
| | | (ncons expr expr) | |||
| | | (nempty? expr) | |||
| | | (nfirst expr) | |||
| | | (nrest expr) | |||
| type | = | number | ||
| | | boolean | |||
| | | nlist | |||
| | | (type -> type) |
You have not implemented some of these constructs yet, but they should be familiar:
iszero consumes a number, and returns true if it is 0, false otherwise
the test expression of bif ("boolean if") must evaluate to true or false
ncons consumes a number and a numeric list, and produces a numeric list
2.18.1 Template
You must use the following template:
| (define-type Expr |
| [num (n number?)] |
| [id (v symbol?)] |
| [bool (b boolean?)] |
| [bin-num-op (op procedure?) (lhs Expr?) (rhs Expr?)] |
| [iszero (e Expr?)] |
| [bif (test Expr?) (then Expr?) (else Expr?)] |
| [with (bound-id symbol?) (bound-body Expr?) (body Expr?)] |
| [fun (arg-id symbol?) |
| (arg-type Type?) (result-type Type?) |
| (body Expr?)] |
| [app (fun-expr Expr?) (arg-expr Expr?)] |
| [nempty] |
| [ncons (first Expr?) (rest Expr?)] |
| [nfirst (e Expr?)] |
| [nrest (e Expr?)] |
| [isnempty (e Expr?)]) |
| (define-type Type |
| [t-num] |
| [t-bool] |
| [t-nlist] |
| [t-fun (arg Type?) (result Type?)]) |
| ; parse : s-expression -> Expr |
| (define (parse sexp) |
| (match sexp |
| [(list '+ lhs rhs) (bin-num-op + (parse lhs) (parse rhs))] |
| [(list '- lhs rhs) (bin-num-op - (parse lhs) (parse rhs))] |
| [(list '* lhs rhs) (bin-num-op * (parse lhs) (parse rhs))] |
| [(list 'iszero e) (iszero (parse e))] |
| [(list 'bif c t f) (bif (parse c) (parse t) (parse f))] |
| [(list 'with (list name named-expr) body) (with name (parse named-expr) (parse body))] |
| [(list 'fun (list arg-name ': arg-type) ': result-type body) |
| (fun arg-name (parse-type arg-type) (parse-type result-type) (parse body))] |
| [(list 'ncons f r) (ncons (parse f) (parse r))] |
| [(list 'nempty? l) (isnempty (parse l))] |
| [(list 'nfirst l) (nfirst (parse l))] |
| [(list 'nrest l) (nrest (parse l))] |
| [(list f a) (app (parse f) (parse a))] |
| [_ (case sexp |
| [(true) (bool true)] |
| [(false) (bool false)] |
| [(nempty) (nempty)] |
| [else (cond [(number? sexp) (num sexp)] |
| [(symbol? sexp) (id sexp)] |
| [else (error 'parse "illegal syntax: ~e" sexp)])])])) |
| ; parse-type : s-expression -> Type |
| (define (parse-type sexp) |
| (error 'parse-type "not implemented")) |
| ; type-of : Expr -> Type |
| (define (type-of e) |
| (error 'type-of "not implemented")) |
2.18.2 Type Judgments
Write down type judgments for the five numeric list constructs: nempty, ncons, nempty?, nfirst, and nrest. (These count as special test cases.)
You must submit this in a file named "judgments.pdf".
2.18.3 Required Functions
| (parse-type sexp) → Type? |
| sexp : s-expression? |
This consumes an s-expression and returns a Type. It is a helper function for parse.
You should thoroughly test parse-type to ensure that it parses all valid types. You may find match useful (as it is used in parse).
| (type-of e) → Type? |
| e : Expr? |
This consumes the abstract representation of a program (i.e. the result of parse). If the program has no type errors, type-of returns the type of the program. If the program has a type error, type-of should invoke error with an appropriate error message. For example:
(type-of (parse '{+ 1 2}))
should produce (t-num), while:
(type-of (parse '{3 4}))
should call error with some string, e.g. "Number is not a function".
You should thoroughly test type-of to ensure that every kind of expression can be typed in as many ways as is reasonable. Similarly, make sure type-of catches every kind of type error. In particular, you should make sure type-of does not catch run-time errors, such as (nfirst nempty).
Do not implement an evaluator, just a type checker.