Homework must be submitted via D2L. All submitted files (3 for this assignment sol6A.hs, sol6B.txt, and sol6C.e6) must be submitted in the appropriate D2L directory in the drop box HW6. It is your responsibility to submit the homework in the proper format with the proper names. For example.
-- Homework 6 Tom Smith tom_smith@gmail.com
All programs mentioned can be downloaded from the this document
Consider a typed variant of our familiar simple language with imperative expressions, functions, and integers, characters, booleans, pairs, and lists. We'll call this language E6. It is very similar to language E3, except it is typed, and it supports booleans, characters and lists as primitive values. We do not encode booleans as integers or encode lists as right-nested pairs, as we did in E3. Instead there are primitive operations for each of these. It also include characters as we did in language E4. E6's concretized abstract syntax is given by the following grammar:
prog := '(' { fundef | globaldef } ')' exp fundef := '(' 'fun' fname typ '(' { var typ } ')' exp ')' globaldef := '(' 'global' vname exp ')' typ := 'Int' | 'Bool' | 'Char' | '(' typ '.' typ ')' | '[' typ ']' | letter exp := var | '(' ':=' var exp ')' | '(' 'write' exp ')' | '(' 'local' '(' { var exp } ')' exp ')' | '(' 'block' { exp } ')' | '(' '@' fname { exp } ')' | '(' 'while' exp exp ')' | True | False | '(' 'if' exp exp exp ')' | int | '(' '+' exp exp ')' | '(' '-' exp exp ')' | '(' '*' exp exp ')' | '(' '/' exp exp ')' | '(' '<=' exp exp ')' | char | '(' = exp exp ') | '(' 'pair' exp exp ')' | '(' 'fst' exp ')' | '(' 'snd' exp ')' | '(' 'cons' exp exp ')' | '(' 'head' exp ')' | '(' 'tail' exp ')' | 'nil' | '(' null exp ')' fname := letter { letter | digit } var := letter { letter | digit }
Note that there is now a new type of syntax to represent types (typ). Note that the expressions (exp) come arranged in groups organized around the type of values they manipulate.
The semantics of E6 expressions and functions are similar to those of previous homeworks. All scoping is static. The scope of each function name is the entire program, allowing two or more functions to be mutually recursive. The language obeys a type discipline, distinguishing integers, characters, booleans, lists, and pairs; every variable and expression must belong to a unique type. Each function parameter is explicitly typed, as is the function result.
For example, the code
(fun f Int (b Bool p (Int . Int)) (if b (+ (fst p) (snd p)) 0))
defines a function f with return type Int , and two parameters: b (whose type is Bool), and p (whose type is a Pair of Ints).
Local variables and globals do not have to be explicitly typed, as their types can always be infered from their initializing expressions.
It is a typing error to use an undefined function or variable name, or to define the same function name twice. If the same variable name appears twice in a parameter list or local declaration, the second appearance hides the first.
An E6 interpreter in Haskell (only) has been provided ( hw6.hs ). It reads a file containing an E6 program in the syntax described above, echoes the program (to confirm correct parsing), performs some typechecking on it, executes it (possibly producing output from write expressions), and displays the overall result, and then places the user in a read-typecheck-eval-print loop.
The typechecker catches some typing errors. For example, the program:
( (fun not Bool (y Bool) (if y False True)) (fun f Int (x Int) (+ 2 3)) ) (@not (@ f 4))
casues the following output
********** PARSING ****************** Program: ((fun not Bool (y Bool) (if y False True)) (fun f Int (x Int) (+ 2 3))) (@ not (@ f 4)) ********** Type Checking ************* not::(Bool-> Bool) f::(Int-> Int) ******** LOADING DEFS ************** not f ********** EXECUTING BODY ********** *** Exception: Non Bool as argument to if test: 5
The error is caused because f 's result type (i.e ., Int ) doesn't match the argument type of not (i.e., Bool ).
Use the existing code as a model. Your completed interpreter should be able to find all type errors in E6 programs. You may use typedlists.e6 as one test file. But I don't guarantee how much that file covers all the features of language E6. All the changes you need to make are between lines 375 and 485 of Hw6.hs. You need to remove the calls to notYet (sh term) and replace it with your own haskell code. There are 8 such calls. Hint. If there is an unimplemented case for an Exp, look what happens at similar cases.
If you've done it properly, the interpreter should never fail during evaluation with a checked runtime error of any kind.
Put your modified interpreter into a file called sol6A.hs and submit it.
********** PARSING ****************** Program: ((global n 7) (global b True) (global p (pair 5 True)) (global l (cons 3 (cons 4 (cons 9 nil)))) (global c 'a')) (+ n 1) ********** Type Checking ************* n::Int b::Bool p::(Int . Bool) l::[Int] c::Char ******** LOADING DEFS ************** n b p l c ********** EXECUTING BODY ********** 8 *********** ENTERING READ EVAL PRINT *************** type ':q' to exit, type 'trace' to flip tracer state enter Exp> (+ n True) user error ( *** Error, near "unknown location" (line 0, column 0) Int =/= Bool (Different type constuctors) Checking (+) While infering the type of True Expected type: Int Computed type: Bool) enter Exp>
Be sure your file has 10 tests, and that it exercises code you wrote!.
Hint: Write a helper function with two parameters, and use it to define rotate.