|
doplus
doplus - simple, high-level, extensible iteration constructdoplus (written DO+) is an iteration macro for Common Lisp. I wrote it because:
The code for doplus is here. Table of contentsOverview and main featuresdoplus basically can be thought as a high-level DSL over CL:DO [*]. In spirit it's similar to iterate, but having implementation simplicity as a core goal, the syntax is necessarily a bit different to accomodate the lack of a code walker that can freely move pieces of code around. Also, doplus generally requires the user to be a bit more explicit than both LOOP and iterate. doplus, like iterate, is meant to be extensible by simply writing macros. By contrast, LOOP is not portably extensible, and on those implementations where it is, it's not trivial to extend it. Most macros that extend doplus can be written combining built-in operators and producing code in doplus syntax, just like a user might have written it. This makes many possible doplus extensions very readable. doplus is fully understood by SLIME, since it uses regular macros and defines dummy top-level macros for its body-local macrolets, to make symbol completion available for them as well. doplus is, to my knowledge, the only advanced iteration construct in Lisp to support atomic initialization and stepping of iteration variables. Refer to the manual section Initialization and stepping for more information. [*] doplus used to be actually written on top of cl:do*, but has been rewritten using lower-level constructs to have more control on the various steps of iteration. StatusI now consider doplus to be quite mature. I've been using it exclusively in my own projects, and it's been on Quicklisp since late 2011. Initially, it progressed very quickly from idea to unfinished hack to something that could be used in real code. It has then been used and refined by the author with the invaluable aid of other Lispers, most notably Tamas K. Papp. Nowadays it provides most of LOOP's and iterate's features, either built-in or easy to emulate, and it has its own unique features. The big, scary exampleIn all its glory: CL-USER>
(do+ ((for x (in '(1 3 5 7 9)))
(for k (from 10 :to 0))
(initially (format t "initially k = ~S~%" k))
(for m (to 100 :by 5))
(initially (format t "another init form~%"))
(with (y 42) z)
(stop-when (eql x 7))
(counting loops)
(finally (format t "finally k = ~S~%" k))
(accumulating-to w)
(accumulating-to p :initially 0 :by #'+ :finally #'-)
(returning (list 'x x 'y y 'z z 'k k 'm m 'w w 'p p
'loops loops 'max-length max-length 'longest-list longest-list))
(finally (format t "another final form~%"))
(finding max-x (maximizing x))
(for list (in '((1 2) (3) (4 5 6) (7 8) (9))))
(finding max-length (maximizing (length list) :saving list :in longest-list)))
(let ((foo "look ma, body is nested!"))
(declare (ignore foo))
(format t "~%loop n° ~A~%" loops)
(format t "before collect, x ~A y ~A z ~A k ~A m ~A w ~A ~% list ~A max-length ~A longest-list ~A ~%"
x y z k m w list max-length longest-list)
(collect x :into w)
(collect x :into p)
(format t "after collect, x ~A y ~A z ~A k ~A m ~A w ~A ~% list ~A max-length ~A longest-list ~A ~%"
x y z k m w list max-length longest-list)))
initially k = 10
another init form
This covers many, but not all, of the features do+ has. ManualThe manual is on a separate page. |