根据文档eval
和eval-syntax
行为与eval
enriches the input syntax的例外情况相同。
如果top-level-form是一个语法对象,其基准不是编译形式,那么它的词汇信息在被发送到评估处理程序之前就会被丰富:
与eval类似,除了stx必须是语法对象,并且在将词汇上下文传递给求值处理程序之前,它的词汇上下文不会被丰富。
我很难理解这意味着什么。我得到的印象是以某种方式涉及命名空间,但我无法想出一个示例程序,其中eval和eval-syntax的行为不同。 (当给出语法对象时。)
那么eval
和eval-syntax
如何区别,或者至少可以给我一个示例程序来显示它们的行为方式不同?
答案 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