简体   繁体   中英

Why can't I use car inside this let statement in Scheme?

The following Scheme code works fine:

(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)))

It is supposed to output a list with the first element being an integer x and the subsequent elements being all the integers from numbers-input which have the same parity as x.

If anyone is interested, this is my attempt at solving the exercise 2.20 from the book Structure and Interpretation of Computer Programs .

Now, I wanted to replace (car numbers-left) and (cdr numbers-left) with the variables "first" and "rest".

(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)))

Trying to call this function now gives me an error:

> (same-parity 1 2 3 4 5)
. . mcar: contract violation
  expected: mpair?
  given: ()

Racket is highlighting the (car numbers-left) inside of the let-statement. Even when I never actually call "first" or "rest" in the body of the function and just leave it the way it was before, I get the same error.

However, in the following code I tried to copy the structure of the above procedure in a simple test definition and surprisingly, this works as you would expect.

(define (test x . testlist)
  (define (test2 test2list)
    (let ((first (car test2list)))
      first))
  (test2 testlist))

> (test 1 2 3 4 5)
2

It turns out that if I replace my (cond...) in my original program with a simple call it works fine as well, so somehow the (cond...) statement prohibits me from using the variables.

I know this is a very specific thing and I don't know if this ever really matters (except maybe if you want to make the code more readable) but I would really like to know why exactly it behaves this way.

Any insight would be appreciated!

Variables' values are evaluated as soon as you define them, whether you use them or not. Therefore you are calling (car '()) at the end of your recursion, once the list has become empty. You never make it to the part of your cond that attempts to exit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM