Search code examples
lispcdr

Why does element retrieving using car and cdr operations cause exception while (append) is not?


Suppose I got this code segment:

(defparameter *islands* '((1 9 8 5) (6 4 2 3)))

(defun edge-pair (a b)
  (unless (eql a b)
    (list (cons a b) (cons b a))))

(defun connected-with-bridges (islands)
  (when (cdr islands)
    (append (edge-pair (caar islands) (caadr islands))
            (connected-with-bridges (cdr islands)))))

Now, if I pass in the interpreter (SBCL):

(connected-with-bridges '((1 9 8 5) (6 4 2 3)))

The result is:

((1 . 6) (6 . 1))

It won't crash. However, if I pass in:

;; '(6 4 2 3) is actually (cdr '((1 9 8 5) (6 4 2 3)))
(caar '(6 4 2 3)) 

It will crash. According to (connected-with-bridges) function, the cdr of the list *islands* will be kept passing in until it can not longer proceed. The first time when *islands* is passed into (connected-with-bridges), the list will be '((1 9 8 5) (6 4 2 3). However, as the recursion goes, the 2nd time will be '(6 4 2 3), which in the (append) function, it will have:

(append (edge-pair (caar '(6 4 2 3)) (caadr '(6 4 2 3)))
                (connected-with-bridges (cdr islands)))

It obviously is crashed if I run it alone in the interpreter, but not with if it is ran inside (append), which is inside (connected-with-bridges).


Solution

  • (caar '(6 4 2 3)) signals an error cause you are trying to do (car 6), and 6 is not a list.

    Inside your function, you dont have (caar '(6 4 2 3)), but(caar '((6 4 2 3))).

    Look how cdr works: (cdr '((1 9 8 5) (6 4 2 3)))) => '((6 4 2 3)), not '(6 4 2 3) So... (caar '((6 4 2 3))) => 6, and (car '(6 4 2 3)) => 6

    Do you see your mistake?