So I'm reading through some tutorials with Common Lisp, and I came across this function, group
:
(defun group (source n)
(if (zerop n) (error "zero length"))
(labels ((rec (source acc)
(let ((rest (nthcdr n source)))
(if (consp rest)
(rec rest (cons
(subseq source 0 n)
acc))
(nreverse
(cons source acc))))))
(if source (rec source nil) nil)))
After some futzing around, trying to understand what this does (it basically takes a flat list, recurses through it, and then groups them into groups of GROUP-SIZE
), I've come up with two alternatives.
This is the version that uses cl-labels
, and is basically a straight-up translation of the above group function (along with some additional modifications):
(defun *hx/group-label (sources group-size)
(if (> 0 group-size)
(error "Invalid GROUP-SIZE %d: GROUP-SIZE must be greater than zero." group-size)
(cl-labels ((rec (source accumulator)
(let ((others (nthcdr group-size source)))
(if (consp others)
(rec others (cons
(subseq source 0 group-size)
accumulator))
(nreverse
(cons source accumulator))))))
(if sources
(rec sources nil)
nil))))
But then I realized... hang on, why do I need to use cl-labels
? And so I came up with this version:
(defun *hx/group-recurse (sources group-size &optional accumulator)
(if (> 0 group-size)
(error "Invalid GROUP-SIZE %d: GROUP-SIZE must be greater than zero." group-size)
(let ((others (nthcdr group-size sources)))
(if (consp others)
(*hx/group-recurse others group-size (cons
(subseq sources 0 group-size)
accumulator))
(nreverse
(cons sources accumulator))))))
What I'd like to know, however, is why it would be necessary to use cl-labels
? I'm already using -*- lexical-binding: t -*-
, so I don't see the advantages in terms of lexical scope (which cl-labels
does, according to the documentation), and they both appear to be functionally similar.
But then again, going through the questions that this query comes up, I'm seeing advice that tells me to not recurse when loops will do. What would be the best way to do this, then?
FWIW, I'm planning to use this function to turn something like this in my init file:
(add-hook 'text-mode-hook (lambda ()
(visual-line-mode t)))
(add-hook 'prog-mode-hook (lambda ()
(visual-line-mode t)))
(add-hook 'visual-line-mode-hook #'visual-fill-column-mode)
(add-hook 'Info-mode-hook (lambda ()
(setq visual-fill-column-width 80)
(visual-fill-column-mode)))
Into something a little more concise, like:
(add-multiple-hooks (<group-function> (prog-mode-hook <function-def>
text-mode-hook <function-def>
...)))
Anyone's insights on this would be highly appreciated!
seq-partition
.