I decided I would tidy up the following function. The idea being that it uses cond
but it also contains if
s, which makes it hard to cognitively process. This is bst code from the book ansi common lisp.
(defun percolate (bst)
(cond ((null (node-l bst))
(if (null (node-r bst))
nil
(rperc bst)))
((null (node-r bst)) (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst)))))
My idea was to remove the ifs, by adding more cases in the cond
, then justify the whole thing nicely with cause on the left, effect on the right.
Here's what I came up with:
(defun percolate (bst) ; [6,7,7a]
(cond (((and (null (node-l bst)) (null (node-r bst))) nil)
((null (node-l bst)) (rperc bst))
((null (node-r bst)) (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst))))))
However, this produces the error
*** - SYSTEM::%EXPAND-FORM: (AND (NULL (NODE-L BST)) (NULL (NODE-R BST))) should be a
lambda expression
I can find other posts about this problem on stack overflow, like here but I still don't understand it. Is cond a departure from normal lisp syntax somehow? I'd like to identify the assumption I'm making which is wrong.
For the record, the below code is accepted by the interpreter, but obviously we don't want to write it like that.
(defun percolate (bst) ; [6,7,7a]
(let ((both-null (and (null (node-l bst)) (null (node-r bst))))
(l-null (null (node-l bst)))
(r-null (null (node-r bst))))
(cond ((both-null nil)
(l-null (rperc bst))
(r-null (lperc bst))
(t (if (zerop (random 2))
(lperc bst)
(rperc bst)))))))
(random-elt (delete nil (vector left right)))
– coredumprandom
bit in his percolate is wrong as explained in the book errata. Someone has commented that "A deleted internal node needs to be replaced either by the maximal node in the left subtree or by the minimal node in the right subtree, and your function does not do this" ... but I haven't fully understood that yet... but my post was just about syntax though... :) – mwal