#lang racket #| Homework thoughts for R1,2: - Follow the design recipe, as you add each new bit from the grammar. That is, we look at the 'add an IfZero to the grammar': ---- Per data type: 1. how to represent this new sort of Expr, inside our language? 2. examples of the data (you'll use them in test cases) 3. template -- adjust 'Expr's template to include this branch. ---- Per function: 4. test-cases for your existing functions expr->string, eval: add your IfZero options (from #2) 5. (well, remind yourself of the purpose-statement, and its signatures) 6. Inventory with values 7. Complete the body 8. run your (new) tests - some people aren't understanding that we're dealing with: representing parse trees. - You'll also want to update `parse!`, so that it deals with If0Exprs. - 'substitute' is not 'eval' |# #| THE LAW OF RACKET: Expresssions evaluate to values. In racket: An Expression is: - value examples: 7 "hello" 'green #t (lambda (x) (+ x 3)) semantics: Values evaluate to themselves. - identifier examples: pi + string-append x semantics: rule for eval: look up in previous `define`s, and eval to the right-hand-side (cached). (if wasn't previously `define`d, it's an error.) - function-application: examples: (+ 2 3) (string-append "hi" name) ((lambda (x) (+ x 3)) 7) syntax: ( ... ) semantics: Evaluate each of ...; let's call them v0...vN. (Btw: v0 had *better* be a function-value! -- else error) if v0 is a built-in function: apply the built-in to v1...vN. if v0 is a lambda: take the *body* of the lambda, substitute v1...vN for ... in that ; call the result E' (substitute only the *free* occurrences) return: eval(E') - special-forms: cond } and } they short-circuit. See file "macro-for-my-cond.rkt" if } let let* -- expands to nested `let`s lambda -- already mentioned up under 'values' cond: syntax: (cond [q a]... ) semantics: (cond [q a] others...) => if eval(q), then eval(a), else eval (cond others...) (cond) => #void (or, in student-levels, throws an exception) syntax: (or expr1 expr2 ... exprN) semantics: (or expr1 exprs...) => if eval(expr), then #t, else (eval (or exprs)) (or) => #f (cond) => false There are also a couple of *statements* (not expressions): define define-struct -- they have a side-effect, and they can't be used in places there 'any expression' fits, like the arguments to "+" -- you can't say (+ (define x 99) 3) ; syntax of `define`: (define [Id] [Expression]) ; semantics of `define`: a. evaluate the expression; b. remember that result as the "binding" for that Id. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; The bottom window of DrRacket is a "read-eval-print loop", or "repl": |# (define (loop _) (loop (print (eval (read)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; See also: file: "macro-for-my-cond.rkt" (define x (sqrt 100)) (+ x 7 x x) #| An example of lazy evaluation, and how wildly different it is: #lang lazy (define nats (cons 0 (map add1 nats))) (first nats) (first (rest nats)) (first (rest (rest nats))) (first (rest (rest (rest nats)))) |#