my task is to make this to test to run:
(test (run "{+ {2 1} {3 4}}") '(5 6 4 5))
(test (run "{+ {- {+ 1 3} 2} {10 -10}}") '(12 -8))
The source code i have so far looks like that
#lang plai
(require (for-syntax racket/base) racket/match racket/list racket/string
(only-in mzlib/string read-from-string-all))
;; build a regexp that matches restricted character expressions, can use only
;; {}s for lists, and limited strings that use '...' (normal racket escapes
;; like \n, and '' for a single ')
(define good-char "(?:[ \t\r\na-zA-Z0-9_{}!?*/<=>:+-]|[.][.][.])")
;; this would make it awkward for students to use \" for strings
;; (define good-string "\"[^\"\\]*(?:\\\\.[^\"\\]*)*\"")
(define good-string "[^\"\\']*(?:''[^\"\\']*)*")
(define expr-re
(regexp (string-append "^"
good-char"*"
"(?:'"good-string"'"good-char"*)*"
"$")))
(define string-re
(regexp (string-append "'("good-string")'")))
(define (string->sexpr str)
(unless (string? str)
(error 'string->sexpr "expects argument of type <string>"))
(unless (regexp-match expr-re str)
(error 'string->sexpr "syntax error (bad contents)"))
(let ([sexprs (read-from-string-all
(regexp-replace*
"''" (regexp-replace* string-re str "\"\\1\"") "'"))])
(if (= 1 (length sexprs))
(car sexprs)
(error 'string->sexpr "bad syntax (multiple expressions)"))))
(test/exn (string->sexpr 1) "expects argument of type <string>")
(test/exn (string->sexpr ".") "syntax error (bad contents)")
(test/exn (string->sexpr "{} {}") "bad syntax (multiple expressions)")
;; WAE abstract syntax trees
(define-type WAE
[num (listof number?)]
[add (left WAE?) (right WAE?)]
[sub (left WAE?) (right WAE?)]
[with (name symbol?) (init WAE?) (body WAE?)]
[id (name symbol?)])
; parse-sexpr : sexpr -> WAE
;; to convert s-expressions into WAEs
(define (parse-sexpr sexp)
(match sexp
[(? number?) (num sexp)]
[(list '+ l r) (add (parse-sexpr l) (parse-sexpr r))]
[(list '- l r) (sub (parse-sexpr l) (parse-sexpr r))]
[(list 'with (list x i) b) (with x (parse-sexpr i) (parse-sexpr b))]
[(? symbol?) (id sexp)]
[else (error 'parse "bad syntax: ~a" sexp)]))
parses a string containing a WAE expression to a WAE AST
(define (parse str)
(parse-sexpr (string->sexpr str)))
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)
(type-case WAE 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))]
[id (name) (if (symbol=? name from) (num to) expr)]
[with (bound-id named-expr bound-body)
(with bound-id
(subst named-expr from to)
(if (symbol=? bound-id from)
bound-body
(subst bound-body from to)))]))
evaluates WAE expressions by reducing them to numbers
(define (eval expr)
(type-case WAE expr
[num (n) n]
[add (l r) (+ (eval l) (eval r))]
[sub (l r) (- (eval l) (eval r))]
[with (bound-id named-expr bound-body)
(eval (subst bound-body
bound-id
(eval named-expr)))]
[id (name) (error 'eval "free identifier: ~s" name)]))
; run : string -> listof number
;; evaluate a WAE program contained in a string
(define (run str)
(eval (parse str)))
bin-op : (number number -> number) (listof number or number) (listof number or number) -> (listof number))
applies a binary numeric function on all combinations of numbers from the two input lists or numbers, and return the list of all of the results
(define (bin-op op ls rs)
(define (helper l rs)
;; f : number -> number
(define (f n) (op l n))
(map f rs))
(if (null? ls)
null
(append (helper (first ls) rs) (bin-op op (rest ls) rs))))
Can someone please give me an idea how to change my functions to make the tests above work?
Thank you in advance.
Related
Here is my code about postfix in scheme:
(define (stackupdate e s)
(if (number? e)
(cons e s)
(cons (eval '(e (car s) (cadr s))) (cddr s))))
(define (postfixhelper lst s)
(if (null? lst)
(car s)
(postfixhelper (cdr lst) (stackupdate (car lst) s))))
(define (postfix list)
(postfixhelper list '()))
(postfix '(1 2 +))
But when I tried to run it, the compiler said it takes wrong. I tried to check it, but still can't find why it is wrong. Does anyone can help me? Thanks so much!
And this is what the compiler said:
e: unbound identifier;
also, no #%app syntax transformer is bound in: e
eval never has any information about variables that some how are defined in the same scope as it is used. Thus e and s does not exist. Usually eval is the wrong solution, but if you are to use eval try doing it as as little as you can:
;; Use eval to get the global procedure
;; from the host scheme
(define (symbol->proc sym)
(eval sym))
Now instead of (eval '(e (car s) (cadr s))) you do ((symbol->proc e) (car s) (cadr s)). Now you should try (postfix '(1 2 pair?))
I've made many interpreters and none of them used eval. Here is what I would have done most of the time:
;; Usually you know what operators are supported
;; so you can map their symbol with a procedure
(define (symbol->proc sym)
(case sym
[(+) +]
[(hyp) (lambda (k1 k2) (sqrt (+ (* k1 k1) (* k2 k2))))]
[else (error "No such operation" sym)]))
This fixes the (postfix '(1 2 pair?)) problem. A thing that I see in your code is that you always assume two arguments. But how would you do a double? eg something that just doubles the one argument. In this case symbol->proc could return more information:
(define (symbol->op sym)
(case sym
[(+) (cons + 2)]
[(double) (cons (lambda (v) (* v v)) 1)]
[else (error "No such operation" sym)]))
(define op-proc car)
(define op-arity cdr)
And in your code you could do this if it's not a number:
(let* ([op (symbol->op e)]
[proc (op-proc op)]
[arity (op-arity op)])
(cons (apply proc (take s arity)
(drop s arity)))
take and drop are not R5RS, but they are simple to create.
So imagine i have a list '(+ (* (x) (5)) (2))
How would i make a procedure that changes the x to whichever parameter i give and then evaluates
the function inside the list?
((calculate expression x))
I had some ideas but didn't get it to work.
These are the helprocedures i made:
(define (atom? x)
(not (pair? x)))
(define (deep-map f l)
(cond
((null? l) '())
((atom? l) (f l))
(else
(cons (deep-map f (car l))
(deep-map f (cdr l))))))
(define (deep-change e1 e2 l)
(deep-map (lambda (x) (if (eq? x e1) e2 x)) l))
(define (go-through-list list)
(if (null? list)
'()
((car list) (go-through-list (cdr list)))))
Here is the main code:
(define (calculate expression x)
(let ((expressie (deep-change 'x x expression)))
(('+ (deep-change '+ (+) expression)))
(('- (deep-change '- (-) expression)))
(('* (deep-change '* (*) expression)))
(('/ (deep-change '/ (/) expression)))
(go-through-list expression)))
I managed to change the x in to to parameter i give but have problems with the * and + inside the list.
(define (replace x y tree)
(cond ((null? tree) tree)
((not (or (pair? tree) (list? tree))) (if (eq? x tree) y tree))
(else (cons (replace x y (car tree))
(replace x y (cdr tree))))))
And then you can simply (replace 'x 42 expr).
Assuming the tree is then valid scheme code. You can simply eval it.
If you're trying to replace multiple variables, it might be wise write a replace-multiple function that will handle arbitrary number of variables so that you can do something like this
(replace-multiple '(x y z) '(1 2 3) expr)
Implementing this function is basically calling replace multiple times.
e.g.
(replace 'x 1 (replace 'y 2 (replace 'z 3 expr)))
So you might want to use recursion there.
If your scheme has the fold operator (provided by srfi-1), use it because it essentially achieves the above.
It would probably look something like this:
(define (replace-multiple xs ys tree)
(fold replace tree xs ys))
This could be an interesting question; consider this clarification:
Evaluate list representing expression with free variable without using eval
What is a way to develop a function to evaluate a Scheme expression built from
the four arithmetic operations, numbers, and a free variable x, without using eval?
The function is given a list representing the expression and a value for x.
Example: (calculate '(+ (* x 5) 2) 3) => 17
Development is presented as a sequence of elaborations of the calculate function;
each define has a Signature comment on the same line, informally describing
argument/result types; function and following example(s) can be copy-pasted into a REPL.
Note: not all errors are detected; there is a compact version without comments at the end.
Getting started: write a function which works for the given example:
(define (calculate-0 expression-in-x value-for-x) ;; '(+ (* x 5) 2) Number -> Number
(if (equal? expression-in-x '(+ (* x 5) 2))
(+ (* value-for-x 5) 2)
(error #f "wrong expression" expression-in-x)))
(calculate-0 '(+ (* x 5) 2) 3) ;=> 17
Real function will have to extract pieces of expression
a simple example with all elements is '(+ x 1):
(define (calculate-1 expression value) ;; '(+ x <n>) Number -> Number
(let ([procedure (car expression)]
[argument-1 (cadr expression)]
[argument-2 (caddr expression)])
(if (and (eq? procedure '+)
(eq? argument-1 'x)
(number? argument-2))
(+ value argument-2)
(error #f "expression" expression))))
(calculate-1 '(+ x 1) 2) ;=> 3
+ in Scheme accepts any number of arguments, so replace if with map/cond:
(define (calculate-2 expression value) ;; '(+ x|<n> ...) Number -> Number
(let ([arguments (cdr expression)])
(let ([arguments
(map (lambda (argument)
(cond ;; (compare with (if ...) in calculate-1)
[(eq? argument 'x) value ]
[(number? argument) argument ]
[else (error #f "argument" argument)]))
arguments)])
(apply + arguments))))
(calculate-2 '(+ 1 x) 2) ;=> 3
(calculate-2 '(+ x 1 x) 3) ;=> 7
(calculate-2 '(+) 99) ;=> 0
Get all four operations working:
(define (calculate-3 expression value) ;; '(op x|<n> ...) Number -> Number
(let ([procedure (car expression)]
[arguments (cdr expression)])
(let ([arguments ;; (same as calculate-2)
(map (lambda (argument)
(cond
[(eq? argument 'x) value ]
[(number? argument) argument ]
[else (error #f "argument" argument)]))
arguments)])
(apply (case procedure
[(+) + ]
[(-) - ]
[(*) * ]
[(/) / ]
[else (error #f "procedure" procedure)])
arguments))))
(calculate-3 '(* x 5) 3) ;=> 15
Allowing nested sub-forms needs just one small change:
(define (calculate-4 expression value) ;; '(op x|<n>|Expr ...) Number -> Number
(let ([procedure (car expression)]
[arguments (cdr expression)])
(let ([arguments
(map (lambda (argument)
(cond
[(eq? argument 'x) value ]
[(number? argument) argument ]
[(pair? argument) ;; (<- only change)
(calculate-4 argument value) ] ;;
[else (error #f "argument" argument)]))
arguments)])
(apply (case procedure
[(+) + ]
[(-) - ]
[(*) * ]
[(/) / ]
[else (error #f "procedure" procedure)])
arguments))))
(calculate-4 '(+ (* x 5) 2) 3) ;=> 17
So there it is: try calculate-4 with the original example in the REPL:
$ scheme
> (calculate-4 '(+ (* x 5) 2) 3)
17
> ; works with all Scheme Numbers:
(calculate-4 '(+ (* x 15/3) 2+2i) 3.0)
17.0+2.0i
>
Not so fast ... expression is a list with the form of a Scheme expression using four
operations, Numbers, and x. But the question doesn't require value to be a Number: procedures are
first-class values in Scheme
(expression could be '(+ (x 3) 2) with value (lambda (n) (* n 5)) ):
(define (calculate-5 expression value) ;; '(x|op x|<n>|Expr ...) Number|Lambda -> Value
(let ([procedure (car expression)]
[arguments (cdr expression)])
(let ([arguments
(map (lambda (argument)
(cond
[(eq? argument 'x) value ]
[(number? argument) argument ]
[(pair? argument) (calculate-5 argument value) ]
[else (error #f "argument" argument)]))
arguments)])
(let ([procedure
(cond ;; (compare with argument cond above)
[(eq? procedure 'x) value ]
[(pair? procedure) (calculate-5 procedure value)]
[else (case procedure
[(+) + ]
[(-) - ]
[(*) * ]
[(/) / ]
[else (error #f "procedure" procedure)]) ]) ])
(apply procedure arguments)))))
(calculate-5 '(+ (x 3) 2) (lambda (n) (* n 5))) ;=> 17
(And so, finally, our calculate function is "Hello World!" capable :)
$ scheme
> ;(copy-paste calculate-5 here)
> (calculate-5 '(x) (lambda _ 'Hello!))
Hello!
>
Compact version (returns #f on error):
(define (calculate expr value)
(call/cc (lambda (error)
(let* ([proc (car expr)]
[args (map (lambda (arg) (cond
[(eq? arg 'x) value]
[(number? arg) arg]
[(pair? arg)
(or (calculate arg value) (error #f))]
[else (error #f)]))
(cdr expr))]
[proc (cond
[(eq? proc 'x) value ]
[(pair? proc) (calculate proc value)]
[else (case proc [(+) +] [(-) -] [(*) *] [(/) /]
[else (error #f)])])])
(apply proc args)))))
I am writing a program in scheme that takes in regular scheme notation ex: (* 5 6) and returns the notation that you would use in any other language ex: (5 * 6)
I have my recursive step down but I am having trouble breaking out into my base case.
(define (infix lis)
(if (null? lis) '()
(if (null? (cdr lis)) '(lis)
(list (infix (cadr lis)) (car lis) (infix(caddr lis))))))
(infix '(* 5 6))
the error happens at the (if (null? lis)) '(lis)
the error message is:
mcdr: contract violation
expected: mpair?
given: 5
>
why is it giving me an error and how can I fix this?
Right now your infix function is assuming that its input is always a list. The input is not always a list: sometimes it is a number.
A PrefixMathExpr is one of:
- Number
- (list BinaryOperation PrefixMathExpr PrefixMathExpr)
If this is the structure of your data, the code should follow that structure. The data definition has a one-of, so the code should have a conditional.
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) ???]))
Each conditional branch can use the sub-parts from that case of the data definition. Here, the list branch can use (car p), (cadr p), and (caddr p).
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) (.... (car p) (cadr p) (caddr p) ....)]))
Some of these sub-parts are complex data definitions, in this case self-references to PrefixMathExpr. Those self-references naturally turn into recursive calls:
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) ???]
[(list? p) (.... (car p) (infix (cadr p)) (infix (caddr p)) ....)]))
Then fill in the holes.
;; infix : PrefixMathExpr -> InfixMathExpr
(define (infix p)
(cond
[(number? p) p]
[(list? p) (list (infix (cadr p)) (car p) (infix (caddr p)))]))
This process for basing the structure of the program on the structure of the data comes from How to Design Programs.
Mistake
(infix '(* 5 6))
; =
(list (infix (cadr '(* 5 6))) (car '(* 5 6)) (infix (caddr '(* 5 6))))
; =
(list (infix 5) '* (infix (caddr 6)))
; = ^^^^^^^^^
; |
; |
; v
(if ...
...
(if (null? (cdr 5)) ; <-- fails here
...
...))
Solution
First, you need to define the structure of the data you're manipulating:
; OpExp is one of:
; - Number
; - (cons Op [List-of OpExp])
; Op = '+ | '* | ...
In english: it's either a number or an operator followed by a list of other op-expressions.
We define some examples:
(define ex1 7)
(define ex2 '(* 1 2))
(define ex3 `(+ ,ex2 ,ex1))
(define ex4 '(* 1 2 3 (+ 4 3 2) (+ 9 8 7)))
Now we follow the structure of OpExp to make a "template":
(define (infix opexp)
(if (number? opexp)
...
(... (car opexp) ... (cdr opexp) ...)))
Two cases:
The first case: what to do when we just get a number?
The second case: first extract the componenet:
(car opexp) is the operator
(cdr opexp) is a list of operands of type OpExp
Refining the template:
(define (infix opexp)
(if (number? opexp)
opexp
(... (car opexp) ... (map infix (cdr opexp)) ...)))
Since we have a a list of op-exps, we need to map a recursive call on all of them. All we need to do is make the operator infix at the top-level.
We use a helper that intertwines the list with the operator:
; inserts `o` between every element in `l`
(define (insert-infix o l)
(cond ((or (null? l) (null? (cdr l))) l) ; no insertion for <= 1 elem lst
(else (cons (car l) (cons o (insert-infix o (cdr l)))))))
and finally use the helper to get the final version:
; converts OpExp into infix style
(define (infix opexp)
(if (number? opexp)
opexp
(insert-infix (car opexp) (map infix (cdr opexp)))))
We define respective results for our examples:
(define res1 7)
(define res2 '(1 * 2))
(define res3 `(,res2 + ,res1))
(define res4 '(1 * 2 * 3 * (4 + 3 + 2) * (9 + 8 + 7)))
And a call of infix on ex1 ... exN should result in res1 ... resN
I am trying to write by myself the cons function in scheme. I have written this code:
(define (car. z)
(z (lambda (p q) p)))
and I am trying to run :
(car. '(1 2 3))
I expect to get the number 1, but it does not work properly.
When you implement language data structures you need to supply constructors and accessors that conform to the contract:
(car (cons 1 2)) ; ==> 1
(cdr (cons 1 2)) ; ==> 2
(pair? (cons 1 2)) ; ==> 2
Here is an example:
(define (cons a d)
(vector a d))
(define (car p)
(vector-ref p 0))
(define (cdr p)
(vector-ref p 1))
Now if you make an implementation you would implement read to be conformant to this way of doing pairs so that '(1 2 3) would create the correct data structure the simple rules above is still the same.
From looking at car I imagine cons looks like this:
(define (cons a d)
(lambda (p) (p a d)))
It works with closures. Now A stack machine implementation of Scheme would analyze the code for free variables living passed their scope and thus create them as boxes. Closures containing a, and d aren't much different than vectors.
I urge you to implement a minimalistic Scheme interpreter. First in Scheme since you can use the host language, then a different than a lisp language. You can even do it in an esoteric language, but it is very time consuming.
Sylwester's answer is great. Here's another possible implementation of null, null?, cons, car, cdr -
(define null 'null)
(define (null? xs)
(eq? null xs))
(define (cons a b)
(define (dispatch message)
(match message
('car a)
('cdr b)
(_ (error 'cons "unsupported message" message))
dispatch)
(define (car xs)
(if (null? xs)
(error 'car "cannot call car on an empty pair")
(xs 'car)))
(define (cdr xs)
(if (null? xs)
(error 'cdr "cannot call cdr on an empty pair")
(xs 'cdr)))
It works like this -
(define xs (cons 'a (cons 'b (cons 'c null))))
(printf "~a -> ~a -> ~a\n"
(car xs)
(car (cdr xs))
(car (cdr (cdr xs))))
;; a -> b -> c
It raises errors in these scenarios -
(cdr null)
; car: cannot call car on an empty pair
(cdr null)
; cdr: cannot call cdr on an empty pair
((cons 'a 'b) 'foo)
;; cons: unsupported dispatch: foo
define/match adds a little sugar, if you like sweet things -
(define (cons a b)
(define/match (dispatch msg)
(('car) a)
(('cdr) b)
(('pair?) #t)
((_) (error 'cons "unsupported dispatch: ~a" msg)))
dispatch)
((cons 1 2) 'car) ;; 1
((cons 1 2) 'cdr) ;; 2
((cons 1 2) 'pair?) ;; #t
((cons 1 2) 'foo) ;; cons: unsupported dispatch: foo
I am studying "Programming Languages: Application and Interpretation" and I can run the first two chapters' examples in DrRacket 5.2.1 after executing #lang plai. but when I typed the 3rd chapter's first example as below:
(with (x 5) (+ x x))
I got the following error:
reference to an identifier before its definition: with
I did not find the definition of with in this book. Do I need a library?
The with construct is not something that you use in your own programs -- it's something that exists in the language that you define instead. In other words, it's something that you implement not something that you use. Note that the books always uses it with curly braces, {with {x ...} ...}, and that's intended to avoid this exact confusion that you're having -- curly braces are always used in code that is in the language you implement, and round parentheses are used for your own implementation's code.
Note that defining your own with is simple in Racket, but it would be wrong, and is likely to get you more confused. Instead of trying to use it in Racket, you should just follow the book, and at the end of chapter 3 you will have a working interpreter for the WAE language -- and then you'll be able to use it to run WAE programs that use with.
As a side note, if you're looking for a Racket form that is similar to with, then look into let -- the only difference is that let allows you to specify multiple bindings instead of just one.
(with (x a) <body>) is just a synonym for ((lambda x <body>) a)
If you still have problem with that you can solve this by using
((lambda x (+ x x)) 5)
I am so sorry I could not test these examples yesterday!
it seems that there are still error,
I typed these codes of the end of chapter 3 as follows:
(define (parse sexp)
(cond
[(number? sexp) (num sexp)]
[(list? sexp)
(case (first sexp)
[(+) (add (parse (second sexp))
(parse (third sexp)))]
[(-) (sub (parse (second sexp))
(parse (third sexp)))])]))
(define-type WAE
[num (n number?)]
[add (lhs WAE?)(rhs WAE?)]
[sub (lhs WAE?) (rhs WAE?)]
[with (name symbol?) (named-expr WAE?)(body WAE?)]
[id (name symbol?)])
(define (subst expr sub-id val)
(type-case WAE expr
[num (n) expr]
[add (l r) (add (subst l sub-id val)
(subst r sub-id val))]
[sub (l r) (sub (subst l sub-id val)
(subst r sub-id val))]
[with (bound-id named-expr bound-body)
(if (symbol=? bound-id sub-id)
(with bound-id
(subst named-expr sub-id val)
bound-body)
(with bound-id
(subst named-expr sub-id val)
(subst bound-body sub-id val)))]
[id (v) (if (symbol=? v sub-id) val expr)]))
(define (calc expr)
(type-case WAE expr
[num (n) n]
[add (l r) (+ (calc l) (calc r))]
[sub (l r) (- (calc l) (calc r))]
[with (bound-id named-expr bound-body)
(calc (subst bound-body
bound-id
(num (calc named-expr))))]
[id (v) (error 'calc "free identifier")]))
and then, I test 'with' as below in page 21
(calc (parse '{with {x {+ 5 5}} {+ x x}}))
I got the error:
"type-case: expected a value from type WAE, got: #"
the reason for this is that a updated parse is needed,I got some snippets from google about chapter 3, for example, in CS 345 Progamming Languages, its parse's definition is as follows:
(define parse
(lambda (sexp)
(cond
[(number? sexp) (num sexp)]
[(symbol? sexp) (id sexp)]
[(list? sexp)
(case (first sexp)
[(+)(add (parse (second sexp))
(parse (third sexp)))]
[(-) (sub (parse (second sexp))
(parse (third sexp)))]
[(with) (with (first (second sexp))
(parse (second (second sexp)))
(parse (third sexp)))]
)])))
finally, I got a right result:
(calc (parse '{with {x {+ 5 5}} {+ x x}}) ) => 20