Search code examples
listrecursionschemelispsicp

SICP Lisp/Scheme - recursive return value gets lost


I'm writing a simple function that recursively checks if x (a list) is an element of remaining (list of lists).

Somehow, the #f return from innermost frame doesn't properly bubble up to the top:

#lang sicp

(define (was_seen? remaining x)
  (cond ((null? remaining) #false)
        ((eq? (car remaining) x) #true)
        ((was_seen? (cdr remaining) x))
  )
)


; test variables

(define seen (list(list 'a)))
(define z (list 0))


; now the test

(was_seen? seen z)
; expected: #f; returns blank (evaluated to #void when seen via debugger)


(was_seen? (cdr seen) z)
; expected: #f; returns #f as it should. 
; This is what the inner (recursive) call - correctly - evaluates to. 
; It's just that this #f doesn't get properly returned to the global caller?

It must be something stupid simple, but I cannot find what. Any help would be appreciated.


Solution

  • cond returns the value from the body of the first clause whose condition is truthy (i.e. not #f), or the value of the else clause if none of them are truthy.

    If none of the conditions are truthy, and there's no else clause, it returns #void.

    In your case, none of the conditions is ever true, since the recursive call is false.

    Change the last clause to be an else clause so the value of the recursive call will be returned.

    (define (was_seen? remaining x)
      (cond ((null? remaining) #false)
            ((eq? (car remaining) x) #true)
            (else (was_seen? (cdr remaining) x))
      )
    )
    

    You may think you were depending on the shortcut that the value of the condition is returned if there's no body in the clause. But that only happens when the condition is truthy, so that this is the clause that's going to return a value. It doesn't apply when the condition is false.