方案:附加到当地环境

时间:2016-01-18 13:42:21

标签: scheme lisp racket

说,我想实现"声明" Scheme中的对象系统,它定义了对象符号,然后将方法和字段附加到该对象。在这样做的时候,我想利用这个对象的本地环境来正确地绑定方法中的字段(稍后会添加),例如(一个非常"被黑客攻击的"示例):

(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绑定到正确的x(在myobj内部)而不是绑定到全局环境中的某些x? 上一篇:有没有办法改变这样的本地化(闭包,对吧?)?

EDIT2:我知道您可以使用本地列表,例如"字段"和"方法"然后由调度员改变它们。我想知道是否有可能改变本地环境(由调度lambda生成)。

2 个答案:

答案 0 :(得分:3)

Scheme中的

begin不会产生本地环境。要引入局部变量,请使用let。或者,或者定义一个对象,或者更确切地说是一个构造对象的类,作为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提供了如何使用本地状态创建对象的很好的例子。

答案 1 :(得分:1)

你在说:

  在调度员定义期间,

可能无法使用

然后你问:

  

然后:如何确保lambda中的x绑定到正确的x(在myobj内部)而不是绑定到全局环境中的某个x?

简短的回答是:你不能

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

  

Scheme是一种具有块结构的静态范围语言。在这方面,它就像Algol和Pascal,与Lisp的大多数其他方言不同,除了Common Lisp。

     

Scheme是静态作用域(而不是动态绑定)这一事实意味着在调用过程时扩展(并变为当前)的环境是创建过程的环境(即,在其中评估过程的定义lambda表达式),不是调用过程的环境。因为所有其他Scheme绑定表达式都可以用过程表示,所以这决定了所有绑定的行为方式。

(强调我的)