Scheme 加载定义值的文件会覆盖顶级绑定

Scheme 加载定义值的文件会覆盖顶级绑定,scheme,Scheme,如果我有一个文件test.scm: (define foo 5) 然后使用REPL: (define foo 2) foo ==> 2 (define bar (lambda () (load "test.scm") foo)) foo ==> 2 (bar) ==> 5 foo ==> 5 换句话说,在一个词法上下文中加载文件允许绑定转义到顶层。为什么会这样?是否有办法按照C#include包含另一个文件,即执行命令,就好像它们在该点被

如果我有一个文件test.scm:

(define foo 5)
然后使用REPL:

(define foo 2)

foo
==> 2

(define bar
  (lambda ()
    (load "test.scm")
    foo))

foo
==> 2

(bar)
==> 5

foo
==> 5
换句话说,在一个词法上下文中加载文件允许绑定转义到顶层。为什么会这样?是否有办法按照C
#include
包含另一个文件,即执行命令,就好像它们在该点被拼接到代码中一样?

请参见

环境(如果给定)是评估文件的环境;如果未给定,则使用当前的REPL环境

这意味着文件将直接计算到repl中,而不是lambda闭包中

编辑
请参阅有关如何创建新环境的问题。

如果由
load
执行的代码能够访问
load
表单的词法上下文,那么它就不是词法上下文

如果
load
是一个宏而不是一个函数,情况可能会有所不同,但即便如此,标准的R5RS宏也是卫生的,不容易与词汇上下文混淆

但是,您可以编写一个
defmacro
风格的宏,通过读取文件并返回一个
begin
表单,其中包含从文件读取的所有内容,来实现您的要求

示例代码:
请注意,
定义宏
是非标准的。您必须根据您的计划实施情况,确定是否以及如何使其发挥作用。

我仍然不确定如何实施“bar”程序。我应该把应该在新环境中执行的代码放在哪里?我应该怎么做?谢谢嗯,
define macro
defmacro
等都不在我的实现(MIT/GNU)中,所以我能做的最好的事情就是在
begin
表单的末尾附加任何代码,然后在顶级环境的克隆中对其求值。无论如何谢谢你@Arafinwe麻省理工学院/GNU计划已经完成,基本上是
defmacro
的超集。
procedure: load filename [environment [syntax-table [purify?]]]
(define-macro (include file)
  (let ((read-forms
         (lambda ()
           (let loop ((forms '()))
             (let ((form (read)))
               (if (eof-object? form)
                   (reverse forms)
                   (loop (cons form forms))))))))
    (with-input-from-file file
      (lambda ()
        (cons 'begin (read-forms))))))