I'm trying to level up on metaprogramming in Racket and realized I don't know how to take a datum and simply "eval" it.
If I have
(for ((x '(("Five" (+ 2 3))
("Twelve" (* 6 2))
("Three" (- (/ 21 3) 4)))))
(displayln (format "~s: ~s" (first x) (second x))))
I get
: "Five": (+ 2 3)
: "Twelve": (* 6 2)
: "Three": (- (/ 21 3) 4)
Which is not actually what I want - I want to actually evaluate that list to get the answer.
I'm sure this is simple (perhaps something I need to involve syntax for?) but I'm just missing the picture now. How do I do that?
Edit:
I want to evaluate the s-exp just before displaying, not in the initial list. This is why I figure I might need syntax since I would (I think) have to inject the current syntax context.
Eval is almost always the wrong choice, but eval is what you are looking for:
#lang racket
(define base-ns (make-base-namespace))
(for ((x '(("Five" (+ 2 3))
("Twelve" (* 6 2))
("Three" (- (/ 21 3) 4)))))
(displayln (format "~s: ~s" (first x) (eval (second x) base-ns))))
Alternative 1: Lambda / thunks
(for ((x `(("Five" ,(thunk (+ 2 3)))
("Twelve" ,(thunk (* 6 2)))
("Three" ,(thunk (- (/ 21 3) 4))))))
;; notice double parentheses to call the thunk
(displayln (format "~s: ~s" (first x) ((second x)))))
A thunk is just syntax sugar for a lambda with no arguments.
I've played a little around having procedures that can print their sources. Thus you can make your own thunk that has the original structure as structure as I demonstrate with my visual lambda:
(struct proc (src obj)
#:property prop:procedure (struct-field-index obj)
#:transparent
#:methods gen:custom-write
[(define (write-proc x port mode)
((case mode
[(#t) write]
[(#f) display]
[else pretty-print])
(proc-src x)
port))])
(define-syntax lambda*
(syntax-rules ()
((_ . rest)
(proc '(lambda* . rest) (lambda . rest)))))
(define test (lambda* (x y) (+ x y)))
test ; ==> #(struct:closure (lambda* (x y) (+ x y)) #<procedure>)
(proc-src test) ; ==> (lambda* (x y) (+ x y))
(proc-obj test) ; ==> #<procedure>
((proc-obj test) 1 2) ; ==> 3
(test 1 2) ; ==> 3
(display test) ; prints (lambda* (x y) (+ x y))
Use backquote together with unquote which is
;; backquote: `
;; unquote: ,
;; there is also splice list: ,#
(for ((x `(("Five" ,(+ 2 3))
("Twelve" ,(* 6 2))
("Three" ,(- (/ 21 3) 4)))))
(displayln (format "~s: ~s" (first x) (second x))))
;; "Five": 5
;; "Twelve": 12
;; "Three": 3
Related
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'm working on this project in Scheme and these errors on these three particular methods have me very stuck.
Method #1:
; Returns the roots of the quadratic formula, given
; ax^2+bx+c=0. Return only real roots. The list will
; have 0, 1, or 2 roots. The list of roots should be
; sorted in ascending order.
; a is guaranteed to be non-zero.
; Use the quadratic formula to solve this.
; (quadratic 1.0 0.0 0.0) --> (0.0)
; (quadratic 1.0 3.0 -4.0) --> (-4.0 1.0)
(define (quadratic a b c)
(if
(REAL? (sqrt(- (* b b) (* (* 4 a) c))))
((let ((X (/ (+ (* b -1) (sqrt(- (* b b) (* (* 4 a) c)))) (* 2 a)))
(Y (/ (- (* b -1) (sqrt(- (* b b) (* (* 4 a) c)))) (* 2 a))))
(cond
((< X Y) (CONS X (CONS Y '())))
((> X Y) (CONS Y (CONS X '())))
((= X Y) (CONS X '()))
)))#f)
Error:
assertion-violation: attempt to call a non-procedure [tail-call]
('(0.0) '())
1>
assertion-violation: attempt to call a non-procedure [tail-call]
('(-4.0 1.0) '())
I'm not sure what it is trying to call. (0.0) and (-4.0 1.0) is my expected output so I don't know what it is trying to do.
Method #2:
;Returns the list of atoms that appear anywhere in the list,
;including sublists
; (flatten '(1 2 3) --> (1 2 3)
; (flatten '(a (b c) ((d e) f))) --> (a b c d e f)
(define (flatten lst)
(cond
((NULL? lst) '())
((LIST? lst) (APPEND (CAR lst) (flatten(CDR lst))))
(ELSE (APPEND lst (flatten(CDR lst))))
)
)
Error: assertion-violation: argument of wrong type [car]
(car 3)
3>
assertion-violation: argument of wrong type [car]
(car 'a)
I'm not sure why this is happening, when I'm checking if it is a list before I append anything.
Method #3
; Returns the value that results from:
; item1 OP item2 OP .... itemN, evaluated from left to right:
; ((item1 OP item2) OP item3) OP ...
; You may assume the list is a flat list that has at least one element
; OP - the operation to be performed
; (accumulate '(1 2 3 4) (lambda (x y) (+ x y))) --> 10
; (accumulate '(1 2 3 4) (lambda (x y) (* x y))) --> 24
; (accumulate '(1) (lambda (x y) (+ x y))) --> 1
(define (accumulate lst OP)
(define f (eval OP (interaction-environment)))
(cond
((NULL? lst) '())
((NULL? (CDR lst)) (CAR lst))
(ELSE (accumulate(CONS (f (CAR lst) (CADR lst)) (CDDR lst)) OP))
)
)
Error:
syntax-violation: invalid expression [expand]
#{procedure 8664}
5>
syntax-violation: invalid expression [expand]
#{procedure 8668}
6>
syntax-violation: invalid expression [expand]
#{procedure 8672}
7>
syntax-violation: invalid expression [expand]
#{procedure 1325 (expt in scheme-level-1)}
This one I have no idea what this means, what is expand?
Any help would be greatly appreciated
code has (let () ...) which clearly evaluates to list? so the extra parentheses seems odd. ((let () +) 1 2) ; ==> 3 works because the let evaluates to a procedure, but if you try ((cons 1 '()) 1 2) you should get an error saying something like application: (1) is not a procedure since (1) isn't a procedure. Also know that case insensitivity is deprecated so CONS and REAL? are not future proof.
append concatenates lists. They have to be lists. In the else you know since lst is not list? that lst cannot be an argument of append. cons might be what you are looking for. Since lists are abstraction magic in Scheme I urge you to get comfortable with pairs. When I read (1 2 3) I see (1 . (2 . (3 . ()))) or perhaps (cons 1 (cons 2 (cons 3 '()))) and you should too.
eval is totally inappropriate in this code. If you pass (lambda (x y) (+ x y)) which evaluates to a procedure to OP you can do (OP 1 2). Use OP directly.
I have to make a function "alternate" which return another function depending of the number of time "alternate" is called.
I first try a simple counter with the square function and it worked well.
(define square
(let ((a 0))
(lambda (x)
(begin
(set! a (+ a 1))
(writeln a)
(* x x)))))
(map square '(1 2 3 4))
It returns as expected
1
2
3
4
'(1 4 9 16)
I want my program below to display
1
2
3
4
'(2 1 6 2)
But I don't know why it seems the counter stays to one. So my program display
1
'(2 4 6 8)
(define alternate
(let ((a 0))
(lambda (f g selector)
(begin
(set! a (+ a 1))
(writeln a)
(if (selector a)
(lambda (x) (f x))
(lambda (x) (g x)))))))
(map (alternate (lambda (x) (* x 2))
(lambda (x) (/ x 2))
odd?)
(first-n-integers 4))
Ps: (first-n-integers 4) return a list
'(1 2 3 4)
The problem is that alternate is executing exactly once and returning a single lambda as its result - instead of that you want to apply it every time. This should work:
(define (alternate f g selector)
(let ((a 0))
(lambda (x)
(set! a (+ a 1))
(writeln a)
(if (selector a)
(f x)
(g x)))))
For example:
(map (alternate (lambda (x) (* x 2))
(lambda (x) (/ x 2))
odd?)
(first-n-integers 4))
1
2
3
4
'(2 1 6 2)
I have a little noob question. I have to do a homework on genetic programming in scheme and the first step is to finish some given functions.
I got to a point where i have to execute a randomly generated function with all the possible parameters in a range (using map). The "function" is list like '(* (+ 1 x) (- x (* 2 3))).
How can i execute it with a given parameter? (for example x = 2). By the way, the generated function has a maximum of 1 parameter (it's x or none).
Thanks!
Here's my solution:
(define (execute expr)
(lambda (x)
(let recur ((expr expr))
(case expr
((x) x)
((+) +)
((-) -)
((*) *)
((/) /)
(else
(if (list? expr)
(apply (recur (car expr)) (map recur (cdr expr)))
expr))))))
Example usage:
> (define foo (execute '(* (+ 1 x) (- x (* 2 3)))))
> (foo 42)
=> 1548
I got this program:
(define a 2)
(define (goo x)
(display x) (newline)
(lambda (y) (/ x y)))
(define (foo x)
(let ((f (goo a)))
(if (= x 0)
x
(f x))))
and I asked to compare the evaluation results between the applicative and normal order on the expression (foo (foo 0)).
As I know, in applicative order, (display x) in function goo will print x and after it the program will collapse because y isn't defined. But when I run it in Scheme nothing happens. What is the reason?
(foo 0) evaluates to this code:
(define (goo 2)
(display 2) (newline)
(lambda (y) (/ 2 y)))
(define (foo x)
(let ((f (goo 2)))
(if (= 0 0)
0
((lambda (y) (/ 2 y)) 0))))
and prints 2, returning 0. While (foo 4) evaluates to:
(define (goo 2)
(display 2) (newline)
(lambda (y) (/ 2 y)))
(define (foo 4)
(let ((f (goo 2)))
(if (= 4 0)
4
((lambda (y) (/ 2 y)) 4))))
and prints 2, returning 0.5.