RU beehive logo ITEC dept promo banner
ITEC 380
2011fall
ibarland

homelecturesexamshwsbreeze (snow day)

hw09
Interpreting N
project

Due Dec.09 (Fri) 23:59

Over the course of several homeworks, we'll implement a “tower” of languages (N0, N1, …, N6) each language incorporating more features than the previous. N0 is provided for you. You may write your interpreter in either in Java or in scheme (besides N1, which you must implement in both scheme and Java).


  1. (35 pts: This problem and the next are really the crux of the assignment.)
    Deferred evaluation: N5 doesn't add any new syntax, but it is a different evaluation model which will give us more expressive semantics. Use a new file/project for N5, separate from N0-N4. Turn in a full set of files on-line; for hardcopy only turn in parts of code that changed from your last turnin or posted solution (namely, eval and new test cases, but not parse or toString).

    There are two problems1 with the substitution approach used in N2-N4: we can't make recursive functions, and it doesn't generalize to assigning to variables. We solve these problems with deferred substitution:

    Your test cases should include a recursive function, as well as the example below. Also, since eval now takes an extra argument, that suggests three to four check-expects with various environments (lists of bindings):

    A step sideways: This algorithm as described lets us add recursive functions, but it also doesn't handle some expressions that N4 did! For example, let make-adder = func(m, func(n, (n plus m)) ) in <<make-adder(3)>4>; gives an error "unbound identifier: m" if no substitution has been done, however <func(m, <func(n, (n plus m))(3)>)(4)> does still work just fine(!). The problem will be fixed in N6: in the first example, <make-adder(3)> returns a function whose body involves m and n, but not the binding of m to 3. We'd need return the function and its bindings.

    Note that this gives us dynamic scoping (which we'll mention in class):

    let m = 100 
    in let addM = func(x, (x plus m))
       in  ((let m = 5 in <addM(3)>;)
            plus
            (let m = 4 in <addM(3)>;))
       ;
    ;
    
    evaluates to 15, not 206.

  2. (Extra credit: 30pts) N6: Implement static scope. Be sure to make a copy of your N5 project files before starting N6.
  3. Further extra-credit options (of varying difficulty):

1 A third issue, pointed out in Programming Languages and Interpretation, is that evaluating deeply nested lets is an O(n2) algorithm.      

2 Note that the list/map you recur with has the additional binding, but that recursive call shouldn't add/modify the list/map used at the top level. Since java.util.Map is inherently mutable, you'll want to make a new copy of that map before recurring.      

3 To update a field, in racket: if your struct is func-expr and it has a field named env, then racket provides a setter named “set-func-expr-env!”. You'll also have to use the keyword #:mutable when you define-struct that structure, to get that setter.      

4 You can think about which implementation you prefer, when using a language: when seeing the program's internal representation of your code (debugging, when debugging or seeing the compiled      

5 Be default, scheme structs are non-mutable; to make them mutable, you have to provide the keyword #:mutable to define-struct.      

homelecturesexamshwsbreeze (snow day)


©2011, Ian Barland, Radford University
Last modified 2011.Dec.07 (Wed)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme