5 Definitions
If we’ve been through the previous part, we can keep using the same file. Or we can use 2-lookup-in-environment.rkt as our starting point.
Passing an unchanging environment around is pretty cool. Maybe it would also be cool if the environment could also be extended with more stuff. Will try to.
We will use a “definition” to bind a name to a value, so that values can be referred to by their names. When we encounter a definition we will extend the environment with a new binding.
5.1 Some tests
You might want to copy them into the test module at the bottom of your Racket file. The tests are going to fail at first. By the end of this chapter they should pass.
(check-equal? (extend-environment (list (cons 'd 2) (cons 'e 1)) (list 'a 'b 'c) (list 5 4 3)) (list (cons 'a 5) (cons 'b 4) (cons 'c 3) (cons 'd 2) (cons 'e 1)))
(check-equal? (evaluate '(begin (define a 2) (define b 3) (+ a b))) 5)
(check-equal? (evaluate '(begin (define a 2) (define a 3) (+ a a))) 6)
5.2 define in Racket
Our defintions are going to work rather like the regular Racket ones. Try out the following lines of code in the REPL:
(define a 2)
a
(define b +)
(b a 3)
(begin (define a 3) (+ a 3))
5.3 extend-environment
We would like a helper-function for extending an environment with new bindings. We want to use this for definitions, and also for adding arguments to the environment when functions are called. Functions can have multiple parameters, so we will make extend-environment take a list of names and a list of values, in addition to the environment it should extend:
(define (extend-environment env names values) your code here)
(map cons (list 'a 'b 'c) (list 1 2 3))
When done, the test that uses extend-environment should pass.
5.4 eval-sequence and define
We make function:
(define (eval-sequence env terms) (match terms [(list exp) your code here] [(list (list 'define name exp) rest ...) your code here] [(list trm rest ...) your code here]))
In the first match-clause: The list only consist of only one element. The one element in a one-element list is its final element. The final term in a sequence is the expression we want to evaluate in order to get its result value. We can use eval-exp.
In the last match-clause: Since the middle clause did not match, trm is not a define-form. We will evaluate it with eval-exp, throw away its result, and use eval-sequence on the rest of the terms. (Yea so throwing away the results seems possibly wasteful. Maybe side effects though?)
In the middle match-clause: A define-form. This is more trickier. First we should evaluate the expression part of the defintion, and create a new environment with extend-environment. Then we can call eval-sequence on the rest of the list and the new environment.
5.5 begin
We use begin-forms to create expressions out of lists of terms. We add a new match-clause in eval-exp:
[(list 'begin terms ...) your code here]
And we will use eval-sequence to deal with the terms.