3
votes

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.

2
hmm @SoraweePorncharoenwase I get +: unbound identifier; also, no #%app syntax transformer is bound at: + in: (+ 2 3)George Mauer
See the section "Namespaces" and/or "Namespaces and Modules" on the page I linked above.Sorawee Porncharoenwase

2 Answers

4
votes

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))
1
votes

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