CS 3520 Homework 4   - Due September 21

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

Exercise 4.1, Functions that Accept Multiple Arguments

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

  <FAE> = <number>
        | {+ <FAE> <FAE>}
        | {- <FAE> <FAE>}
        | <id>
        | {fun {<id>*} <FAE>}
        | {<FAE> <FAE>*}

Assume that each argument <id> is distinct for a fun expression.

At run-time, a new error is now possible: function application with the wrong number of arguments. As usual, we don't care how nicely this error is reported.

Since you must change the FAE 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 FAE value.

In addition, define interp-expr, which takes an expression, interprets it with an empty substitution, and produces either a number or 'function:

  (test (interp-expr (parse '{{fun {x y} {- y x}} 10 12}))
        2)
  (test (interp-expr (parse '{fun {} 12}))
        'function)
  (test (interp-expr (parse '{fun {x} {fun {} x}}))
        'function)
  (test (interp-expr (parse '{{{fun {x} {fun {} x}} 13}}))
        13)

Do not use require to import any libraries into your program, but that the PLAI Advanced language provides the following useful function:

The following list-of definition is useful for creating a predicate to match a list of a particular kind of value:

  (define (list-of p?)
    (lambda (x)
      (and (list? x)
           (andmap p? x))))

For example, ((list-of number?) '(1 2 3)) produces true, whereas ((list-of number?) 1) and ((list-of number?) '(a b c)) both produce false. Predicates created with list-of may be particularly useful when revising datatype definitions:

  (define-type Maze
    [dead-end]
    [room (doors (list-of Maze?))])

  (room (list (dead-end) (dead-end))) ; => (room (list (dead-end) (dead-end)))
  (room (dead-end)) ; => error: (dead-end) is not a list
  (room (list 1)) ; => error: 1 is not a Maze

Exercise 4.2, Records

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

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

Assume that each <id> is distinct in a rec expression.

Adding records means that the language now has three kinds of values: numbers, functions, and records. At run-time, errors may occur because a record is misused as a number or function, a number or function is supplied to get, or a record supplied to get does not have the named field. As usual, we don't care how nicely these error are reported.

Extend parse to support rec and get expressions, and extend interp-expr so that it produces either a number, 'function, or 'record:

  (test (interp-expr (parse '{rec {a 10} {b {+ 1 2}}}))
        'record)
  (test (interp-expr (parse '{get {rec {a 10} {b {+ 1 2}}} b}))
        3)
  (test (interp-expr (parse '{fun {r} {get r c}}))
        'function)
  (test (interp-expr (parse '{{fun {r} {get r c}} {rec {a 0} {c 12} {b 7}}}))
        12)
  (test (interp-expr (parse '{get {rec {r {rec {z 0}}}} r}))
        'record)
  (test (interp-expr (parse '{get {get {rec {r {rec {z 0}}}} r} z}))
        0)

Exercise 4.3, Extra Credit: Dynamic Bindings

This exercise is optional, for extra credit.

Extend your interpreter to support dynamic bindings (leaving all other bindings as lexical):

  <FAE> = ...
        | {dyn-with {<id> <FAE>} <FAE>}
        | {dyn <id>}

The namespace of dynamic bindings is seperate from the namespace of lexical bindings. That is, binding <id> using dyn-with does not affect direct references to <id>; it affects only references through dyn. Similarly, dyn does not access values bound using with.

  (test (interp-expr (parse '{dyn-with {x 2} {dyn x}}))
        2)
  (test (interp-expr (parse '{with {f {fun {y} {dyn x}}}
                               {dyn-with {x 2} 
                                 {f 0}}}))
        2)
  (test (interp-expr (parse '{dyn-with {x 0}
                               {with {f {fun {y} {+ {dyn x} y}}}
                                 {+ {f 1}
                                    {dyn-with {x 3}
                                      {f 2}}}}}))
        6)
  (test (interp-expr (parse '{dyn-with {x 2} {with {x 3} {dyn x}}}))
        2)
  (test (interp-expr (parse '{with {x 3} {dyn-with {x 2} x}}))
        3)

Hint: Having separate namespaces suggests having separate substitution caches.


Last update: Wednesday, November 23rd, 2005
mflatt@cs.utah.edu