为什么用宏调用我的滚动(缩减)函数会影响以后对该函数的调用?

时间:2018-09-03 03:44:47

标签: macros scheme guile

背景:几周前,我正在使用 guile 1.8.8 方案开发一个项目,由于有点生疏,我忘记了内置的{ {1}}函数,所以我自己滚动了。过了一会儿,我遇到了一个看起来毫无希望的错误:在调用一个无副作用的函数后,程序的其余部分的流程发生了变化(正常工作并通过了一些单元测试,而完全崩溃)。很久以来回来了。以前曾经返回诸如(reduce)之类的几段代码现在仅返回(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行会根据第二行的设置产生另外的+1。因此,序列3 + or +导致输出+
  • 在第一行之后的6 1 1 1and的附加行不会切回输出。因此,如果序列为or + and or,则输出为+。似乎,一旦我将6 3 3 3or传递给and,该函数就会被永久“卡住”,并以此作为参数。
  • 我还注意到,将(my-reduce)and传递给内置or函数会导致类型错误,因为从技术上讲它们是宏而不是函数。
  • 沿着这些相同的行,我注意到将(reduce)换成or会产生预期的输出。因此,这里的关键似乎是将宏传递给我的本地化reduce函数会导致问题。

问题:这是怎么回事?为什么用(lambda (x y) (or x y))(my-reduce)调用and会导致这种意外行为?这些“功能”实际上是宏,这与事实有关吗?

在此先感谢您的帮助。这真的让我难过!

1 个答案:

答案 0 :(得分:3)

您自己说过的话,不能将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)))))