首页 文章

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

提问于
浏览
9

根据文档 evaleval-syntax 的行为相同,除了 eval enriches the input syntax .

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

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

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

那么 evaleval-syntax 如何区别,或者至少可以给我一个示例程序,以显示它们的行为方式不同?

3 回答

  • 2

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

    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]
    

    这表明 namespace-syntax-introduceeval 情况下使用具有向量绑定的命名空间应用于语法对象 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!
    
  • 9

    这是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
    
  • 4

    这里的关键字是"enrichen" . 文档说 eval 使用 namespace-syntax-introduce 来丰富语法对象:

    (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给出的,该语法对象stx引用当前命名空间中的绑定,其中 eval 被调用,而这正是Asumu的例子所做的 .

    FWIW在这里是我对“丰富的顶级形式”如何运作的理解:

    (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

相关问题