- To extend the language a little, and to get you thinking about environments.

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

Add a simple conditional construct called

`if0`

. The concrete syntax for`if0`

is{if0 [FWAE] [FWAE] [FWAE]}

The first expression to

`if0`

should evaluate to a number. If that number is zero, return the value of the second expression (the "then" part); otherwise, return the value of the third expression (the "else" part). For example:{if0 {+ 5 -5} {- 8 2} 10}

would evaluate to (num 6).

Extend functions to take multiple arguments. For example, the following function definition (and naturally its application) should now be valid in the concrete syntax:

{fun {x y} {+ {* x x} {* y y}}}

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.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.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