Why does this not evaluate in Scheme?

元气小坏坏 提交于 2021-01-28 05:40:48

问题


I am using the DrRacket environment to try out the Scheme language.

I defined sum+1 as follows:

(define sum+1 '(+ x y 1))

I was wondering why the following expression does not evaluate:

(let ([x 1] [y 2]) (eval sum+1))

whereas doing this returns the correct value:

(define x 1)
(define y 2)
(eval sum+1)

回答1:


eval does not work with lexical variables at all unless the lexical variable was created in the same expression:

#!r7rs 
(import (scheme base)
        (scheme eval))

(define env (environment '(scheme base)))

(let ((x 10))
  (eval 'x env)) ; ERROR! `x` is not defined

You can think of it as eval always happening top level with the global bindings of the environment you pass to the second argument. You can perhaps trick it by passing values from your lexical environment like this:

(eval '(let ((x 10))
         x)
      env) ; ==> 10


(let ((x 10))
  (eval `(let ((x ,x))
           x)
        env) ; ==> 10

By the time most Scheme implementations run code local variables are usually stack allocated. Thus something imagine this code:

(define (test v)
  (display v)
  (newline)
  (eval 'v))

Might turn into this at runtime:

(define (test 1 #f) ; indicates 1 argument, no rest
  (display (ref 0)) ; fetches first argument from stack
  (newline)
  (eval 'v))        ; but what is v?, certainly not the first argument

Also you can make corner cases. What happens if you mutate?

(define (test v)
  (eval '(set! v 10))
  v)

The structure to eval might come from user input so it's not obvious that v gets mutated, also many compiling Scheme implementations need to treat variables that mutate differently so it needs to know before the code runs that v needs special treatment, but it is not decidable because the (set! v 10) might come from the database or user input. Thus by not including local bindings you save yourself a lot of trouble and the language gets easier to optimize and compile.

There are lisp languages that can only be interpreted since it allows for passing macros as first class objects. These languages are impossible to reason about at compile time.




回答2:


The reason that the command with let does not work is that let creates local variables. This means that the variables it creates can NOT be accessed from just anywhere - only from within let's body argument.

In your example, you defined:

(define sum+1 '(+ x y 1))

Then you commanded this:

(let ([x 1] [y 2]) (eval sum+1))

This doesn't work because x and y are only being defined in the eval statement, not within the procedure sum+1. This may seem counter-intuitive, but it prevents many errors with other inputs.

Your second example was:

(define x 1)
(define y 2)
(eval sum+1)

This does works because x and y are defined globally. This means that they CAN be accessed anywhere, and by anything. They are then applied to the sum+1 definition and are able to be printed. Please respond with any questions or feedback you have!



来源:https://stackoverflow.com/questions/46415909/why-does-this-not-evaluate-in-scheme

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!