views:

95

answers:

3

I was wondering if there is a standard practice regarding the use of labels in Lisp. I've been messing around with a Lisp implementation of the algorithm described in the first answer here http://stackoverflow.com/questions/352203/generating-permutations-lazily My current version uses labels to break out portions of functionality.

(defun next-permutation (pmute)
  (declare (vector pmute))
  (let ((len (length pmute)))
    (if (> len 2)
        (labels ((get-pivot ()
                   (do ((pivot (1- len) (1- pivot)))
                       ((or (= pivot 0)
                            (< (aref pmute (1- pivot))
                               (aref pmute pivot)))
                        pivot)))
                 (get-swap (pivot)
                   (let ((swp (1- len)))
                     (loop for i from (1- len) downto pivot do
                           (if (or (and (> (aref pmute i)
                                           (aref pmute (1- pivot)))
                                        (< (aref pmute i) (aref pmute swp)))
                                   (< (aref pmute swp) (aref pmute (1- pivot))))
                               (setf swp i)))
                     swp))
                 (next (swp pivot)
                   (rotatef (aref pmute (1- pivot)) (aref pmute swp))
                   (reverse-vector pmute pivot (1- len))))
          (let ((piv (get-pivot)))
            (if (> piv 0)
                (next (get-swap piv) piv)
              nil))))))

Since each label is only called once I was wondering if this is considered bad practice since the only reason to do it in this case is for aesthetic reasons. I would argue that the current version with labels is clearer but that may go against common wisdom that I'm not aware of, being new to Lisp.

+1  A: 

Not being anything other than a Lisp newbie, I'd say you're doing the right thing: making your code more readable by naming chunks.

Frank Shearar
+7  A: 

No, it's fine. Writing named functions makes the code a little bit more self-documenting and more modular.

Sometimes I would also list all variables used in the functions arglist and not use the variables from the enclosing function. That makes the interface a little bit clearer and helps moving the function around in the code (if necessary).

The local functions also offer the possibility to add local documentation strings and interface descriptions.

If the local functions are getting too large and they may also be used outside, then I would extract them and make them global.

Rainer Joswig
+2  A: 

I do not see anything bad with it. You are making the two subprocesses very clear and easy to chunk, making it easy to get a quick grasp at what the function really does by looking just at the body. Also its now easy to promote the inner functions to global functions if you need to.

johanbev