Find minimum value in a BST: using boolean operators, and using conditionals I've been studying the BST code in Paul Graham's ANSI Common Lisp.

He provides (my comments):

(defun bst-min (bst)
  (and bst                               ; [3]
       (or (bst-min (node-l bst)) bst))) ; [4]

(defun bst-max (bst)
  (and bst                               ; [5]
       (or (bst-max (node-r bst)) bst))) ; [6]

;; [1] How do you find min and max of a bst?
;;     Recall, the core point is that all items in left subtree are lower,
;;     and all items in right subtree are higher, &amp; this holds for the whole
;;     tree, -otherwise binary search would miss-, and not just within a
;;     single parent child relationship.
;; [2] Therefore, to find min, we just need to go left until we can go left
;;     no more, &amp; that's the min. If the above property didn't hold, you
;;     might go left, then right, then left, and that final one there
;;     could be as low as you like; but no, it must be greater than its
;;     ancestor of which it is a right child.

;; [3] A null node has no min. The base case. Returns nil if bst is empty.
;; [4] For a non null node, the min is either the min of its left node, or
;;     if that's null, then it's this node, instead.
;; [5] A null node has no max. The base case. Returns nil if bst is empty.
;; [6] For a non null node, the max is either the max of its right node, or
;;     if that's null, then it's this node, instead.


I find this code more or less fine, but I still find it not easy to read or cognitively process.

I'm wondering whether that subjective fact is a feature of the code itself (i.e., is the code really hard to read), or whether it's something I need to stick with and then it will become very natural; remembering Hickey's advice about lisp that it is simple but not easy.

So, I produced this version by translating from a java implementation.
It's easier for me to read (currently).

(defun bst-min (bst)
  (if (null (node-l bst))
      bst
      (bst-min (node-l bst))))

(defun bst-max (bst)
  (if (null (node-r bst))
      bst
      (bst-max (node-r bst))))


Is the first version somehow a relic of former days?
Would anyone program like that now?

Question I would like to ask helpful peeps here is: which version would you favour and why?
The aspect of the code that may cause difficulty to those new to Lisp appears to be the fact that in Common Lisp, nil has two meanings.  It's the value of an empty list () and it's also false when used in boolean context.  So when we have something like (or '(1 2 3) ()) the first non-NIL list is returned.  When we use and it returns the last item if all items are true (that is, all lists are nonempty if we pass in lists).  If you keep those facts in mind, you'll see that the first code is both consistent and logical.  See also https://stackoverflow.com/questions/23826145/what-is-the-exact-difference-between-null-and-nil-in-common-lisp

I'd probably write the code the first way because it's a more compact way of expressing what you've done with if and also only evaluates node-l once instead of twice.  But then, I'd still write car instead of first, so maybe I'm a relic of former days as well.  :)