Homework #5: PLANG
Out: Friday, February 10th, Due: Friday, February 17th, 4:30pm

The language for this homework is:

#lang plait


Introduction

In this assignment you will extend the FLANG environment based interpreter to add optional dynamic typed identifiers, modelled on Racket’s parameter feature. Note that in this assignment (and the linked documentation) parameter is used in a technical sense distinct from the usual "identifier naming an argument to a function"

Begin by downloading the template file to serve as the basis of your work. The FLANG interpreter from the lectures has been extended to add abstract syntax Parameterize (with corresponding surface syntax param1), and abstract syntax Param (with a surface syntax that looks like a function call with no arguments). The provided surface syntax looks more like the parameter syntax from #lang racket, but there is also a parameterize and corresponding parameter-ref in plait. Our parameter implementation will be fully dynamically scoped, so make-parameter will not be needed, unlike #lang racket or #lang plait.


Add optional dynamic scope

Update the interp function (and other functions as needed) so that Parameterize and Param are evaluated. In particular ensure the following tests (which include 3 tests to verify the default lexical scope still works) pass.

;; With lexical scope, x is not rebound
(test (run `{let1 {x 3}
                  {let1 {f {lam y {+ x y}}}
                        {let1 {x 5}
                              {f 4}}}})    7)

;; with dynamically scoped parameters, x is rebound
(test (run `{param1 {x 3}
                  {let1 {f {lam y {+ {x} y}}}
                        {param1 {x 5}
                              {f 4}}}})    9)

;; lexical scope example 2 from lecture 7: binding of x is saved
(test (run `{{let1 {x 3}
                   {lam y {+ x y}}}
             4})    7)

;; same test but with parameters: binding of x is not saved.
(test/exn (run `{{param1 {x 3}
                         {lam y {+ {x} y}}}
                 4})    "binding")

;; lexical scope example 3 from lecture 7
(test (run `{{{lam x {x 1}}
              {lam x {lam y {+ x y}}}}
             123})
      124)

;; param1 works for functions, including shadowing
(test (run `{param1 {g {lam x x}}
                    {param1 {g {lam x {+ x 1}}}
                            {{g} 6}}})
      7)

;; param1 supports dynamic typing
(test (run `{param1 {x {lam y 3}}
                    {param1 {x 4}
                            {x}}})
      4)

;; nest param1 inside lam
(test (run `{let1 {f {lam x {param1 {y 3} {+ x {y}}}}}
                  {param1 {y 4} {f 3}}})
      6)

;; parameter references can be defined outside param1 scope.
(test (run `{let1 {f {lam x {y}}}
                  {param1 {y 42}
                          {f 0}}})
      42)

There are several possible implementation strategies. Probably the simplest is to maintain a completely separate environment for the parameters. You may use plait parameterize to implement PLANG parameters if you want, but I have not tested this solution. Do not use mutation (functions ending in !) in your solution. If you don’t use plait’s parameterize, you may want to add an extra argument to interp for the new environment. Whichever strategy you choose, be sure to document and test what you expect to happen if a parameter and a lexically scoped identifier (introduced by let1) have the same name. In particular decide what should result from evaluating the following:

(run `{let1 {x 1}
            {param1 {x 2}
                     {+ x {x}}}})


Finally

Make sure you have complete test coverage, and add any other needed tests. Define minutes-spent to estimate the time it took you to solve the assignment.