【问题标题】:Why does calling my home-rolled (reduce) function with a macro affect future calls to the function?为什么用宏调用我的 home-rolled (reduce) 函数会影响未来对该函数的调用?
【发布时间】:2019-02-08 02:33:48
【问题描述】:

背景: 几周前我在 guile 1.8.8 方案中做一个项目,有点生疏,我忘记了内置的 @ 987654321@ 函数,所以我自己滚动。不久之后,我遇到了一个看似无望的错误,在该错误中调用没有副作用的函数会改变程序其余部分的流程(正常工作并通过一些单元测试与完全崩溃)早就回来了。以前返回 (A B C D) 之类的几段代码现在只返回 (A),导致许多问题。

最小工作示例:经过几天的精简,我将问题集中到了这段独立的代码中:

(define (my-reduce fun ls)
    (if (null? (cdr ls))
        (car ls)
        (my-reduce fun (cons (fun (car ls) (cadr ls))
                             (cddr ls)))))

(format #t "~a "  (my-reduce +   '(1 2 3)))
(format #t "~a "  (my-reduce or  '(1 2 3)))
(format #t "~a~%" (my-reduce +   '(1 2 3)))

打印出6 1 1,而不是预期的6 1 6

补充意见:

  • 将第二行设置为 + 会产生预期的 6 6 6
  • 将第二行设置为and 会产生6 3 3
  • + 之后的附加行会产生附加的1s 或3s,具体取决于第二行的设置。所以,序列+or++导致输出6 1 1 1
  • andor 在第一行之后的附加行不会切换回输出。因此,如果序列为+andor+,则输出为6 3 3 3。似乎,一旦我将orand 传递给(my-reduce),函数就会以它作为参数永久“卡住”。
  • 我还注意到,将 andor 传递给内置的 (reduce) 函数会导致类型错误,因为它们在技术上是宏而不是函数。
  • 按照同样的思路,我注意到将or 换成(lambda (x y) (or x y)) 会产生预期的输出。因此,这里的关键似乎是将宏传递给我自制的 reduce 函数会导致问题。

问题:这是怎么回事?为什么用andor 调用(my-reduce) 会导致这种意外行为?这与那些“函数”实际上是宏这一事实有关吗?

提前感谢您的帮助。这个真的把我难住了!

【问题讨论】:

    标签: macros scheme guile


    【解决方案1】:

    您自己说过,您不能将 andor 作为参数传递给预期的函数,因为它们是 ,并且会抱怨“语法错误”错误.事实上,我什至无法理解这对你有什么作用:

    (my-reduce or '(1 2 3))
    

    我能想到的唯一方法是您在某处将andor 重新定义为函数,而 是问题的根源。附带说明一下,my-reduce(理解为右折叠操作)可以以更标准的方式实现,如下所示:

    (define (my-reduce fun ls)
      (if (null? (cdr ls))
          (car ls)
          (fun (car ls)
               (my-reduce fun (cdr ls)))))
    

    上面假设列表是非空的,如果不是总是这样,通常是传递一个初始值作为参数:

    (define (my-reduce fun init ls)
      (if (null? ls)
          init
          (fun (car ls)
               (my-reduce fun init (cdr ls)))))
    

    【讨论】:

    • 感谢您的回答。我将my-reduce 实现为左关联,因为根据this 页面,似乎只有右关联的一个被明确标记为标准。是的,我知道它假定了一个非空列表,这有点像 hack,因为我知道我永远不会通过一个空列表。
    • 现在,一个澄清问题:你是说在预期函数的地方传递一个宏会产生未定义的行为吗?如果是这样,您能否链接相关文档?否则,我认为我不能给这个绿色检查,因为它没有完全回答“为什么用 and 或 or 调用 (my-reduce) 会导致这种意外行为?”
    • (另外,我没有重新定义 andor,我运行的代码与 MWE 中显示的完全一样。它在您的实现中崩溃了吗?这似乎指向这是未定义的行为。)
    • 在我的解释器 (DrRacket) 中,my-reduce 在执行之前失败,当它检测到 or 作为参数传递时。它甚至从不打印1。我的观点:你的 my-reduce 没有任何问题(除了一个奇怪的实现,它不应该创建一个列表)。
    • 您发布的代码中没有任何内容解释了为什么调用之间的结果会发生变化,我什至在 Guile 中对其进行了测试,不出所料,当我尝试将 or 作为参数传递时出现错误:"source expression failed to match any pattern in form or"。因此,您的环境肯定有一些不同的东西,这使得问题无法重现。
    猜你喜欢
    • 1970-01-01
    • 2020-01-05
    • 1970-01-01
    • 2014-11-21
    • 2020-10-22
    • 1970-01-01
    • 2014-04-02
    • 2021-04-16
    相关资源
    最近更新 更多