Your problem is actually that you are mixing imperative with functional style. There is no special handling of the last
form of the body of DO, it is discarded, so your call to CONS is wasted, and SAT remains NIL
As an aside, DO should be used only in situations where you can't use one of the more specialised looping constructs (DOLIST etc.) If you need a variable then you should wrap a LET. This is because mentally parsing a DO form to work out what it is actually doing is complicated.
I would have written your function like so:
Code: Select all
(defun satisfy (fun list)
(let (result)
(dolist (el list (nreverse result))
(when (funcall fun el)
(push el result)))))
Note the call to NREVERSE otherwise your results are backwards.
For completeness a functional style version would be like:
Code: Select all
(defun satisfy (fun list)
(labels ((rec (list acc)
(if list
(rec (rest list)
(if (funcall fun
(first list))
(cons (first list)
acc)
;; else
acc))
;; else
(nreverse acc))))
(rec list nil)))
Though it's worth noting that the standard doesn't guarantee tail-call optimisation (even if most implementations actually would). This means that the imperative style would be both safer and shorter