方案:附加到本地环境

Scheme: append to local environment

比如说,我想通过定义对象符号然后将方法和字段附加到该对象来在 Scheme 中实现 "declarative" 对象系统。在这样做的同时,我想利用这个对象的本地环境来正确绑定它在方法中的字段(稍后添加),例如(一个非常 "hacked-together" 的例子):

(define myobj 
(begin
    (define x 5) ; some local field (hard-coded for example)
    (define (dispatch m d)
        (cond ((eq? m 'add-meth) (define localmethod1 d))
              ((eq? m 'inv-meth) (localmethod1 d))))
    dispatch
))
(myobj 'add-meth (lambda (y) (+ y x)) ;want this to bind to x of myobj
(myobj 'inv-meth 3) ;8

不要介意愚蠢的调度机制和硬编码 "localmethod1" :) 另外请注意,在调度程序定义期间 x 可能不可用。 首先,我在使用 define in define 时遇到问题(Bad define placement)。
然后:如何确保 lambda 中的 x 绑定到正确的那个(myobj 内部)而不是全局环境中的某个 x?
最后:有没有办法改变这样的本地环境(闭包,对吧?)?

EDIT2:我知道您可以使用 "fields" 和 "methods" 等本地列表进行此操作,然后由调度员更改这些列表。我想知道是否有可能改变本地环境(由调度 lambda 生成)。

Scheme中的

begin不产生本地环境。要引入局部变量,请使用 let。或者,定义一个对象,或者定义一个 class 来构造对象,作为 lambda 过程,它将充当构造函数。这将解决您的前两个问题。

变异:你可以通过正确的调度方法来变异。例如,

(define (make-object init-val)
  (define x init-val)
  (define (dispatch msg)
    (cond ((eq? msg 'inc)
           (lambda (y)
             (set! x (+ x y))))
          ((eq? msg 'x)
           x)
          (else
           (error "Unknown msg"))))
  dispatch)

> (define obj (make-object 10))
> (obj 'x)
10
> ((obj 'inc) 20)
> (obj 'x)
30

SICP, Chapter 3 提供了如何使用本地状态创建对象的好例子。

你是说:

x may not be available during definition of dispatcher

然后你在问:

Then: how to make sure that x in lambda binds to the right one (inside of myobj) and not to some x in global environment?

简短的回答是:你不能

原因是(参见Mit-Scheme manual的例子):

Scheme is a statically scoped language with block structure. In this respect, it is like Algol and Pascal, and unlike most other dialects of Lisp except for Common Lisp.

The fact that Scheme is statically scoped (rather than dynamically bound) means that the environment that is extended (and becomes current) when a procedure is called is the environment in which the procedure was created (i.e. in which the procedure's defining lambda expression was evaluated), not the environment in which the procedure is called. Because all the other Scheme binding expressions can be expressed in terms of procedures, this determines how all bindings behave.

(强调我的)