为什么我不能在 Scheme 的这个 let 语句中使用 car?
Why can't I use car inside this let statement in Scheme?
以下方案代码工作正常:
(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(cond ((null? numbers-left) nil)
((check-parity (car numbers-left)) (cons (car numbers-left) (iter (cdr numbers-left))))
(else (iter (cdr numbers-left)))))
(cons x (iter numbers-input)))
假设输出一个列表,第一个元素是整数x,后面的元素是numbers-input中与x具有相同奇偶校验的所有整数。
如果有人感兴趣,这是我尝试解决 Structure and Interpretation of Computer Programs 书中的练习 2.20。
现在,我想用变量 "first" 和 "rest".
替换 (car numbers-left) 和 (cdr numbers-left)
(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(let ((first (car numbers-left))
(rest (cdr numbers-left)))
(cond ((null? numbers-left) nil)
((check-parity first) (cons first (iter rest)))
(else (iter rest)))))
(cons x (iter numbers-input)))
现在尝试调用此函数时出现错误:
> (same-parity 1 2 3 4 5)
. . mcar: contract violation
expected: mpair?
given: ()
Racket 突出显示了 let 语句中的 (car numbers-left)。即使我从未真正在函数体中调用 "first" 或 "rest" 并保持原样,我也会遇到同样的错误。
但是,在下面的代码中,我尝试在一个简单的测试定义中复制上述过程的结构,令人惊讶的是,这正如您所期望的那样有效。
(define (test x . testlist)
(define (test2 test2list)
(let ((first (car test2list)))
first))
(test2 testlist))
> (test 1 2 3 4 5)
2
事实证明,如果我用一个简单的调用替换原始程序中的 (cond ...),它也可以正常工作,所以 (cond ...) 语句以某种方式禁止我使用变量。
我知道这是一件非常具体的事情,我不知道这是否真的很重要(除非你想让代码更具可读性)但我真的很想知道为什么它会这样.
如有任何见解,我们将不胜感激!
变量的值在您定义它们后立即计算,无论您是否使用它们。因此,一旦列表变空,您就会在递归结束时调用 (car '())
。您永远无法到达 cond
试图退出的部分。
以下方案代码工作正常:
(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(cond ((null? numbers-left) nil)
((check-parity (car numbers-left)) (cons (car numbers-left) (iter (cdr numbers-left))))
(else (iter (cdr numbers-left)))))
(cons x (iter numbers-input)))
假设输出一个列表,第一个元素是整数x,后面的元素是numbers-input中与x具有相同奇偶校验的所有整数。
如果有人感兴趣,这是我尝试解决 Structure and Interpretation of Computer Programs 书中的练习 2.20。
现在,我想用变量 "first" 和 "rest".
替换 (car numbers-left) 和 (cdr numbers-left)(define (same-parity x . numbers-input)
(define (check-parity a) (= (remainder x 2) (remainder a 2)))
(define (iter numbers-left)
(let ((first (car numbers-left))
(rest (cdr numbers-left)))
(cond ((null? numbers-left) nil)
((check-parity first) (cons first (iter rest)))
(else (iter rest)))))
(cons x (iter numbers-input)))
现在尝试调用此函数时出现错误:
> (same-parity 1 2 3 4 5)
. . mcar: contract violation
expected: mpair?
given: ()
Racket 突出显示了 let 语句中的 (car numbers-left)。即使我从未真正在函数体中调用 "first" 或 "rest" 并保持原样,我也会遇到同样的错误。
但是,在下面的代码中,我尝试在一个简单的测试定义中复制上述过程的结构,令人惊讶的是,这正如您所期望的那样有效。
(define (test x . testlist)
(define (test2 test2list)
(let ((first (car test2list)))
first))
(test2 testlist))
> (test 1 2 3 4 5)
2
事实证明,如果我用一个简单的调用替换原始程序中的 (cond ...),它也可以正常工作,所以 (cond ...) 语句以某种方式禁止我使用变量。
我知道这是一件非常具体的事情,我不知道这是否真的很重要(除非你想让代码更具可读性)但我真的很想知道为什么它会这样.
如有任何见解,我们将不胜感激!
变量的值在您定义它们后立即计算,无论您是否使用它们。因此,一旦列表变空,您就会在递归结束时调用 (car '())
。您永远无法到达 cond
试图退出的部分。