Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Since you already have a solution that's working, I'll amplifiy <a href="https://stackoverflow.com/questions/1822382/a-lisp-function-refinement/1822579#1822579">Rainer Joswig's solution</a>, mainly to make related stylistic comments.</p> <pre><code>(defun preceders (obj seq &amp;key (start 0) (end (length seq)) (test #'eql)) (%preceders obj seq nil start end test)) </code></pre> <p>The main reason to have separate helper function (which I call <code>%PRECEDERS</code>, a common convention for indicating that a function is "private") is to eliminate the optional argument for the result. Using optional arguments that way in general is fine, but optional and keyword arguments play horribly together, and having both in a single function is a extremely efficient way to create all sorts of hard to debug errors.</p> <p>It's a matter of taste whether to make the helper function global (using <code>DEFUN</code>) or local (using <code>LABELS</code>). I prefer making it global since it means less indentation and easier interactive debugging. YMMV.</p> <p>A possible implementation of the helper function is:</p> <pre><code>(defun %preceders (obj seq result start end test) (let ((pos (position obj seq :start start :end end :test test))) ;; Use a local binding for POS, to make it clear that you want the ;; same thing every time, and to cache the result of a potentially ;; expensive operation. (cond ((null pos) (delete-duplicates (nreverse result) :test test)) ((zerop pos) (%preceders obj seq result (1+ pos) end test)) ;; I like ZEROP better than (= 0 ...). YMMV. (t (%preceders obj seq (cons (elt seq (1- pos)) result) ;; The other little bit of work to make things ;; tail-recursive. (1+ pos) end test))))) </code></pre> <p>Also, after all that, I think I should point out that I also agree with Rainer's advice to do this with an explicit loop instead of recursion, provided that doing it recursively isn't part of the exercise. </p> <p><strong>EDIT:</strong> I switched to the more common "%" convention for the helper function. Usually whatever convention you use just augments the fact that you only explicitly export the functions that make up your public interface, but some standard functions and macros use a trailing "*" to indicate variant functionality.</p> <p>I changed things to delete duplicated preceders using the standard <code>DELETE-DUPLICATES</code> function. This has the potential to be much (i.e., exponentially) faster than repeated uses of <code>ADJOIN</code> or <code>PUSHNEW</code>, since it can use a hashed set representation internally, at least for common test functions like <code>EQ</code>, <code>EQL</code> and <code>EQUAL</code>. </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload