Skip to content

Commit

Permalink
Added appending, collecting macros and with-alist and with-alist-output
Browse files Browse the repository at this point in the history
  • Loading branch information
bobbysmith007 committed Apr 25, 2014
1 parent 1a9d63f commit aa91c65
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ Given an aggregator and a value, should we include the value in our
collection. Used in conjunction with the skip restart to orchestrate
skipping items.

#### Place Setters

This is function (or list thereof) that writes the aggregate value to the place after each

#### Signals and Restarts

* collectors-signals:aggregating - signaled when we begin aggregating a value
Expand Down
57 changes: 57 additions & 0 deletions collectors.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
#:with-collector-output
#:with-collectors
#:make-collector
#:with-alist-output
#:collecting
#:make-pusher
#:with-reducer
#:make-reducer
#:with-appender
#:with-appender-output
#:make-appender
#:appending
#:with-string-builder
#:with-string-builder-output
#:make-string-builder
Expand Down Expand Up @@ -400,6 +403,39 @@ FUNCTION and INITIAL-VALUE are passed directly to MAKE-REDUCER."
,@body
(,name)))

(defmacro with-alist ((name &key place (collect-nil T) initial-value from-end) &body body)
"Bind NAME to a collector function and execute BODY. If
FROM-END is true the collector will actually be a pusher, (see
MAKE-PUSHER), otherwise NAME will be bound to a collector,
(see MAKE-COLLECTOR).
(with-collector (col)
(col 1)
(col 2)
(col 3)
(col)) => (1 2 3)
"
`(let ((,name (,(if from-end
'make-pusher
'make-collector)
:initial-value (or ,initial-value ,place)
:collect-nil ,collect-nil
:place-setter ,(when place `(lambda (new) (setf ,place new))))))
(flet ((,name (&rest items)
(loop for (k v) on items by #'cddr
do (operate ,name (cons k v)))))
,@body)))

(defmacro with-alist-output ((name &key (collect-nil t) initial-value from-end place)
&body body)
`(with-alist (,name :collect-nil ,collect-nil
:initial-value ,initial-value
:from-end ,from-end
:place ,place)
,@body
(,name)))



(defmacro with-collectors (names &body body)
"Bind multiple collectors. Each element of NAMES should be a
list as per WITH-COLLECTOR's first orgument."
Expand Down Expand Up @@ -600,6 +636,27 @@ This form returns the result of that formatter"
(flet ((,name (&rest ,flet-args) (apply ,col ,flet-args)))
,@body)))))

(defmacro collecting ((arg list) &body body)
"A mapping collecting macro for operating on elements of a list
(similar to (mapcar (lambda (,arg) ,@body) list), but using a collector
so all signals are in place)"
`(with-collector-output (output)
(dolist (,arg (alexandria:ensure-list ,list))
(restart-case
(output (progn ,@body))
(skip () "Skip this element"))
)))

(defmacro appending ((arg list) &body body)
"A mapping collecting macro for operating on elements of a list
(similar to (mapcan (lambda (,arg) ,@body) list), but using a collector
so all signals are in place)"
`(with-appender-output (output)
(dolist (,arg (alexandria:ensure-list ,list))
(restart-case
(output (progn ,@body))
(skip () "Skip this element")))))




Expand Down

0 comments on commit aa91c65

Please sign in to comment.