Add two of On Lisp's utility functions: group and once-only

This commit is contained in:
Renaud Casenave-Péré 2014-09-19 17:17:25 +09:00
parent aec779ac7b
commit 4e544af6fc

View file

@ -10,6 +10,7 @@
(:export :it (:export :it
:aif :aif
:awhen :awhen
:group :once-only
:restartable :restartable
:add-hook :remove-hook :run-hook :add-hook :remove-hook :run-hook
:update-current-time :get-delta-time :update-current-time :get-delta-time
@ -32,6 +33,25 @@
(when it (when it
,@body))) ,@body)))
(defun group (source n)
"Regroup the list `source' elements by n."
(when (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)))
(defmacro once-only ((&rest names) &body body)
"Evaluate the symbols in `names' only once, for use in a macro, as per Peter Siebel's Practical Common-Lisp."
(let ((gensyms (loop for n in names collect (gensym))))
`(let (,@(loop for g in gensyms collect `(,g (gensym))))
`(let (,,@(loop for g in gensyms for n in names collect ``(,,g ,,n)))
,(let (,@(loop for n in names for g in gensyms collect `(,n ,g)))
,@body)))))
(defmacro restartable (unprotected &body body) (defmacro restartable (unprotected &body body)
"Provide a Continue restart unless `unprotected' is t." "Provide a Continue restart unless `unprotected' is t."
`(if ,unprotected `(if ,unprotected