【问题标题】:Difference between `eval` and `eval-syntax``eval` 和 `eval-syntax` 之间的区别
【发布时间】:2015-11-10 17:34:30
【问题描述】:

根据文档evaleval-syntax 的行为相同,但eval enriches the input syntax 除外。

如果顶级形式是一个语法对象,其数据不是编译形式,则在将其发送到评估处理程序之前丰富其词法信息:

和 eval 一样,只是 stx 必须是一个语法对象,并且它的词法上下文在传递给评估处理程序之前没有被丰富。

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

那么evaleval-syntax 有什么不同,或者至少你能给我一个示例程序来显示它们的行为不同吗?

【问题讨论】:

    标签: eval racket


    【解决方案1】:

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

    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!
    

    【讨论】:

    • 嗯...这些确实表现不同。尽管如果您删除前两个表达式并使用不带 ns 参数的 (eval stx)(eval-sytnax stx) 似乎具有完全相同的行为。
    • 另外,如果我在一个模块中做所有事情,evaleval-syntax 似乎又做了同样的事情。 (向量图未定义的错误。)
    • 嗯...其实,没关系。当我在最新版本的球拍上尝试它时,它就像你描述的那样工作。谢谢。
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      这里的关键词是“丰富”。文档说namespace-syntax-introduceeval 用来丰富语法对象:

      (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 的示例所做的。

      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

      【讨论】:

        猜你喜欢
        • 2014-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-12-15
        • 2011-01-14
        相关资源
        最近更新 更多