`eval`和`eval-syntax`之间的区别

Lei*_*sen 9 eval racket

根据文档evaleval-syntax行为相同,异常eval 丰富了输入语法.

如果top-level-form是一个语法对象,其基准不是编译形式,那么它的词汇信息在被发送到评估处理程序之前会被丰富:

与eval类似,除了stx必须是语法对象,并且它的词汇上下文在传递给求值处理程序之前不会被丰富.

我很难理解这意味着什么.我得到的印象是以某种方式涉及命名空间,但我无法想出一个示例程序,其中eval和eval-syntax的行为不同.(当给出语法对象时.)

那么怎么做evaleval-syntax有所不同,或者至少你能给我一个样本程序,让他们表现出不同的行为?

Asu*_*awa 9

这是一个示例交互,显示它们的行为不同:

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)