根据文档eval和eval-syntax行为相同,异常eval 丰富了输入语法.
如果top-level-form是一个语法对象,其基准不是编译形式,那么它的词汇信息在被发送到评估处理程序之前会被丰富:
与eval类似,除了stx必须是语法对象,并且它的词汇上下文在传递给求值处理程序之前不会被丰富.
我很难理解这意味着什么.我得到的印象是以某种方式涉及命名空间,但我无法想出一个示例程序,其中eval和eval-syntax的行为不同.(当给出语法对象时.)
那么怎么做eval和eval-syntax有所不同,或者至少你能给我一个样本程序,让他们表现出不同的行为?
这是一个示例交互,显示它们的行为不同:
Welcome to Racket v6.2.900.10.
-> (define ns (make-base-namespace)) ; set up namespace ns
-> (eval '(require racket/vector) ns) ; bring in vector-map into ns
-> (module a racket/base
(define stx #'(vector-map + #(1 2) #(3 4))) ; no vector-map here
(provide stx))
-> (require 'a)
-> (eval stx ns)
'#(4 6)
-> (eval-syntax stx ns)
; vector-map: undefined;
; cannot reference undefined identifier
; [,bt for context]
Run Code Online (Sandbox Code Playgroud)
这表明在使用具有向量绑定的命名空间的情况下namespace-syntax-introduce应用于语法对象,这就是应用程序成功的原因.stxevalvector-map
在这种eval-syntax情况下,语法对象没有词法信息,vector-map并且没有完成命名空间引入,因此会导致错误.
请注意,您需要模块来显示此差异而不是语法对象的顶级定义,因为顶级绑定是特殊的.看到这个位来自namespace-syntax-introduce:
语法对象的词法信息中的任何现有顶级绑定都会覆盖其他上下文
您可以在模块内部获得类似的行为:
#lang racket/base ; racket/base does not include racket/vector
(define ns (make-base-namespace)) ; Create Namespace
(eval #'(require racket/vector) ns) ; Load racket/vector into ns
(define stx #'(vector-map + #(1 2) #(3 4)))
(eval stx ns) ; => '#(4 6)
(eval-syntax stx ns) ; => ERROR!
Run Code Online (Sandbox Code Playgroud)