【问题标题】:Why can't I use car inside this let statement in Scheme?为什么我不能在 Scheme 的这个 let 语句中使用 car?
【发布时间】:2020-04-17 01:56:34
【问题描述】:

以下方案代码可以正常工作:

(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 语句中的(左车号)。即使我从来没有在函数体中真正调用过“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 ...) 语句以某种方式禁止我使用变量。

我知道这是一件非常具体的事情,我不知道这是否真的很重要(除非你想让代码更具可读性),但我真的很想知道它为什么会这样。

任何见解将不胜感激!

【问题讨论】:

    标签: list scheme racket sicp cons


    【解决方案1】:

    变量的值在您定义它们后立即被评估,无论您是否使用它们。因此,一旦列表变为空,您将在递归结束时调用(car '())。您永远不会到达您的cond 中尝试退出的部分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-30
      • 2013-09-22
      • 2023-01-30
      • 1970-01-01
      • 2010-09-21
      • 2012-06-15
      • 2019-10-06
      相关资源
      最近更新 更多