The language for this homework is:
#lang plait |
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.
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}}}}) |