背景:几周前,我正在使用 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 1
或and
的附加行不会切回输出。因此,如果序列为or
+
and
or
,则输出为+
。似乎,一旦我将6 3 3 3
或or
传递给and
,该函数就会被永久“卡住”,并以此作为参数。(my-reduce)
或and
传递给内置or
函数会导致类型错误,因为从技术上讲它们是宏而不是函数。(reduce)
换成or
会产生预期的输出。因此,这里的关键似乎是将宏传递给我的本地化reduce函数会导致问题。 问题:这是怎么回事?为什么用(lambda (x y) (or x y))
或(my-reduce)
调用and
会导致这种意外行为?这些“功能”实际上是宏,这与事实有关吗?
在此先感谢您的帮助。这真的让我难过!
答案 0 :(得分:3)
您自己说过的话,不能将and
,or
作为期望函数的参数,因为它们是宏,并且会抱怨“错误的语法”错误。实际上,我什至不知道这对您如何起作用:
(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)))))