6

这似乎是一个简单的问题;也许它是如此简单,以至于很难找到可以找到答案的搜索。在 Scheme 中(特别是 Guile 实现,如果这有什么不同的话)我如何评估已引用的内容?

这就是我想要做的。

我基本上需要确保我定义的函数按特定顺序评估其参数,因为评估一个参数引起的副作用取决于评估其他参数的过程。但是,Scheme 说参数可以按任何顺序进行评估,所以我想通过引用参数来手动强制它,然后按需要的顺序手动评估它们。

看来“eval”应该做我想做的事,但它有两个问题:

  1. 不鼓励使用它,所以我觉得应该有更好的方法来完成我想要在这里做的事情。
  2. 在 Scheme 中,eval 似乎采用了第二个参数,即环境。这让我很困惑。我希望它在语句出现的同一环境中进行评估,那么为什么我需要第二个参数?这甚至可能吗?我玩过 eval ,似乎有些实现需要不同的参数(例如 mit-scheme 甚至不知道 (interaction-environment) 是什么!!!)

我尝试了其他技巧,例如构建 lambda:

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

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

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

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

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

4

3 回答 3

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,如果你必须。

于 2011-07-09T00:54:46.933 回答
3

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

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

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

(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
    
于 2011-07-09T00:02:34.873 回答
0

通过传入 lambda,您走在了正确的轨道上。如果你有

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

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

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

这将以未评估的形式调用f所有参数 ( a, b, )。c在内部f,您完全有权选择评估它们的顺序。唯一的区别是您必须显式调用(x),(y)和, 并在or -like 语句中(z)捕获它们的值。这使您可以确保副作用只发生一次。definelet

这里根本不需要宏。顺便说一句,不用担心到处使用大量的 lambda,它们非常便宜。

于 2014-01-28T04:46:21.950 回答