Start with the interpreter that uses deferred substitution for this assignment (see the lecture notes).

Here is the grammar that your parser should accept:

FAE ::= {+ FAE FAE} | {- FAE FAE} | number | {with {ID FAE} FAE} | ID | {if0 FAE FAE FAE} | {fun {ID ID ...} FAE} | {FAE FAE FAE ...} ;; application expressionswhere an ellipsis means that the thing that directly precedes it can appear 0 or more times.

Add `with` to the parser for the FAE language, according to this rule:

{with {x FAE1} FAE2} | |

=> | {{fun {x} FAE2} FAE1} |

Add multiple argument functions to the parser for the FAE language, according to these rules:

{FAE1 FAE2 FAE3 FAE4 ...} | |

=> | {{FAE1 FAE2} FAE3 FAE4 ....} |

{fun {ID1 ID2 ID3 ...} FAE} | |

=> | {fun {ID1} {fun {ID2 ID3 ...} FAE}} |

{fun {a b} {+ a b}} | |

=> | {fun {a} {fun {b} {+ a b}}} |

{f x y z} => {{f x} y z} => {{{f x} y} z} | |

{fun {a b c} {- a {+ b c}}} | |

=> | {fun {a} {fun {b c} {- a {+ b c}}}} |

=> | {fun {a} {fun {b} {fun {c} {- a {+ b c}}}}} |

Nullary functions (i.e., functions with no arguments) and application expressions that supply no arguments are both syntax errors. Also note that these rules are intended to be schematic, not precise descriptions of how to implement your parser (but the examples form the basis of test cases for your parser; calling your parser on the before and after of the examples should produce the same results).

Your parser can assume that the inputs it is given are always well-formed. It doesn't have to give good (or any) error messages for programs that are syntax errors.

Add `if0` to your interpreter with the same syntax as homework 4 but, unlike homework 4, you must be careful that the test position can be any value at all, not just a number. If the test position is a procedure, it is treated the same as any other non-`0` value (i.e., it is not an error; it takes the false branch).

There are three different kinds of errors that can occur (at run-time) in this language and for each error in the input program, your interpreter must signal an error that includes one of the following phrases:

free identifier application expected procedure numeric operation expected number

Note that each operation in the language that evaluates its sub-expressions immediately must evaluate them from left to right and must evaluate all of them before checking any error conditions. For example:

(test/exn (interp-expr (parse `{+ {fun {x} x} {1 2}})) "application expected procedure")is a valid test case: the application error must be signaled first even though the add expression also gets incorrect inputs.

It is possible to represent numbers using functions. One way to do this is to represent

0 as | {fun {f} {fun {x} x}} |

1 as | {fun {f} {fun {x} {f x}}} |

2 as | {fun {f} {fun {x} {f {f x}}}} |

3 as | {fun {f} {fun {x} {f {f {f x}}}}}, |

Write an FAE function that converts a natural number in the above representation into a number in the normal representation called `f-to-n` and write a FAE program that converts back, called `n-to-f`. The `n-to-f` function does not have to be well-defined if it gets a negative number (or a rational or complex, etc); that is, you can assume it is called only with natural numbers.

For example,

{with {n-to-f ...} {with {f-to-n ...} {f-to-n {n-to-f 4}}}} => 4

Write the FAE functions `plus` and `times` that accept two numbers in the above representation and add/multiply them together. Neither of these FAE functions can (indirectly or directly) use FAE's `+` or `-` operations (i.e., you cannot use `f-to-n` from part 4, add the numbers, and then call `n-to-f`).

For example,

{with {n-to-f ...} {with {f-to-n ...} {with {plus ...} {with {times ...} {f-to-n {plus {n-to-f 2} {n-to-f 3}}}}}}} => 5Similarly, with the appropriate

{f-to-n {plus {n-to-f 0} {n-to-f 0}}} => 0 {f-to-n {plus {n-to-f 2} {n-to-f 0}}} => 2 {f-to-n {plus {n-to-f 0} {n-to-f 2}}} => 2 {f-to-n {times {n-to-f 1} {n-to-f 0}}} => 0 {f-to-n {times {n-to-f 0} {n-to-f 1}}} => 0 {f-to-n {times {n-to-f 3} {n-to-f 4}}} => 12

The final program you hand in should use this precise `define-type` definition for `FAE`.

(define-type FAE [num (n number?)] [add (lhs FAE?) (rhs FAE?)] [sub (lhs FAE?) (rhs FAE?)] [id (name symbol?)] [if0 (test FAE?) (then FAE?) (else FAE?)] [fun (param symbol?) (body FAE?)] [app (fun FAE?) (arg FAE?)])

Provide a definition of `interp-expr : FAE -> number or 'procedure`, as above. Note that `interp-expr` is a wrapper function around your main, recursive interpreter. It translates whatever you decide to use for your representation of values into either a number, or the symbol `'procedure`. For example, these test cases should pass:

(test (interp-expr (num 10)) 10) (test (interp-expr (fun 'x (id 'x))) 'procedure)

Provide a definition of `parse : sexpression -> FAE`, as above.

Bind your definitions of `n-to-f`, `f-to-n`, `plus`, and `times` to PLAI-level definitions of the same name, e.g.,

(define n-to-f `{fun {n} ...}) (define f-to-n `{fun {f} ...}) (define plus `{fun {f1 f2} ...}) (define times `{fun {f1 f2} ...})Note that these should each be complete FAE programs; if you wish, use quasiquote and unquote (see the parsing lecture notes for more on quasiquote and unquote) to avoid duplicating code.

Last update: Thursday, February 2nd, 2017stamourv@eecs.northwestern.edu |