1

Paul Graham's 'On Lisp' errata page states:

p. 23. our-find-if would recurse infinitely if no element matches. Caught by Markus Triska.

The function definition as shown in the book is:

(defun our-find-if (fn lst)
    (if (funcall fn (car lst))
        (car lst)
        (our-find-if fn (cdr lst))))

And here is my probably poor fix for it:

(defun our-find-if (fn lst)
    (if (funcall fn (car lst))
        (car lst)
        (if (cdr lst)
            (our-find-if fn (cdr  lst))
            nil)))

Is this correct? Is my version of 'our-find-if' still tail recursive? (I think so...)

Better alternatives welcome.

TIA

AndRAM
  • 155
  • 1
  • 10

1 Answers1

3

It is OK, and it is tail recursive.

I would propose the following changes, though:

  • use standard indentation (2 spaces for a body)
  • use cond instead of nested ifs
  • use non-abbreviated variable names, and predicate for a function that returns a boolean
  • use endp to test for the end of the list

update: first test for end of list, thanks to Paulo Madeira

It looks like this then:

(defun our-find-if (predicate list)
  (cond ((endp list)
         nil)
        ((funcall predicate (car list))
         (car list))
        (t
         (our-find-if predicate (cdr list)))))
Svante
  • 50,694
  • 11
  • 78
  • 122
  • 3
    Actually, you should test for the end of the list first, otherwise `predicate` will be called with `nil` for an empty list, which it seems is not the purpose, e.g. `(our-find-if 'evenp '())` will signal an error. – acelent Aug 12 '14 at 14:50
  • I understand you're referring to my own version so it was not really OK. In my discharge I must say this flaw was already present in Graham's one :-) – AndRAM Aug 13 '14 at 09:50