Scheme 为什么';我的计划行得通吗?

Scheme 为什么';我的计划行得通吗?,scheme,racket,Scheme,Racket,我希望我的代码将结构转换为表达式,并对其求值以获得原始结构。这是我的密码: (define-syntax expr-returning (syntax-rules () ((expr-returning (car x)) '(car (expr-returning x))) ((expr-returning (cdr x)) '(cdr (expr-returning x)))

我希望我的代码将结构转换为表达式,并对其求值以获得原始结构。这是我的密码:

(define-syntax expr-returning (syntax-rules ()
                           ((expr-returning (car x)) '(car (expr-returning x)))
                           ((expr-returning (cdr x)) '(cdr (expr-returning x)))
                           ((expr-returning (cons x y)) '(cons (expr-returning x) (expr-returning y)))
                           ((expr-returning obj) (cond [(null? obj)  'null]
                                                       [(number? obj)  'obj]
                                                       [(char? obj)  'obj]
                                                       [(boolean? obj) 'obj]
                                                       [(pair? obj) (expr-returning (cons (car obj) (cdr obj)))]
                                                       [else 'error]
                                                  ))))
这是我的测试:

(define ls (append '(a e i o u) 'y))
(define d (cons ls (cdr (cdr ls))))
(define e (expr-returning d))

d
e
(eval e)
输出是

'((a e i o u . y) i o u . y)
'(cons (expr-returning (car d1)) (expr-returning (cdr d1)))
cons: unbound identifier;
 also, no #%app syntax transformer is bound in: cons

我的缺点是什么?

如果您使用
#lang racket
作为语言选择运行程序, 您需要对
eval
使用正确的命名空间

例如,您可以使用:

(define ns (variable-reference->namespace (#%variable-reference)))
(eval e ns)
简而言之:您的宏正在工作。评估宏结果的示例不是(至少在
#lang racket
中)


还请注意,从“模块内部”使用
eval
与从REPL使用之间存在差异。我打赌Renzo在REPL中测试了您的示例,它在REPL中正常工作,并且您在模块内(即在定义窗口中)尝试了该示例。

查看您的代码没有多大意义,因为宏扩展发生在代码运行之前

(define-syntax expr-returning
  (syntax-rules ()
    ((expr-returning (car x)) '(car (expr-returning x)))
    ((expr-returning (cdr x)) '(cdr (expr-returning x)))
    ((expr-returning (cons x y)) '(cons (expr-returning x) (expr-returning y)))
    ((expr-returning obj) (cond [(null? obj)  'null]
                                [(number? obj)  'obj]
                                [(char? obj)  'obj]
                                [(boolean? obj) 'obj]
                                [(pair? obj) '(cons (expr-returning (car obj)) (expr-returning (cdr obj)))] ; expanded 
                                [else 'error]
                                ))))
由于
d
是宏的一个符号,因此它是
obj
,在运行时它会变成文字表达式:

'(cons (expr-returning (car d)) (expr-returning (cdr d)))
计算此值将触发expr returning的扩展,以便您实际正在计算
(cons'(car(expr returning d))(cdr(expr returning d))
,该值将转换为
((car(expr returning d))(cdr(expr returning d)))
,显示为
((car(expr returning d))cdr(expr returning d))

如果您要再次评估此值,请注意,您有
(expr返回d)
,它确实会像以前一样执行此操作。实际上,你永远不会得到
d
的结构,而是遵循
d
作为一对的奇怪循环,然后遵循常量,然后回到
d
作为一对

只要不让结构中存在像
这样没有文字版本的类型,就可以创建一个采用结构并生成计算结果与原始结构相等的表达式的过程。下面是一个仅支持对和数字的:

(define (obj->literal obj)
  (define (primitive? v)
    (or (number? v) (null? v)))
  (list 'quote 
        (let recur ((obj obj))
          (if (primitive? obj)
              obj
              (cons (recur (car obj)) 
                    (recur (cdr obj)))))))

(define e (obj->literal d))
e
; ==> (cons (cons 'a (cons 'e (cons 'i (cons 'o (cons 'u 'y))))) (cons 'i (cons 'o (cons 'u 'y))))
(equal? d (eval e (make-base-namespace)))
; ==> #t

我在DrRacket中尝试了您的示例,它是有效的:
(eval e)
=>
'((car(expr返回d))cdr(expr返回d))
。是的,名称空间是必需的。Oops。我的密码出错了。环路不应该在那里。你的代码是对的。