So i got this code:
#lang pl
#| BNF for the AE language:
<AE> ::= <num>
| { + <AE> <AE> }
| { - <AE> <AE> }
| { * <AE> <AE> }
| { / <AE> <AE> }
|#
;; AE abstract syntax trees
(define-type AE
[Num Number]
[Add AE AE]
[Sub AE AE]
[Mul AE AE]
[Div AE AE])
(: parse-sexpr : Sexpr -> AE)
;; to convert s-expressions into AEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(list '+ lhs rhs)
(Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '- lhs rhs)
(Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '* lhs rhs)
(Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '/ lhs rhs)
(Div (parse-sexpr lhs) (parse-sexpr rhs))]
[else
(error 'parse-sexpr "bad syntax in ~s" sexpr)]))
(: parse : String -> AE)
;; parses a string containing an AE expression to an AE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
(: eval : AE -> Number)
;; consumes an AE and computes the corresponding number
(define (eval expr)
(cases expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]
[(Sub l r) (- (eval l) (eval r))]
[(Mul l r) (* (eval l) (eval r))]
[(Div l r) (/ (eval l) (eval r))]))
(: run : String -> Number)
;; evaluate an AE program contained in a string
(define (run str)
(eval (parse str)))
you can test and run is with run (+ 3 5) and the you will get 8.
my mission is to change the code so i can do run (3 + 5)
so i change the parse-sexpr function who build the tree it self to:
(: parse-sexpr : Sexpr -> AE)
;; to convert s-expressions into AEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(list lhs '+ rhs)
(Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '- rhs)
(Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '* rhs)
(Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list lhs '/ rhs)
(Div (parse-sexpr lhs) (parse-sexpr rhs))]
[else
(error 'parse-sexpr "bad syntax in ~s" sexpr)]))
I can still compile the code, but if i will do run (+ 5 3) i will get 8 and if i try to run (5 + 3) i'm getting:
Type Checker: Cannot apply expression of type Positive-Byte, since
it is not a function type in: (5 + 3)
why doe's this happend?
This is an issue of what is an expression in typed racket, vs. what is an expression in your language. In your language, (5 + 3) is an expression, but in typed racket, it's a type error. So you need to represent (5 + 3) as data in typed racket.
One common way to do this, as #soegaard pointed out, is to put a quote in front of it, like this: '(5 + 3). Though I hate writing it like that. What it really is, is (list 5 '+ 3). So you can pass it to your new parse-sexpr function to get
> (parse-sexpr (list 5 '+ 3))
- : AE
(Add (Num 5) (Num 3))
Then you can pass that value to your eval function to get
> (eval (Add (Num 5) (Num 3)))
- : Number
8
Composed together:
> (eval (parse-sexpr (list 5 '+ 3)))
- : Number
8
But your run function takes a string, passes it to string->sexpr then passes that to parse-sexpr and then your eval function. So what you probably meant to do all along was this:
> (eval (parse-sexpr (string->sexpr "{5 + 3}")))
- : Number
8
> (run "{5 + 3}")
- : Number
8
Assuming that string->sexpr takes expressions with curly braces like that. What you were doing was (run (5 + 3)), which treats (5 + 3) as a typed racket expression. What you wanted was (run "{5 + 3}"), which treats (5 + 3) as an expression in your language, which is represented as data in typed racket.
Did you by chance write
(run (+ 5 3))
instead of
(run '(+ 5 3))
?
If you write (run (+ 5 3)) then Racket will compute (+ 5 3) first, and then call (run 8). If you write (run (5 + 3)) then Racket will attempt to evaluate (5 + 3) and that gives the error you see: the number 5 is not a function type, so it can not be used as in (5 ...).
Related
How can I use typed Racket for some functions in my codebase, but use (untyped) Racket for others? When I define a function in Racket but import it into a typed Racket context, it seems to be changing the behavior of the function (functions described below).
As it is now, the files do typecheck, but don't pass my tests in p11typedtest.rkt -- however, my files do successfully pass my tests if I either (A) switch p11typed.rkt to regular Racket or (B) copy the pack function into p11typed.rkt and provide its type annotation.
;; p09.rkt
#lang racket
(provide pack)
;; packs consecutive duplicates within a list into sublists
(define (pack lst)
(for/foldr ([acc '()]) ([x lst])
(match acc
[(cons (cons y ys) zs) #:when (equal? x y)
(list* (list* x y ys) zs)]
[_ (list* (list x) acc)]
)))
;; p11typed.rkt
#lang typed/racket
(provide encode-runlen-mod)
;; (require (only-in (file "p09.rkt") pack))
(require/typed (only-in (file "p09.rkt") pack)
[pack (All (A) (-> (Listof A) (Listof (Listof A))))]
)
(define-type (Runof a) (List Index a))
(define-type (RunListof a) (Listof (U a (Runof a))))
;; encodes a list as a list of runs
(: encode-runlen-mod (All (A) (-> (Listof A) (RunListof A))))
(define (encode-runlen-mod lst)
;; uncomment to print the result of pack
;; (displayln (pack lst))
(for/list ([dups (pack lst)])
(match (length dups)
[1 (car dups)]
[n (list n (car dups))]
)))
; (: pack (All (A) (-> (Listof A) (Listof (Listof A)))))
; (define (pack lst)
; (for/foldr ([acc '()]) ([x lst])
; (match acc
; [(cons (cons y ys) zs) #:when (equal? x y)
; (list* (list* x y ys) zs)]
; [_ (list* (list x) acc)]
; )))
;; p11typedtest.rkt
#lang racket
(require (only-in (file "p11typed.rkt") encode-runlen-mod))
(define (test-output namespace expr v)
(let* ([val (eval expr namespace)]
[fail (not (equal? val v))])
(begin
(display (if fail "FAIL" "ok "))
(display " '(=? ")
(print expr)
(display " ")
(print v)
(display ")'")
(if fail
(begin
(display ", got ")
(print val)
(displayln " instead")
)
(displayln "")
)
(void))
))
(define-namespace-anchor a)
(define ns (namespace-anchor->namespace a))
(test-output ns '(encode-runlen-mod '(1 2 3 4)) '(1 2 3 4))
(test-output ns '(encode-runlen-mod '(1 1 1)) '((3 1)))
(test-output ns '(encode-runlen-mod '(1 2 2 3 4)) '(1 (2 2) 3 4))
(test-output ns '(encode-runlen-mod '(1 2 3 4 4 4)) '(1 2 3 (3 4)))
(test-output ns '(encode-runlen-mod '(1 2 3 (3 4))) '(1 2 3 (3 4)))
(test-output ns '(encode-runlen-mod '(A A A A B C C A A D E E))
'((4 A) B (2 C) (2 A) D (2 E)))
)
my assignment is to add new function called sqrt+ to my racket language.
the sqrt+ function return list with the root of the number and the negtive root of him.
The way to call to the sqrt+ function i by Sqrt syntax:
#lang pl 03
#| BNF for the MUWAE language:
<MUWAE> ::= <num>
| { + <MUWAE> <MUWAE> }
| { - <MUWAE> <MUWAE> }
| { * <MUWAE> <MUWAE> }
| { / <MUWAE> <MUWAE> }
| { Sqrt <MUWAE> }
| { with { <id> <WAE> } <MUWAE> }
| <id>
|#
;; MUWAE abstract syntax trees
(define-type MUWAE
[Num Number]
[Add MUWAE MUWAE]
[Sub MUWAE MUWAE]
[Mul MUWAE MUWAE]
[Div MUWAE MUWAE]
[Sqrt MUWAEE]
[Id Symbol]
[With Symbol MUWAE MUWAE])
(: parse-sexpr : Sexpr -> MUWAE)
;; to convert s-expressions into MUWAEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(symbol: name) (Id name)]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
(With name (parse-sexpr named) (parse-sexpr body))]
[else (error 'parse-sexpr "bad `with' syntax in ~s" sexpr)])]
[(list '+ lhs rhs) (Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '- lhs rhs) (Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '* lhs rhs) (Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '/ lhs rhs) (Div (parse-sexpr lhs) (parse-sexpr rhs))]
[(list 'Sqrt s) (sqrt+ (parse-sexpr s))]
[else (error 'parse-sexpr "bad syntax in ~s" sexpr)]))
(: parse : String -> MUWAE)
;; parses a string containing a MUWAE expression to a MUWAE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
#| Formal specs for `subst':
(`N' is a <num>, `E1', `E2' are <MUWAE>s, `x' is some <id>,
`y' is a *different* <id>)
N[v/x] = N
{+ E1 E2}[v/x] = {+ E1[v/x] E2[v/x]}
{- E1 E2}[v/x] = {- E1[v/x] E2[v/x]}
{* E1 E2}[v/x] = {* E1[v/x] E2[v/x]}
{/ E1 E2}[v/x] = {/ E1[v/x] E2[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]}
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
|#
(: subst : MUWAE Symbol MUWAE -> MUWAE)
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define (subst expr from to)
(cases expr
[(Num n) expr]
[(Add l r) (Add (subst l from to) (subst r from to))]
[(Sub l r) (Sub (subst l from to) (subst r from to))]
[(Mul l r) (Mul (subst l from to) (subst r from to))]
[(Div l r) (Div (subst l from to) (subst r from to))]
[(Sqrt s) (sqrt+ (subst s from to))]
[(Id name) (if (eq? name from) to expr)]
[(With bound-id named-expr bound-body)
(With bound-id
(subst named-expr from to)
(if (eq? bound-id from)
bound-body
(subst bound-body from to)))]))
#| Formal specs for `eval':
eval(N) = N
eval({+ E1 E2}) = eval(E1) + eval(E2)
eval({- E1 E2}) = eval(E1) - eval(E2)
eval({* E1 E2}) = eval(E1) * eval(E2)
eval({/ E1 E2}) = eval(E1) / eval(E2)
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
|#
(: eval : MUWAE -> Number)
;; evaluates MUWAE expressions by reducing them to numbers
(define (eval expr)
(cases expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]
[(Sub l r) (- (eval l) (eval r))]
[(Mul l r) (* (eval l) (eval r))]
[(Div l r) (/ (eval l) (eval r))]
[(Sqrt s) (sqrt+ (eval s))]
[(With bound-id named-expr bound-body)
(eval (subst bound-body
bound-id
(Num (eval named-expr))))]
[(Id name) (error 'eval "free identifier: ~s" name)]))
(: run : String -> Number)
;; evaluate a MUWAE program contained in a string
(define (run str)
(eval (parse str)))
(: sqrt+ : (Listof Number) -> (Listof Number))
;; a version of `sqrt' that takes a list of numbers, and return a list
;; with twice the elements, holding the two roots of each of the inputs;
;; throws an error if any input is negative.
(define (sqrt+ ns)
(cond [(null? ns) 0]
[(< (first ns) 0) (error 'ns "`sqrt' requires a nonnegative input ~s")]
[else (sqrt ns (* (sqrt ns) -1))]))
but when i try to run the language i get:
cases: missing cases for the following variants: (Sqrt ...)
What did i miss and needed to make change?
Without trying your program:
[(Sqrt s) (sqrt+ (subst s from to))]
in the subst function seems to be incorrect. subst is supposed to return a MUWAE. However, the returning type of sqrt+ is a list of numbers.
Also,
[(Sqrt s) (sqrt+ (eval s))]
in the eval function seems to be incorrect because again, eval is supposed to return a number. However, the returning type of sqrt+ is a list of numbers. Similarly, the type of (eval s) is supposed to be a number, but sqrt+ consumes a list of numbers.
Lastly, I also believe that your implementation of sqrt+ is also wrong. In particular, it doesn't make sense to write [else (sqrt ns (* (sqrt ns) -1))] because sqrt consumes a number...
I'm trying to add sqrt function to my proffesor language in racket, here is the language:
;; ** The MUWAE interpreter
#lang pl 03
#| BNF for the MUWAE language:
<MUWAE> ::= <num>
| { + <MUWAE> <MUWAE> }
| { - <MUWAE> <MUWAE> }
| { * <MUWAE> <MUWAE> }
| { / <MUWAE> <MUWAE> }
| { sqrt <MUWAE> }
| { with { <id> <WAE> } <MUWAE> }
| <id>
|#
;; MUWAE abstract syntax trees
(define-type MUWAE
[Num Number]
[Add MUWAE MUWAE]
[Sub MUWAE MUWAE]
[Mul MUWAE MUWAE]
[Div MUWAE MUWAE]
[sqrt MUWAEE]
[Id Symbol]
[With Symbol MUWAE MUWAE])
(: parse-sexpr : Sexpr -> MUWAE)
;; to convert s-expressions into MUWAEs
(define (parse-sexpr sexpr)
(match sexpr
[(number: n) (Num n)]
[(symbol: name) (Id name)]
[(cons 'with more)
(match sexpr
[(list 'with (list (symbol: name) named) body)
(With name (parse-sexpr named) (parse-sexpr body))]
[else (error 'parse-sexpr "bad `with' syntax in ~s" sexpr)])]
[(list '+ lhs rhs) (Add (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '- lhs rhs) (Sub (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '* lhs rhs) (Mul (parse-sexpr lhs) (parse-sexpr rhs))]
[(list '/ lhs rhs) (Div (parse-sexpr lhs) (parse-sexpr rhs))]
[(list 'sqrt s) (sqrt (parse-sexpr s))]
[else (error 'parse-sexpr "bad syntax in ~s" sexpr)]))
(: parse : String -> MUWAE)
;; parses a string containing a MUWAE expression to a MUWAE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
#| Formal specs for `subst':
(`N' is a <num>, `E1', `E2' are <MUWAE>s, `x' is some <id>,
`y' is a *different* <id>)
N[v/x] = N
{+ E1 E2}[v/x] = {+ E1[v/x] E2[v/x]}
{- E1 E2}[v/x] = {- E1[v/x] E2[v/x]}
{* E1 E2}[v/x] = {* E1[v/x] E2[v/x]}
{/ E1 E2}[v/x] = {/ E1[v/x] E2[v/x]}
y[v/x] = y
x[v/x] = v
{with {y E1} E2}[v/x] = {with {y E1[v/x]} E2[v/x]}
{with {x E1} E2}[v/x] = {with {x E1[v/x]} E2}
|#
(: subst : MUWAE Symbol MUWAE -> MUWAE)
;; substitutes the second argument with the third argument in the
;; first argument, as per the rules of substitution; the resulting
;; expression contains no free instances of the second argument
(define (subst expr from to)
(cases expr
[(Num n) expr]
[(Add l r) (Add (subst l from to) (subst r from to))]
[(Sub l r) (Sub (subst l from to) (subst r from to))]
[(Mul l r) (Mul (subst l from to) (subst r from to))]
[(Div l r) (Div (subst l from to) (subst r from to))]
[(sqrt s) (sqrt (subst l from to))]
[(Id name) (if (eq? name from) to expr)]
[(With bound-id named-expr bound-body)
(With bound-id
(subst named-expr from to)
(if (eq? bound-id from)
bound-body
(subst bound-body from to)))]))
#| Formal specs for `eval':
eval(N) = N
eval({+ E1 E2}) = eval(E1) + eval(E2)
eval({- E1 E2}) = eval(E1) - eval(E2)
eval({* E1 E2}) = eval(E1) * eval(E2)
eval({/ E1 E2}) = eval(E1) / eval(E2)
eval(id) = error!
eval({with {x E1} E2}) = eval(E2[eval(E1)/x])
|#
(: eval : MUWAE -> Number)
;; evaluates MUWAE expressions by reducing them to numbers
(define (eval expr)
(cases expr
[(Num n) n]
[(Add l r) (+ (eval l) (eval r))]
[(Sub l r) (- (eval l) (eval r))]
[(Mul l r) (* (eval l) (eval r))]
[(Div l r) (/ (eval l) (eval r))]
[(sqrt s) (sqet (eval s))]
[(With bound-id named-expr bound-body)
(eval (subst bound-body
bound-id
(Num (eval named-expr))))]
[(Id name) (error 'eval "free identifier: ~s" name)]))
(: run : String -> Number)
;; evaluate a MUWAE program contained in a string
(define (run str)
(eval (parse str)))
But when i try to run my code i get:
define-type: variant name is already bound in: sqrt
I added the sqrt function in my bnf stracture and added in all the eval, subst and sexper, but i have problem i guess in the stracture.
i guess that sqrt is a save word and in need to override the word, this is the way to do it so? there is another way?
what does error means?
Without trying your program:
The problem is that the language #lang pl 03 has a sqrt operator already.
The name is therefore already used; and when you try to give another meaning you get the error "variant name is already bound in: sqrt".
I think the simplest fix is to call your square root operator for Sqrt instead.
I am studying PLAI's Chapter8 "Implementing Laziness", and finished the following CFAE/L:
(define-type CFAE/L
[num (n number?)]
[add (lhs CFAE/L?)(rhs CFAE/L?)]
[id (name symbol?)]
[fun (param symbol?)(body CFAE/L?)]
[app (fun-expr CFAE/L?)(arg-expr CFAE/L?)])
(define-type CFAE/L-Value
[numV (n number?)]
[closureV (param symbol?)
(body CFAE/L?)
(env Env?)]
[exprV (expr CFAE/L?)
(env Env?)])
(define-type Env
[mtSub]
[aSub (name symbol?)(value CFAE/L-Value?)(env Env?)])
(define (num+ x y) ;; need this because we can't just use Scheme + to add FAE-values
(numV (+ (numV-n x) (numV-n y))))
(define (parse sexp)
(cond [(number? sexp) (num sexp)]
[(symbol? sexp) (id sexp)]
[(list? sexp)
(case (first sexp)
((+)
(add (parse (second sexp))
(parse (third sexp))))
((with)
(app (fun (first (second sexp))
(parse (third sexp)))
(parse (second (second sexp)))))
((fun)
(fun (first (second sexp))
(parse (third sexp))))
(else
(app (parse (first sexp))
(parse (second sexp)))))]))
(define (lookup name env)
(type-case Env env
[mtSub() (error 'lookup "no binding for identifier")]
[aSub (bound-name bound-value rest-ds)
(if (symbol=? bound-name name)
bound-value
(lookup name rest-ds))]))
(define (interp expr env)
(type-case CFAE/L expr
[num (n) (numV n)]
[add (l r)(num+ (interp l env)(interp r env))]
[id (v) (lookup v env)]
[fun (bound-id bound-body)
(closureV bound-id bound-body env)]
[app (fun-expr arg-expr)
(local ([define fun-val (interp fun-expr env)]
[define arg-val (exprV arg-expr env)])
(interp (closureV-body fun-val)
(aSub (closureV-param fun-val)
arg-val
(closureV-env fun-val))))]))
According to this interpreter, I want to evaluate the page76's
{with {x 3} {+ x x}}
(1) when typing:
(interp (parse '{with {x 3} {+ x x}}) {mtSub})
I got errors as below:
numV-n: contract violation, expected: numV?, given: (exprV (num 3) (mtSub))
contract from: numV-n, blaming: use
contract: (-> numV? number?)
at: /study/lisp/plai/chapter8.scm:10.9
(2) I wanted to write down the steps by hand for understanding page76's description as below:
"The interpreter evaluates each x in the body to an expression closure (because that’s what is bound to x in the environment), but the addition procedure cannot handle these: it (and similarly any other arithmetic primitive) needs to know exactly which number the expression closure corresponds to.", but I am still not clear about this description after finishing the steps. there are my steps : (interp (parse '(with (x 3) (+ x x))) (mtSub))
step1: (parse '(with (x 3) (+ x x))) => (app (fun 'x (add (id 'x) (id 'x))) (num 3))
NOTE: fun-exp is (fun 'x (add (id 'x), arg-expr is (num 3)
step2: (cloSureV 'x (add (id 'x) (id 'x)) (mtSub)) (as fun-val)
and (experV (num 3) (mtSub)) (as arg-val)
step3: (interp (add (id 'x) (id 'x)) (aSub 'x (num 3) (mtSub)))
Thanks in advance!
Ad 1)
This is the expected behaviour. The error message you got was:
numV-n: contract violation,
expected: numV?,
given: (exprV (num 3) (mtSub))
...
This numV-n was the one in num+. This es explained in the last
paragraph of page 75. The primitives such as num+ expected non-closure
values, but the value (exprV (num 3) (mtSub)) is the number 3 closed
over the empty environment.
Therefore the primitives such as num+ must force the arguments.
From page 76:
(define (num+ n1 n2)
(numV (+ (numV-n (strict n1) ) (numV-n (strict n2) ))))
Ad 2)
Do the explanation of 1) help with 2) ?
ADDED
Why not let the interpreter write out the steps for you?
The quick fix:
(define (interp expr env)
(displayln (list 'expr expr 'env env))
(type-case CFAE/L expr
To get more readable output, first write unparse that converts
a CFAE/L to a (readable) string.
I have found the code from this lesson online (http://groups.csail.mit.edu/mac/ftpdir/6.001-fall91/ps4/matcher-from-lecture.scm), and I am having a heck of a time trying to debug it. The code looks pretty comparable to what Sussman has written:
;;; Scheme code from the Pattern Matcher lecture
;; Pattern Matching and Simplification
(define (match pattern expression dictionary)
(cond ((eq? dictionary 'failed) 'failed)
((atom? pattern)
(if (atom? expression)
(if (eq? pattern expression)
dictionary
'failed)
'failed))
((arbitrary-constant? pattern)
(if (constant? expression)
(extend-dictionary pattern expression dictionary)
'failed))
((arbitrary-variable? pattern)
(if (variable? expression)
(extend-dictionary pattern expression dictionary)
'failed))
((arbitrary-expression? pattern)
(extend-dictionary pattern expression dictionary))
((atom? expression) 'failed)
(else
(match (cdr pattern)
(cdr expression)
(match (car pattern)
(car expression)
dictionary)))))
(define (instantiate skeleton dictionary)
(cond ((atom? skeleton) skeleton)
((skeleton-evaluation? skeleton)
(evaluate (evaluation-expression skeleton)
dictionary))
(else (cons (instantiate (car skeleton) dictionary)
(instantiate (cdr skeleton) dictionary)))))
(define (simplifier the-rules)
(define (simplify-exp exp)
(try-rules (if (compound? exp)
(simplify-parts exp)
exp)))
(define (simplify-parts exp)
(if (null? exp)
'()
(cons (simplify-exp (car exp))
(simplify-parts (cdr exp)))))
(define (try-rules exp)
(define (scan rules)
(if (null? rules)
exp
(let ((dictionary (match (pattern (car rules))
exp
(make-empty-dictionary))))
(if (eq? dictionary 'failed)
(scan (cdr rules))
(simplify-exp (instantiate (skeleton (car rules))
dictionary))))))
(scan the-rules))
simplify-exp)
;; Dictionaries
(define (make-empty-dictionary) '())
(define (extend-dictionary pat dat dictionary)
(let ((vname (variable-name pat)))
(let ((v (assq vname dictionary)))
(cond ((null? v)
(cons (list vname dat) dictionary))
((eq? (cadr v) dat) dictionary)
(else 'failed)))))
(define (lookup var dictionary)
(let ((v (assq var dictionary)))
(if (null? v)
var
(cadr v))))
;; Expressions
(define (compound? exp) (pair? exp))
(define (constant? exp) (number? exp))
(define (variable? exp) (atom? exp))
;; Rules
(define (pattern rule) (car rule))
(define (skeleton rule) (cadr rule))
;; Patterns
(define (arbitrary-constant? pattern)
(if (pair? pattern) (eq? (car pattern) '?c) false))
(define (arbitrary-expression? pattern)
(if (pair? pattern) (eq? (car pattern) '? ) false))
(define (arbitrary-variable? pattern)
(if (pair? pattern) (eq? (car pattern) '?v) false))
(define (variable-name pattern) (cadr pattern))
;; Skeletons & Evaluations
(define (skeleton-evaluation? skeleton)
(if (pair? skeleton) (eq? (car skeleton) ':) false))
(define (evaluation-expression evaluation) (cadr evaluation))
;; Evaluate (dangerous magic)
(define (evaluate form dictionary)
(if (atom? form)
(lookup form dictionary)
(apply (eval (lookup (car form) dictionary)
user-initial-environment)
(mapcar (lambda (v) (lookup v dictionary))
(cdr form)))))
;;
;; A couple sample rule databases...
;;
;; Algebraic simplification
(define algebra-rules
'(
( ((? op) (?c c1) (?c c2)) (: (op c1 c2)) )
( ((? op) (? e ) (?c c )) ((: op) (: c) (: e)) )
( (+ 0 (? e)) (: e) )
( (* 1 (? e)) (: e) )
( (* 0 (? e)) 0 )
( (* (?c c1) (* (?c c2) (? e ))) (* (: (* c1 c2)) (: e)) )
( (* (? e1) (* (?c c ) (? e2))) (* (: c ) (* (: e1) (: e2))) )
( (* (* (? e1) (? e2)) (? e3)) (* (: e1) (* (: e2) (: e3))) )
( (+ (?c c1) (+ (?c c2) (? e ))) (+ (: (+ c1 c2)) (: e)) )
( (+ (? e1) (+ (?c c ) (? e2))) (+ (: c ) (+ (: e1) (: e2))) )
( (+ (+ (? e1) (? e2)) (? e3)) (+ (: e1) (+ (: e2) (: e3))) )
( (+ (* (?c c1) (? e)) (* (?c c2) (? e))) (* (: (+ c1 c2)) (: e)) )
( (* (? e1) (+ (? e2) (? e3))) (+ (* (: e1) (: e2))
(* (: e1) (: e3))) )
))
(define algsimp (simplifier algebra-rules))
;; Symbolic Differentiation
(define deriv-rules
'(
( (dd (?c c) (? v)) 0 )
( (dd (?v v) (? v)) 1 )
( (dd (?v u) (? v)) 0 )
( (dd (+ (? x1) (? x2)) (? v)) (+ (dd (: x1) (: v))
(dd (: x2) (: v))) )
( (dd (* (? x1) (? x2)) (? v)) (+ (* (: x1) (dd (: x2) (: v)))
(* (dd (: x1) (: v)) (: x2))) )
( (dd (** (? x) (?c n)) (? v)) (* (* (: n) (+ (: x) (: (- n 1))))
(dd (: x) (: v))) )
))
(define dsimp (simplifier deriv-rules))
(define scheme-rules
'(( (square (?c n)) (: (* n n)) )
( (fact 0) 1 )
( (fact (?c n)) (* (: n) (fact (: (- n 1)))) )
( (fib 0) 0 )
( (fib 1) 1 )
( (fib (?c n)) (+ (fib (: (- n 1)))
(fib (: (- n 2)))) )
( ((? op) (?c e1) (?c e2)) (: (op e1 e2)) ) ))
(define scheme-evaluator (simplifier scheme-rules))
I'm running it in DrRacket with the R5RS, and the first problem I ran into was that atom? was an undefined identifier. So, I found that I could add the following:
(define (atom? x) ; atom? is not in a pair or null (empty)
(and (not (pair? x))
(not (null? x))))
I then tried to figure out how to actually run this beast, so I watched the video again and saw him use the following:
(dsimp '(dd (+ x y) x))
As stated by Sussman, I should get back (+ 1 0). Instead, using R5RS I seem to be breaking in the extend-dictionary procedure at the line:
((eq? (cadr v) dat) dictionary)
The specific error it's returning is: mcdr: expects argument of type mutable-pair; given #f
When using neil/sicp I'm breaking in the evaluate procedure at the line:
(apply (eval (lookup (car form) dictionary)
user-initial-environment)
The specific error it's returning is: unbound identifier in module in: user-initial-environment
So, with all of that being said, I'd appreciate some help, or the a good nudge in the right direction. Thanks!
Your code is from 1991. Since R5RS came out in 1998, the code must be written for R4RS (or older).
One of the differences between R4RS and later Schemes is that the empty list was interpreted as false in the R4RS and as true in R5RS.
Example:
(if '() 1 2)
gives 1 in R5RS but 2 in R4RS.
Procedures such as assq could therefore return '() instead of false.
This is why you need to change the definition of extend-directory to:
(define (extend-dictionary pat dat dictionary)
(let ((vname (variable-name pat)))
(let ((v (assq vname dictionary)))
(cond ((not v)
(cons (list vname dat) dictionary))
((eq? (cadr v) dat) dictionary)
(else 'failed)))))
Also back in those days map was called mapcar. Simply replace mapcar with map.
The error you saw in DrRacket was:
mcdr: expects argument of type <mutable-pair>; given '()
This means that cdr got an empty list. Since an empty list has
no cdr this gives an error message. Now DrRacket writes mcdr
instead of cdr, but ignore that for now.
Best advice: Go through one function at a time and test it with
a few expressions in the REPL. This is easier than figuring
everything out at once.
Finally begin your program with:
(define user-initial-environment (scheme-report-environment 5))
Another change from R4RS (or MIT Scheme in 1991?).
Addendum:
This code http://pages.cs.brandeis.edu/~mairson/Courses/cs21b/sym-diff.scm almost runs.
Prefix it in DrRacket with:
#lang r5rs
(define false #f)
(define user-initial-environment (scheme-report-environment 5))
(define mapcar map)
And in extend-directory change the (null? v) to (not v).
That at least works for simple expressions.
Here is the code that works for me with mit-scheme (Release 9.1.1).
You also may use this code. It runs on Racket.
For running "eval" without errors, the following needed to be added
(define ns (make-base-namespace))
(apply (eval '+ ns) '(1 2 3))