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 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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With