EECS 321 Programming Languages: Homework 4

Part 1 – Functions that accept multiple arguments (with deferred substitutions)

Start with the F1WAE interpreter for deferred substitution, and extend the implementation to support any number of arguments to a function (including zero), and any number of arguments (including zero) in a function application:

  <FunDef> = {deffun {<id> <id>*} <FnWAE>}
  <FnWAE> = <number>
          | {+ <FnWAE> <FnWAE>}
          | {- <FnWAE> <FnWAE>}
          | {with {<id> <FnWAE>} <FnWAE>}
          | <id>
          | {<id> <FnWAE>*}

Since you must change the F1WAE datatype, and since different people may change it in different ways, you must provide a parse function. It must accept a quoted expression and produce an FnWAE value. For parsing, assume that any symbol other than '+, '-, or 'with can be a function name for a function call. Also, you must provide a parse-defn function that takes one (quoted) deffun form and produces a FunDef value.

At run-time, a new error is now possible: function application with the wrong number of arguments. Your interp-expr function should detect the mismatch and report an error that includes the words "wrong arity".

If a free variable is detected, your interpreter must report an error that includes the words "free variable".

If a use of an un-defined function is detected, your interpreter must report an error that includes the words "undefined function".

Some examples:

  (test (interp-expr (parse '{f 1 2})
                     (list (parse-defn '{deffun {f x y} {+ x y}})))
  (test (interp-expr (parse '{+ {f} {f}})
                     (list (parse-defn '{deffun {f} 5})))
  (test/exn (interp-expr (parse '{f 1})
                         (list (parse-defn '{deffun {f x y} {+ x y}})))
            "wrong arity")

Your interpreter must evaluate all of the argument expressions in an application expressions before signaling any arity errors. For example:

    (test/exn (interp-expr (parse '{f x})
                           (list (parse-defn '{deffun {f a b c} c})))
              "free variable")

Similarly, your interpreter must check to see if the function position of an application is legtimate before evaluating the arguments. For example:

    (test/exn (interp-expr (parse '{f x})
                           (list (parse-defn '{deffun {g a b c} c})))
              "undefined function")

A function would be ill-defined if two of its argument <id>s are the same. To prevent this problem, your parse-defn function should detect this problem and reports a "bad syntax" error. For example, (parse-defn '{deffun {f x x} x}) should report a "bad syntax" error, while (parse-defn '{deffun {f x y} x}) should produce a FunDef value.

If the list of definitions contains multiple definitions for the same function, use just the first one (ignoring the others).

Otherwise, assume that the input to your parser is a well-formed program.

Part 2 – Conditionals

Add if0, a conditional expression. It has three subexpressions:

  <FnWAE> = ...
          | {if0 FnWAE FnWAE FnWAE}

Evaluating an if0 expression evaluates the first subexpression; if it produces 0, then the result of the entire expression is the result of the second subexpression. Otherwise, the result is the result of the third subexpression.


  (test (interp-expr (parse '{if0 0 1 2}) '()) 1)
  (test (interp-expr (parse '{if0 1 2 3}) '()) 3)

Part 3 – Negative predicate

Implement, in the FnWAE language (without any extensions), a predicate neg? that determines if an integer is negative.

  {deffun {neg? x} ...}

It must return either 0 (if the input is negative), or 1 (if not).

Part 4 – Multiplication on integers

Implement, in the FnWAE language (without any extensions), a function mult that computes the product of two integers.

  {deffun {mult x y} ...}

Part N – Handin instructions

The final program you handin should:

Last update: Monday, January 23rd, 2017