' eval '和' eval-syntax '的区别



根据文档evaleval-syntax的行为相同,除了eval丰富了输入语法。

如果顶级表单是一个语法对象,其数据不是编译后的表单,则在将其发送到求值处理程序之前对其词法信息进行充实:

与eval类似,只是stx必须是一个语法对象,并且在传递给求值处理程序之前不会充实它的词法上下文。

我很难理解这是什么意思。我得到的印象是,这在某种程度上涉及到名称空间,但我无法提出一个示例程序,其中eval和eval语法的行为不同。(当给定语法对象时)

那么evaleval-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]

这表明在eval的情况下,namespace-syntax-introduce使用具有向量绑定的名称空间应用于语法对象stx,这就是vector-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!

这是Asumu回答底部的对偶程序:

#lang racket/base
(require racket/vector) ; adds vector-map to lexical scope
; use vector-map from lexical scope
(eval-syntax #'(vector-map + #(1 2) #(3 4)))  ; => #(4 6)
; vector-map not in dynamic scope
; (make-base-namespace == racket/base)
(eval '(vector-map + #(1 2) #(3 4)) (make-base-namespace)) 
; => ERR: vector-map: undefined

这里的关键字是" enrichment "。文档说eval使用namespace-syntax-introduce来丰富语法-object:

(namespace-syntax-introduce stx) → syntax?
Returns a syntax object like stx, except that the current namespace’s bindings 
are included in the syntax object’s lexical information (see Syntax Objects). 

这意味着语法对象stx给出了一个例子,它引用了当前名称空间中调用eval的绑定,而该绑定在构造语法对象时不可用。而这正是Asumu的例子所做的。

以下是我对"rich -top-level-form"的理解:

(define (enrichen-top-level-form top-level-form)
  ; see docs for eval
  (define introduce namespace-syntax-introduce)
  (match top-level-form
    [(? syntax? s)
     (match (syntax-e s)
       [(? compiled-expression? c) c]
       [(cons (? sym-or-id? mod?) more)
        (define mod (introduce mod?))
        (if (bound-identifier=? mod #'module)
            (datum->syntax #f (cons mod more))
            (introduce s))]
       [_ (introduce s)])]
    [d (enrichen-top-level-form (datum->syntax #f d #f))]))

查看更多信息:https://github.com/soegaard/meta/blob/master/expander/expander.rkt#L348

最新更新