方案中的控制评估(guiile)

发布于 2024-11-19 16:36:40 字数 740 浏览 3 评论 0原文

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

这就是我正在尝试做的事情。

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

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

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

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

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

但似乎必须对其进行评估才能生成过程。 我也尝试过:

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

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

编辑: 看起来宏可以用于控制求值顺序: (defmacro test1 (ab) `(开始,b,a))

This seems like a simple question; perhaps it is so simple that it is difficult to find a search that will find the answer. In Scheme (specifically, the Guile implementation if that makes any difference) how do I evaluate something that has been quoted?

Here's what I'm trying to do.

I basically need to ensure that a function I define gets its arguments evaluated in a specific order, because side effects caused by evaluating one argument are depended on during the evaluation of other arguments. However, Scheme says arguments can be evaluated in any order, so I want to manually force it by quoting the arguments and then manually evaluating them in the order that is needed.

It appears that "eval" is supposed to do what I want, but it has two problems:

  1. Its use is discouraged, so I feel like there should be a better way to accomplish what I want to do here.
  2. In Scheme it appears that eval takes a second parameter which is the environment. This is confusing to me. I want it to eval in the same environment the statement appears in, so why I should need a second parameter? Is this even possible? I've played with eval a bit and it appears that some implementations requires different parameters (e.g. mit-scheme doesn't even know what (interaction-environment) is!!!)

I've tried other tricks, like building up a lambda:

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

but it appears that this would then have to be evaluated to generate a procedure.
I also tried:

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

but this returns a "primitive-builtin-macro" which doesn't work either.

Edit:
Looks like a macro will work for controlling order of evaluation:
(defmacro test1 (a b) `(begin ,b ,a))

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

魂牵梦绕锁你心扉 2024-11-26 16:36:40

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

eval is utterly the wrong tool for just changing the order of evaluation of arguments. Create a macro instead:

;; (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) ....)

Or use defmacro, if you must.

昵称有卵用 2024-11-26 16:36:40

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

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

如果您只需要按特定顺序进行计算,则可以使用 beginlet,或者只是一个函数体。它们定义了一系列求值:

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

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

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

    <前><代码>> (defmacro test1 (ab) `(开始,b,a))
    > (测试1 (显示2) (显示3)
    32

  • 延迟计算(Scheme 用于延迟计算的特殊语法):

    <前><代码>> (定义(test1 ab)(开始(力b)(力a)))
    > (测试1 (延迟(显示2)) (延迟(显示3)))
    32

  • 常规 lambda 抽象和应用

    <前><代码>> (定义(test1 ab)(开始(b)(a)))
    > (test1 (lambda () (显示 2)) (lambda () (显示 3)))
    32

If you need to evaluate a list structure (nested lists with quoted symbols that represent a Scheme program text), then you should use eval. Scheme requires passing an environment as a second argument, even if it is the current environment:

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

If you just need to do your calculations in a particular order, you can enforce the order of evaluation for side effects by using begin, let, or just a function body. They define a sequence of evaluations:

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

Edit: If you need to have a parametrized block of code where you can pass expressions unevaluated and then force their evaluation in some particular order, then you may use one of these techniques:

  • A macro (as you've mentioned already, just for completeness):

    > (defmacro test1 (a b) `(begin ,b ,a))
    > (test1 (display 2) (display 3)
    32
    
  • A delayed computation (Scheme's special syntax for lazy evaluation):

    > (define (test1 a b) (begin (force b) (force a)))
    > (test1 (delay (display 2)) (delay (display 3)))
    32
    
  • A regular lambda abstraction and application

    > (define (test1 a b) (begin (b) (a)))
    > (test1 (lambda () (display 2)) (lambda () (display 3)))
    32
    
提赋 2024-11-26 16:36:40

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

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

...那么你可以像这样调用它:

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

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

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

You were on the right track with passing in lambdas. If you have

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

... then you can call it like so:

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

This will call f with all arguments (a, b, c) in an unevaluated form. Inside f, you have complete power to choose the order you evaluate them. The only difference is that you have to explicitly call (x), (y) and (z), and capture their values inside define or let-like statements. This lets you ensure that the side effects happen only once.

No need for macros here at all. Btw, don't worry about using lots of lambdas everywhere, they are very cheap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文