#lang racket #| ; Btw, that's all the racket I'll teach: ; - call a function ; - `define` for flat values ; - `cond` ; - `define-struct` ; - `lambda` ; - `let` ; ; Certainly racket has other things (a class-system, macros, a module system, ...) ; but we're not teaching racket; we're teaching a few fundamental concepts ; (and a language where we don't need to bring in extra concepts to just use the basics). ; ; Note that technically, `if` `and` `or` aren't functions ; (since they short-cut!); but I'll sweep that under the rug ; and pretend they're just library-functions and not separate syntax. ; The Law of Scheme (and, Racket): ; An Expr is: Examples Semantics: evals to... ; - a literal value, OR 14 #true "hi" (λ(a b) (- a b)) itself. ; - an identifier, OR pi howdy the value previously remembered from a `define` (or, error if that id not defined) ; - a cond, OR (cond [(even? 3) 6] [#true 19]) (cond) is error; (cond [exprQ exprA] QAPairs) is: if eval(exprQ) then eval(exprA), else eval((cond QAPairs)). ; - a let, OR (let {[a 3] [b (sqrt 4)]} (+ a b)) Eval each right-hand-side v1..vn; the answer is the body-expr after substituting v1..vn for id1..idn. ; - a function call (sqrt (+ 14 2)) For each arg-expression e0..en, eval to get v0..vn. ; v0 must be a func-val taking n args (else error). ; If the func-val is a primitive (.asm), call it; ; if a lambda w/ params id1..idn, then: ; take the lambda's body and substitute id{k} w/ v{k}, and evaluate *that* expression (meaning the body-after-substitutions). ; - a definition(*), OR (define n (+ 14 2)) eval r.h.s., and remember id/value pair (*) technically, a "definition" is not an expression -- I can't say `(+ 2 (define x 99))` ; Expr -> LitVal | Id | Defn | CondExpr | LetExpr | FuncCall ; LitVal -> NumericLiteral | StringLiteral | BooleanLiteral | RegexpLiteral | ImageLiteral | ...(detailed rules ommitted)... ; Id -> ...(a sequence of letters & digits that is not all digits)... ; Defn -> (define Id Expr) ; CondExpr -> (cond QAPairs) ; QAPairs -> ϵ | QAPair QAPairs ; QAPair -> [ Expr Expr ] ; FuncCall -> (Expr Exprs) ; semantics: eval all exprs to get values v0..vn ; v0 had better be a lambda-value accepting n arguments, else error! ; Call v0, passing the valus v1...vn. ; Exprs -> ϵ | Expr Exprs ; ; Let -> (let { Bindings } Expr) ; Bindings -> ... ; Binding -> [ Id Expr ] ; eval : expr -> value ; parse : string -> expr (eval (parse "(cond [(even? 3) 6] [#true 19])")) = (eval (parse "(cond [#true 19])")) = (eval (parse "19")) = 19 ; (eval an-expr) is: ; cond ; ...lambda, so that 'define' meets the above ; ...'let' as 'lambda'. (eval (parse '((lambda (x y z) (+ x (string-length (string-append y "hmm" z)))) (+ 2 3) "ibar" "land")') = (eval (parse '((lambda (x y z) (+ x (string-length (string-append y "hmm" z)))) 5 "ibar" "land")') = (eval (parse '(+ 5 (string-length (string-append "ibar" "hmm" "land")))') |#