为什么我的Scheme宏不能很好地工作?

时间:2016-11-11 03:32:41

标签: scheme racket

我希望我的代码将结构转移到表达式,并对其进行评估以获取原始结构。这是我的代码:

(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

我的缺点有什么问题?

2 个答案:

答案 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