我希望我的代码将结构转移到表达式,并对其进行评估以获取原始结构。这是我的代码:
(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
我的缺点有什么问题?
答案 0 :(得分:1)
如果您使用#lang racket
作为语言选择来运行程序,
您需要使用eval
正确的命名空间。
例如,你可以使用它:
(define ns (variable-reference->namespace (#%variable-reference)))
(eval e ns)
简而言之:您的宏正在运行。评估宏结果的示例不是(至少在#lang racket
中)。
另请注意,在模块内部使用{&#34}之间存在差异"来自REPL。我打赌Renzo在REPL中测试了你的例子,它正常工作,你在模块中尝试了这个例子(也就是在定义窗口中)。
答案 1 :(得分:0)
查看代码并没有多大意义,因为宏扩展发生在代码运行之前。
(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-returns的扩展,以便您实际评估(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-returning d)
确实存在与之前相同的情况。实际上,你实际上永远不会得到d
的结构,而是遵循d
成对的奇怪循环,然后遵循常量,然后回到d
成对。
创建一个带有结构并生成一个表达式的过程很简单,只要保持结构不含那些没有文字版本的结构,它就会计算到原始结构的equal?
。例如#<procedure: +>
或#<struct:bla>
。这里只支持对和数字:
(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