【问题标题】:controlling evaluation in scheme (guile)控制方案中的评估(诡计)
【发布时间】:2011-10-01 16:02:31
【问题描述】:

这似乎是一个简单的问题;也许它是如此简单,以至于很难找到可以找到答案的搜索。在 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 (a b) `(begin ,b ,a))

【问题讨论】:

    标签: scheme eval quote guile


    【解决方案1】:

    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

    【讨论】:

      【解决方案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
        
      • 延迟计算(用于惰性求值的方案的特殊语法):

        > (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
        

      【讨论】:

      • 如果我需要可变数量的参数,宏如何工作? (defmacro test1 (a . b) `(begin ,b ,a)) 不起作用,因为 b 现在是一个列表。我需要以某种方式将其拼接到开头,但诸如`(begin (if (pair? ,b) (test1 ,b)) ,a)) 之类的各种尝试都不起作用。
      • 另外,我不能使用(defmacro test1 (a . b) `(begin (apply begin ,b) ,a)) ,因为我不能应用宏。
      • 你错过的是(defmacro test1 (a . b) `(begin ,(cons 'begin b) ,a))
      【解决方案3】:

      您在传递 lambdas 时走在了正确的轨道上。如果你有

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

      ...那么你可以这样称呼它:

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

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

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

      【讨论】:

        猜你喜欢
        • 2021-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-30
        相关资源
        最近更新 更多