Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between `eval` and `eval-syntax`

Tags:

eval

racket

According to the documentation eval and eval-syntax behave the same with the exception that eval enriches the input syntax.

If top-level-form is a syntax object whose datum is not a compiled form, then its lexical information is enriched before it is sent to the evaluation handler:

Like eval, except that stx must be a syntax object, and its lexical context is not enriched before it is passed to the evaluation handler.

I am having a hard time understanding what this means. I get the impression that involves namespaces somehow, but I can't come up with an example program where eval and eval-syntax behave differently. (When given a syntax object.)

So how do eval and eval-syntax differ, or at least can you give me a sample program that shows them behaving differently?

like image 234
Leif Andersen Avatar asked Aug 17 '15 23:08

Leif Andersen


1 Answers

Here is a sample interaction that shows them behaving differently:

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]

This shows that namespace-syntax-introduce is applied to the syntax object stx in the eval case using a namespace that has the vector bindings, which is why the vector-map application succeeds.

In the eval-syntax case, the syntax object does not have the lexical information for vector-map and no namespace introduction is done, so it results in an error.

Note that you need the module to show this difference rather than a top-level definition of the syntax object because top-level bindings are special. See this bit from namespace-syntax-introduce:

The additional context is overridden by any existing top-level bindings in the syntax object’s lexical information

You can get similar behavior inside of a module:

#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!
like image 168
Asumu Takikawa Avatar answered Oct 23 '22 02:10

Asumu Takikawa