CS 3520 Homework 3   - Due September 17

This homework is due September 17, 8:00 AM.

Exercise 3.1, Functions that Accept Multiple Arguments

Start with the F1WAE+DefrdSub interpreter, and extend the implementation to support multiple or zero arguments to a function, and multiple or zero arguments in a function call:

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

Since you must change the F1WAE datatype, and since different people may change it in different ways, you must provide a parse function this time, which accepts a quoted expression and produces an F1WAE 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 function should detect the mismatch and report an error that includes the words "wrong arity".

Some examples (see the second exercise about interp-expr):

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

A function would be ill-defined if two of its argument <id>s were 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.

For consistency with the second part of this assignment, this part of the assignment will be tested for handin using the interp-expr function, instead of interp.

Remember that the PLAI Advanced provides the following useful function:

Exercise 3.2, Records

Extend your interpreter to support the construction of records with named fields, and to support field selection from a record:

  <F1WAE> = ...
          | {rec {<id> <F1WAE>}*}
          | {get <F1WAE> <id>}

Your revised parse should check that each <id> is distinct in a rec expression.

Adding records means that the language now has two kinds of values: numbers and records. At run-time, an error may occur because a record is misused as a number, a number is supplied to get, or a record supplied to get does not have the named field. Your error message for the last case should include the words "no such field", otherwise you can make up your own error messages (or just let primitive error checking handle problems, such as trying to add a record to a number).

Extend parse to support rec and get expressions. Also, add an interp-expr function that is like interp, except that

  1. when the result is a record, it just reports 'record; and
  2. it does not take an initial DefrdSub argument, and instead starts with an empty substitution.

Examples:

  (test (interp-expr (parse '{rec {a 10} {b {+ 1 2}}})
                     empty)
        'record)
  (test (interp-expr (parse '{get {rec {a 10} {b {+ 1 2}}} b})
                     empty)
        3)
  (test/exn (lambda ()
              (interp-expr (parse '{get {rec {a 10}} b})
                           empty))
            "no such field")
  (test (interp-expr (parse '{g {rec {a 0} {c 12} {b 7}}})
                     (list (parse-defn '{deffun {g r} {get r c}})))
        12)
  (test (interp-expr (parse '{get {rec {r {rec {z 0}}}} r})
                     empty)
        'record)
  (test (interp-expr (parse '{get {get {rec {r {rec {z 0}}}} r} z})
                     empty)
        0)


Last update: Monday, October 15th, 2007
mflatt@cs.utah.edu