在 Scheme (SCM) 中定义过滤器函数的结果末尾获取 #f 或 False
Getting #f or False at end of result from Define Filter function in Scheme (SCM)
我正在写 SICP 书。我在 Windows 上使用 SCM 而不是实际的 Scheme 程序。当我 运行 下面的过滤器函数时,我得到 (1 3 5 . #f),如下面的代码 window 所示。我不明白点和假值是如何附加到奇数的。
(define (filter odd? lst)
(cond ((null? lst) nil)
((odd? (car lst))
(cons (car lst)
(filter odd? (cdr lst))))
(else (filter odd? (cdr lst)))))
(filter odd? (list 1 2 3 4 5))
(1 3 5 . #f)
我希望得到 (1 3 5) 作为结果而不是 (1 3 5 . #f)。
当出现我不理解的行为时,我将调试输出添加到程序中。当您说:
时会发生什么
(define (filter odd? lst)
(display lst) (newline)
(cond ((null? lst) (display "1") (newline) nil)
((odd? (car lst))
(display "2") (newline)
(cons (car lst)
(filter odd? (cdr lst))))
(else (display "3") (newline)
(filter odd? (cdr lst)))))
您将看到在每次递归调用时传递的参数,并且您将知道在每次递归调用时选择了 cond
的哪个分支。这通常会告诉我问题所在。
我认为问题在于以下行:
(cond ((null? lst) nil)
和 nil
的值。根据本书的方案,我相信 nil
等同于空列表 '()
。我怀疑 SCM 认为 nil
等同于 false,#f
。因此,如果将 nil
替换为 '()
,您可能会得到预期的结果。
nil
不是今天定义顶级绑定的 Scheme 报告。如果它存在于实现中,它可以是任何值,因此您不能依赖它。 SICP 使用比 R4RS 更早的 Scheme 版本,因此今天没有现代实现可以完全支持它。我使用 DrRacket since it supports many of the report languages, has a nice debugger and IDE, and the chances of syntax errors is lessened by the fact it indents the code while writing. It has a SICP compatibilty language 这样 SICP 代码就可以工作而不必跳过太多的环节。
从历史上看,Scheme 来自 Lisp,而 Lisp 不区分空列表和假值。 Scheme 引入了 #t
和 #f
但保留了空列表被认为是错误的事实,直到他们改变它,以便只有 #f
是错误的,其他一切都被认为是真实的。 nil
在早期报告中是对 ()
的绑定,因此可能是 SCM 在进行更改时将其更改为 #f
,因为 CL 经常使用 nil
作为假值,并且()
对于空列表,即使它们只是相同值的两种表示形式。
许多实现在它们符合的报告之上引入了它们自己的绑定。使用它们会使您锁定它们的风格,因此最好的办法是保持代码标准。与其他实现相比,DrRacket 以非常严格的方式解释报告,因此用 DrRacket 编写的 R6RS 程序很可能 运行 而不会更改其他 R6RS 兼容实现。这样的标准很酷!
我正在写 SICP 书。我在 Windows 上使用 SCM 而不是实际的 Scheme 程序。当我 运行 下面的过滤器函数时,我得到 (1 3 5 . #f),如下面的代码 window 所示。我不明白点和假值是如何附加到奇数的。
(define (filter odd? lst)
(cond ((null? lst) nil)
((odd? (car lst))
(cons (car lst)
(filter odd? (cdr lst))))
(else (filter odd? (cdr lst)))))
(filter odd? (list 1 2 3 4 5))
(1 3 5 . #f)
我希望得到 (1 3 5) 作为结果而不是 (1 3 5 . #f)。
当出现我不理解的行为时,我将调试输出添加到程序中。当您说:
时会发生什么(define (filter odd? lst)
(display lst) (newline)
(cond ((null? lst) (display "1") (newline) nil)
((odd? (car lst))
(display "2") (newline)
(cons (car lst)
(filter odd? (cdr lst))))
(else (display "3") (newline)
(filter odd? (cdr lst)))))
您将看到在每次递归调用时传递的参数,并且您将知道在每次递归调用时选择了 cond
的哪个分支。这通常会告诉我问题所在。
我认为问题在于以下行:
(cond ((null? lst) nil)
和 nil
的值。根据本书的方案,我相信 nil
等同于空列表 '()
。我怀疑 SCM 认为 nil
等同于 false,#f
。因此,如果将 nil
替换为 '()
,您可能会得到预期的结果。
nil
不是今天定义顶级绑定的 Scheme 报告。如果它存在于实现中,它可以是任何值,因此您不能依赖它。 SICP 使用比 R4RS 更早的 Scheme 版本,因此今天没有现代实现可以完全支持它。我使用 DrRacket since it supports many of the report languages, has a nice debugger and IDE, and the chances of syntax errors is lessened by the fact it indents the code while writing. It has a SICP compatibilty language 这样 SICP 代码就可以工作而不必跳过太多的环节。
从历史上看,Scheme 来自 Lisp,而 Lisp 不区分空列表和假值。 Scheme 引入了 #t
和 #f
但保留了空列表被认为是错误的事实,直到他们改变它,以便只有 #f
是错误的,其他一切都被认为是真实的。 nil
在早期报告中是对 ()
的绑定,因此可能是 SCM 在进行更改时将其更改为 #f
,因为 CL 经常使用 nil
作为假值,并且()
对于空列表,即使它们只是相同值的两种表示形式。
许多实现在它们符合的报告之上引入了它们自己的绑定。使用它们会使您锁定它们的风格,因此最好的办法是保持代码标准。与其他实现相比,DrRacket 以非常严格的方式解释报告,因此用 DrRacket 编写的 R6RS 程序很可能 运行 而不会更改其他 R6RS 兼容实现。这样的标准很酷!