如何在Scheme中的eval中使用外部变量?

时间:2010-10-02 03:06:50

标签: lisp scheme eval

我正在尝试一些有趣的方案。我正在尝试创建一个Area函数来获取它正在操作的东西的类型,然后根据对象的类型调用不同的函数。这是我的代码:

(define (area object)
  (if (not (null? (eval (word 'area- (get-type object)))))
      (eval (list (word 'area- (get-type object)) 'object))
      #f
  )
)

Scheme不喜欢这个,因为它说对象是一个未绑定的变量。不,我不能把报价拿走,因为它实际上是把值放在那里,然后Scheme抱怨列表格式不正确。

如何在eval中使用object中的值?

注意:Scheme显然抓住全局变量“object”就好了,所以它基本上忽略了它在函数内部。

相关语言的一些信息在这里:http://docs.racket-lang.org/guide/eval.html,这似乎表明Scheme中没有解决方案,但如果你知道我想听到的那个。

3 个答案:

答案 0 :(得分:3)

没有一个 - 这是一个功能。 eval正在评估在运行时动态生成的表单。因此,如果需要了解本地绑定,那么您需要以不同方式编译(lamba (x) x)(lambda (y) y) - 因为名称很重要。但这只是提示,实现这种功能存在很多问题。

至于你的问题 - 即使你可以做你想做的事情,这是一个脆弱的解决方案,取决于名称。请记住,在Scheme中,您可以像使用任何其他值一样使用函数 - 因此,不要调用get-type并将其与某个符号组合以获取名称,而是让您的对象包含所需的函数(此时将是更好地称为“方法”)。

类似的东西:

(define (area object)
  ((get-area-method object) object))

显然,这样做意味着没有一点不顺利:

(define (area object)
  (get-area object))

只是

(define area get-area)

但是第一个可能是更典型的类似OO的系统,有一种获取方法的方法,所以它可能对你有用。那个方向可以带你去:

(define (area object)
  ((get-method object 'get-area) object))

答案 1 :(得分:2)

球拍有classes and methods,您应该使用它!

(define circle%
  (class object%
    (init radius)
    (define r radius)
    (super-new)
    (define/public (area)
      (* pi r r))))

(define rectangle%
  (class object%
    (init width height)
    (define w width)
    (define h height)
    (super-new)
    (define/public (area)
      (* w h))))

(define unit-circle (new circle% [radius 1]))
(define unit-square (new rectangle% [width 1] [height 1]))

(send unit-circle area)   ; => 3.141592653589793
(send unit-square area)   ; => 1

很多比基于名称的派遣更少hacky。

答案 2 :(得分:0)

显然,有一种方法可以做我想在Scheme中做的事情。这是代码:

(define (area object)
  ((eval (list 'identity (word 'area- (get-type object)))) object)
)

基本上诀窍是:因为eval只知道全局变量,所以我仍然可以使用eval中的identity函数来返回全局变量的值。在这种情况下我感兴趣的全局变量是一个函数,就像任何其他变量一样。然后我可以返回此值并将其用作调用原始参数的过程。这允许我构造我想从全局范围获取的变量的名称,并获取并使用该变量中包含的过程,完成我正在寻找的结果。

这是一个更清洁的版本:

(define (area object)
  ((get-function (word 'area- (get-type object))) object)
)

(define (get-function function)
  (eval (list 'identity function)))

然而,显然is-not-null部分不起作用,因为尝试获取不存在的函数的标识会导致未绑定的变量错误。因此,仍然需要小心地在支持它的类型上调用操作符。