2015-08-17 2 views
9

В соответствии с документацией eval и eval-syntax ведут себя одинаково, за исключением того, что evalenriches the input syntax.Разница между `eval` и` eval-syntax`

Если верхний уровень-форма представляет собой синтаксис объект, точка привязки не скомпилированные форм, то его лексическая информация обогащается перед его отправкой в ​​обработчик оценки:

Like eval, за исключением того, что stx должен быть синтаксическим объектом, а его лексический контекст не обогащается до того, как он будет передан обработчику оценки.

Мне сложно понять, что это значит. У меня создается впечатление, что они каким-то образом затрагивают пространства имен, но я не могу придумать примерную программу, где eval и eval-syntax ведут себя по-разному. (При задании объекта синтаксиса.)

Так как же eval и eval-syntax отличаются, или, по крайней мере, вы можете дать мне пример программы, которая показывает, что они ведут себя по-другому?

ответ

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! 
+0

Хм ... так хорошо, что они ведут себя по-другому. Хотя это похоже на то же самое поведение, если вы удалите первые два выражения и используйте '(eval stx)' и '(eval-sytnax stx)' без аргумента ns. –

+0

Также, если я все это делаю в модуле, похоже, что 'eval' и' eval-syntax' делают то же самое снова. (ошибка в том, что векторная карта не определена.) –

+0

Хм ... на самом деле, неважно. Когда я пытаюсь использовать последнюю версию ракетки, она работает так, как вы ее описываете. Благодарю. –

2

Ключевое слово здесь «enrichen». Документы говорят, что namespace-syntax-introduce используются eval для enrichen синтаксиса-объекта:

(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 называется, что не были доступны там, где был создан синтаксис-объект. И это именно то, что делает пример Асуму.

FWIW вот мое понимание того, как «enrichen-верхний уровень форма» работает:

(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

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 
Смежные вопросы