CS 536 (F03) Homework 3: Interpreters

Due: September 29 in class (hardcopy)


Assignment Goals


  1. Start with the FWAE (syntactic) interpreter with static scoping, eager evaluation, and cached substitution. Augment this interpreter in two ways:

  2. We remarked in class that the with and fun cases are remarkably similar. Indeed, we can express with expressions through fun and app. Specifically,

      {with {name named-expr} body}
    

    can be written as

      {{fun {name} body}
        named-expr}
    

    (Convince yourself that this transformation is valid--meaning that it preserves the behavior of with--in the substitution semantics.)

    This similarity also extends to with expressions that bind multiple variables. We could write

      {with {{x 3}
             {y 4}}
        {+ x y}}
    

    as the expression

      {{fun {x y} {+ x y}}
       3 4}
    

    Add support for multi-armed with to your parser, but instead of producing concrete syntax for with, have the parser rewrite with into function application as shown in the examples above. Once you make this change, you no longer need to support with in your interpreter in order to support it in your language.

  3. With the addition of if0, we can now write functions such as factorial in the syntax of our language:

    {with {fac {fun {n} 
                 {if0 n
                      1
                      {* n {fac {- n 1}}}}}}
      {fac 5}}
    

    Run this example through the interpreter you wrote for this assignment. Do you get the expected answer (since we know what factorial of 5 should evaluate to)? If not, explain why in terms of how the interpreter evaluates, how the environments work, or other technical terms. Don't edit your interpreter though! Simply answer this based on what the interpreter does do.

  4. When we first added the substitution cache (but before we added closures), we accidentally got an interpreter with dynamic scoping instead of static scoping. For the following example program (from class), it appeared that using a queue instead of a stack for the environment would have yielded the correct answer, without requiring us to introduce closures.

      {with {x 3}
        {with {f {fun {y} {+ x y}}}
          {with {x 5}
            {f 4}}}}
    

    Would a queue-based strategy for environments implement static scoping properly in the general case? Either justify that it would or provide a counterexample program and explain why the queue-based implementation would fail to yield static scoping for it.

    You do not need to implement an interpreter for this question. This is a paper and pencil exercise only.

Turn in the new parser and new interpreter, as well as a written (plain text fine) answer to questions 3 and 4.


Back to the Assignments page