这似乎是一个简单的问题;也许它很简单,很难找到能找到答案的搜索。在Scheme(特别是Guile实现,如果这有任何区别)我如何评估被引用的内容?
这就是我想要做的事情。
我基本上需要确保我定义的函数以特定顺序评估其参数,因为在评估其他参数期间,评估一个参数所引起的副作用是依赖的。但是,Scheme表示可以按任何顺序计算参数,因此我想通过引用参数手动强制它,然后按所需的顺序手动评估它们。
似乎“eval”假设做我想做的事,但它有两个问题:
我尝试过其他技巧,比如建立一个lambda:
(list 'lambda '() '(car (b c)))
但似乎必须对此进行评估以生成程序。 我也尝试过:
(list lambda '() '(car (b c)))
但是这会返回一个“原始内置宏”,它也不起作用。
编辑: 看起来宏将用于控制评估顺序: (defmacro test1(a b)`(begin,b,a))
答案 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))
如果您只需要按特定顺序进行计算,则可以使用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
答案 2 :(得分:0)
你在传递lambda的过程中走在了正确的轨道上。如果你有
(define (f x y z) ...)
...然后你可以这样称呼它:
(f
(lambda () a)
(lambda () b)
(lambda () c))
这将以未评估的形式调用f
所有参数(a
,b
,c
)。在f
内,您可以完全选择评估它们的顺序。唯一的区别是您必须明确调用(x)
,(y)
和(z)
,并在define
或let
之内捕获它们的值。这样可以确保副作用只发生一次。
根本不需要宏。顺便说一下,不要担心到处都有很多lambdas,它们非常便宜。