控制计划评估(guile)

时间:2011-07-08 23:11:31

标签: scheme eval quote guile

这似乎是一个简单的问题;也许它很简单,很难找到能找到答案的搜索。在Scheme(特别是Guile实现,如果这有任何区别)我如何评估被引用的内容?

这就是我想要做的事情。

我基本上需要确保我定义的函数以特定顺序评估其参数,因为在评估其他参数期间,评估一个参数所引起的副作用是依赖的。但是,Scheme表示可以按任何顺序计算参数,因此我想通过引用参数手动强制它,然后按所需的顺序手动评估它们。

似乎“eval”假设做我想做的事,但它有两个问题:

  1. 不鼓励使用它,所以我觉得应该有更好的方法来完成我想要做的事情。
  2. 在Scheme中,似乎eval采用第二个参数,即环境。这对我来说很困惑。我希望它在声明出现的相同环境中进行评估,那么为什么我需要第二个参数呢?这甚至可能吗?我玩了一点eval,似乎有些实现需要不同的参数(例如,mit-scheme甚至不知道什么(交互环境)!)
  3. 我尝试过其他技巧,比如建立一个lambda:

    (list 'lambda '() '(car (b c)))
    

    但似乎必须对此进行评估以生成程序。 我也尝试过:

    (list lambda '() '(car (b c)))
    

    但是这会返回一个“原始内置宏”,它也不起作用。

    编辑: 看起来宏将用于控制评估顺序:     (defmacro test1(a b)`(begin,b,a))

3 个答案:

答案 0 :(得分:8)

eval完全是改变参数评估顺序的错误工具。改为创建一个宏:

;; (my-fun e1 e2)
;; Just calls my-real-fun, but evaluates e2 before e1
(define-syntax my-fun
  (syntax-rules ()
    [(my-fun e1 e2)
     ;; let* has guaranteed order of evaluation
     (let* ([y e2]
            [x e1])
       (my-real-fun x y))]))

(define (my-real-fun x y) ....)

如果必须,请使用defmacro

答案 1 :(得分:2)

如果您需要评估列表结构(带有代表Scheme程序文本的带引号的符号的嵌套列表),那么您应该使用eval。 Scheme需要将环境作为第二个参数传递,即使它是当前环境:

(eval '(+ x y) (interaction-environment))

如果您只需要按特定顺序进行计算,则可以使用beginlet或仅使用函数体强制执行副作用的评估顺序。他们定义了一系列评估:

(let ((x 42))
  ; eval with effects #1
  (display x)
  ; eval with effects #2
  (display (+ x 1)))

编辑:如果您需要一个参数化的代码块,您可以在其中传递未评估的表达式,然后按特定顺序强制进行评估,那么您可以使用以下技术之一:

  • 宏(正如您已经提到的那样,只是为了完整性):

    > (defmacro test1 (a b) `(begin ,b ,a))
    > (test1 (display 2) (display 3)
    32
    
  • 延迟计算(Scheme的延迟评估特殊语法):

    > (define (test1 a b) (begin (force b) (force a)))
    > (test1 (delay (display 2)) (delay (display 3)))
    32
    
  • 常规的lambda抽象和应用

    > (define (test1 a b) (begin (b) (a)))
    > (test1 (lambda () (display 2)) (lambda () (display 3)))
    32
    

答案 2 :(得分:0)

你在传递lambda的过程中走在了正确的轨道上。如果你有

(define (f x y z) ...)

...然后你可以这样称呼它:

(f
  (lambda () a)
  (lambda () b)
  (lambda () c))

这将以未评估的形式调用f所有参数(abc)。在f内,您可以完全选择评估它们的顺序。唯一的区别是您必须明确调用(x)(y)(z),并在definelet之内捕获它们的值。这样可以确保副作用只发生一次。

根本不需要宏。顺便说一下,不要担心到处都有很多lambdas,它们非常便宜。