为什么用宏调用我的自制(归约)函数会影响以后对该函数的调用?
Why does calling my home-rolled (reduce) function with a macro affect future calls to the function?
背景: 几周前,我在 guile 1.8.8 方案中从事一个项目,有点生疏,我忘记了内置的 (reduce)
功能,所以我推出了自己的功能。过了一会儿,我 运行 遇到了一个似乎无可救药的错误,其中调用一个没有副作用的函数改变了程序其余部分的流程(正常工作并通过一些单元测试与完全崩溃) AFTER 函数早已 returned。以前 return 类似 (A B C D)
的几段代码现在 return 只 (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
s 或 3
s。因此,序列 +
or
+
+
导致输出 6 1 1 1
.
- 第一行之后的
and
或 or
的附加行不要将输出切换回来。所以,如果序列是 +
and
or
+
,输出是 6 3 3 3
。似乎,一旦我将 or
或 and
传递给 (my-reduce)
,该函数就永久性地 "stuck" 将其作为参数。
- 我还注意到将
and
或 or
传递给内置 (reduce)
函数会导致类型错误,因为它们在技术上是宏而不是函数。
- 沿着相同的思路,我注意到将
or
换成 (lambda (x y) (or x y))
会产生预期的输出。因此,这里的关键似乎是将宏传递给我的自制 reduce 函数会导致问题。
问题:这是怎么回事?为什么用 and
或 or
调用 (my-reduce)
会导致这种意外行为?这与那些 "functions" 实际上是宏的事实有关吗?
在此先感谢您的帮助。这个真的难倒我了!
你自己说了,你不能将 and
、or
作为需要函数的参数传递,因为它们是 macros,并且会报 "bad syntax" 错误。事实上,我什至不明白这对你有什么用:
(my-reduce or '(1 2 3))
我能想到的唯一办法就是你把and
、or
重新定义为某处的函数,那个就是问题的根源。作为旁注,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)))))
背景: 几周前,我在 guile 1.8.8 方案中从事一个项目,有点生疏,我忘记了内置的 (reduce)
功能,所以我推出了自己的功能。过了一会儿,我 运行 遇到了一个似乎无可救药的错误,其中调用一个没有副作用的函数改变了程序其余部分的流程(正常工作并通过一些单元测试与完全崩溃) AFTER 函数早已 returned。以前 return 类似 (A B C D)
的几段代码现在 return 只 (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
s 或3
s。因此,序列+
or
+
+
导致输出6 1 1 1
. - 第一行之后的
and
或or
的附加行不要将输出切换回来。所以,如果序列是+
and
or
+
,输出是6 3 3 3
。似乎,一旦我将or
或and
传递给(my-reduce)
,该函数就永久性地 "stuck" 将其作为参数。 - 我还注意到将
and
或or
传递给内置(reduce)
函数会导致类型错误,因为它们在技术上是宏而不是函数。 - 沿着相同的思路,我注意到将
or
换成(lambda (x y) (or x y))
会产生预期的输出。因此,这里的关键似乎是将宏传递给我的自制 reduce 函数会导致问题。
问题:这是怎么回事?为什么用 and
或 or
调用 (my-reduce)
会导致这种意外行为?这与那些 "functions" 实际上是宏的事实有关吗?
在此先感谢您的帮助。这个真的难倒我了!
你自己说了,你不能将 and
、or
作为需要函数的参数传递,因为它们是 macros,并且会报 "bad syntax" 错误。事实上,我什至不明白这对你有什么用:
(my-reduce or '(1 2 3))
我能想到的唯一办法就是你把and
、or
重新定义为某处的函数,那个就是问题的根源。作为旁注,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)))))