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

时间:2015-08-17 23:23:27

标签: eval racket

根据文档evaleval-syntax行为与eval enriches the input syntax的例外情况相同。

  

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

  

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

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

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

3 个答案:

答案 0 :(得分: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]

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

答案 1 :(得分:4)

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

答案 2 :(得分:2)

这里的关键字是“丰富”。文档说namespace-syntax-introduce eval使用(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). 来丰富语法对象:

eval

这意味着一个示例由一个语法对象stx给出,该语法对象stx引用当前命名空间中的绑定,其中(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))])) 被调用,在构造语法对象时不可用。这正是Asumu的例子。

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

df=dfFromJson:
{"class":"name 1","stream":"science"}
{"class":"name 1","stream":"arts"}
{"class":"name 1","stream":"science"}
{"class":"name 1","stream":"law"}
{"class":"name 1","stream":"law"}
{"class":"name 2","stream":"science"}
{"class":"name 2","stream":"arts"}
{"class":"name 2","stream":"law"}
{"class":"name 2","stream":"science"}
{"class":"name 2","stream":"arts"}
{"class":"name 2","stream":"law"}


df.groupBy("class").agg(count(col("stream")==="science") as "stream_science", count(col("stream")==="arts") as "stream_arts", count(col("stream")==="law") as "stream_law")

在此处查看更多内容:https://github.com/soegaard/meta/blob/master/expander/expander.rkt#L348