Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 233 lines (179 sloc) 7.469 kB
a27785d @tlikonen Add files to the repository
authored
1 * General accumulator
2
11f24d6 @tlikonen Move author and license info to the beginning
authored
3 *A general-purpose, extensible value accumulator library for Common Lisp*
4
5 ** Author and license
6
7 Author: Teemu Likonen <tlikonen@iki.fi>
8
9 License: Public domain
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 ** Introduction
16
a27785d @tlikonen Add files to the repository
authored
17 General accumulator is a general-purpose, extensible value accumulator
811472a @tlikonen Rephrase README text
authored
18 library for the Common Lisp language. Its main interface is
a27785d @tlikonen Add files to the repository
authored
19 =with-accumulator= macro which sets an environment for easy
20 accumulation. The library provides several built-in accumulators which
811472a @tlikonen Rephrase README text
authored
21 should cover the most common use-cases but any kind of accumulators can
22 be added because the accumulator back-end is implemented through generic
a27785d @tlikonen Add files to the repository
authored
23 functions.
24
25 #+BEGIN_SRC lisp
26 (with-accumulator (NAME OBJECT &key KEYWORD-ARGUMENTS ...)
27 BODY ...)
28 #+END_SRC
29
30 The =with-accumulator= macro creates an accumulation environment in
811472a @tlikonen Rephrase README text
authored
31 which the local function /name/ handles the accumulation. Accumulator's
a27785d @tlikonen Add files to the repository
authored
32 type is defined by the /object/ argument. Then all /body/ forms are
33 executed normally and the return value of the last form is returned.
34
35 The local function /name/ can optionally take one argument which is an
36 object to be accumulated. If the function is called without arguments it
811472a @tlikonen Rephrase README text
authored
37 returns the currently accumulated value. The accumulation process is
38 handled by generic functions =initialize=, =accumulate= and =value=.
a27785d @tlikonen Add files to the repository
authored
39
40 ** Built-in accumulators
89a45fa @tlikonen Delete trailing whitespace from README
authored
41
a27785d @tlikonen Add files to the repository
authored
42 There are several built-in accumulator types. Possible values for the
43 /object/ argument of =with-accumulator= macro:
89a45fa @tlikonen Delete trailing whitespace from README
authored
44
d76ac6f @tlikonen Change built-in accumulator names from boldface to a ***-level heading
authored
45 *** :LIST
89a45fa @tlikonen Delete trailing whitespace from README
authored
46
a27785d @tlikonen Add files to the repository
authored
47 Creates a list collector. Each accumulated object is collected to a
48 list. Example:
89a45fa @tlikonen Delete trailing whitespace from README
authored
49
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
50 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
51 GENACC> (with-accumulator (collect :list)
52 (collect 1) (collect 2) (collect 3)
53 (collect))
54 (1 2 3)
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
55 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
56
d715cae @tlikonen Markup changes: =accumulate= instead of /accumulate/
authored
57 The collecting is done destructively. The applicable =accumulate= method
a27785d @tlikonen Add files to the repository
authored
58 maintains a pointer to the last cons cell of the list and each time
59 modifies its /cdr/ value to point to a new cons cell.
89a45fa @tlikonen Delete trailing whitespace from README
authored
60
933be3f @tlikonen [A list] -> [List]
authored
61 *** [List]
89a45fa @tlikonen Delete trailing whitespace from README
authored
62
a27785d @tlikonen Add files to the repository
authored
63 If the /object/ argument is of type /list/ then new elements are
64 collected at the end. Example:
89a45fa @tlikonen Delete trailing whitespace from README
authored
65
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
66 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
67 GENACC> (with-accumulator (collect (list 1 2 3))
68 (collect 4) (collect 5)
69 (collect))
70 (1 2 3 4 5)
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
71 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
72
a27785d @tlikonen Add files to the repository
authored
73 This is a destructive operation. The /cdr/ value of the last cons cell
74 of the original list is modified and linked to a new cons cell.
89a45fa @tlikonen Delete trailing whitespace from README
authored
75
d76ac6f @tlikonen Change built-in accumulator names from boldface to a ***-level heading
authored
76 *** :VECTOR
89a45fa @tlikonen Delete trailing whitespace from README
authored
77
a27785d @tlikonen Add files to the repository
authored
78 Creates a general vector collector. It creates an adjustable vector with
79 a fill pointer 0 and element type /t/. New elements are pushed to that
80 vector with =cl:vector-push-extend= function. Example:
89a45fa @tlikonen Delete trailing whitespace from README
authored
81
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
82 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
83 GENACC> (with-accumulator (collect :vector)
84 (collect "first") (collect "second")
85 (collect))
86 #("first" "second")
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
87 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
88
d76ac6f @tlikonen Change built-in accumulator names from boldface to a ***-level heading
authored
89 *** :STRING
89a45fa @tlikonen Delete trailing whitespace from README
authored
90
a27785d @tlikonen Add files to the repository
authored
91 This is similar to =:VECTOR= but the element type is /character/. The
cdded0d @tlikonen Yet another change from /accumulate/ to =accumulate=
authored
92 underlying =accumulate= methods can take a single /character/ or a
a27785d @tlikonen Add files to the repository
authored
93 sequence of characters as the argument. Example:
89a45fa @tlikonen Delete trailing whitespace from README
authored
94
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
95 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
96 GENACC> (with-accumulator (collect :string)
97 (collect #\a)
98 (collect "bcd")
99 (collect #(#\e #\f))
100 (collect '(#\g #\h #\i))
101 (collect))
102 "abcdefghi"
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
103 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
104
d76ac6f @tlikonen Change built-in accumulator names from boldface to a ***-level heading
authored
105 *** :BIT-VECTOR
89a45fa @tlikonen Delete trailing whitespace from README
authored
106
a27785d @tlikonen Add files to the repository
authored
107 This is similar to =:STRING= but the element type is /bit/. The argument
108 for the accumulator function can a /bit/ or a sequence of bits.
89a45fa @tlikonen Delete trailing whitespace from README
authored
109
933be3f @tlikonen [A list] -> [List]
authored
110 *** [Vector]
89a45fa @tlikonen Delete trailing whitespace from README
authored
111
a27785d @tlikonen Add files to the repository
authored
112 If /object/ is of type /vector/ which satisfies the test
6e5330a @tlikonen Add CL: prefix to ARRAY-HAS-FILL-POINTER-P
authored
113 =cl:array-has-fill-pointer-p= then that vector is appended, starting
114 from its current fill pointer.
89a45fa @tlikonen Delete trailing whitespace from README
authored
115
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
116 #+BEGIN_EXAMPLE
70abd17 @tlikonen Reformat a vector-collector code example
authored
117 GENACC> (with-accumulator
118 (collect (make-array 2 :fill-pointer 2 :adjustable t
119 :initial-contents (vector 1 2)))
a27785d @tlikonen Add files to the repository
authored
120 (collect 3)
121 (collect 4)
122 (collect))
123 #(1 2 3 4)
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
124 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
125
a27785d @tlikonen Add files to the repository
authored
126 Note that if the vector is not adjustable then the accumulator may reach
127 vector's limits and =cl:vector-push-extend= signals an error.
89a45fa @tlikonen Delete trailing whitespace from README
authored
128
933be3f @tlikonen [A list] -> [List]
authored
129 *** [Function]
89a45fa @tlikonen Delete trailing whitespace from README
authored
130
a27785d @tlikonen Add files to the repository
authored
131 If /object/ is of type /function/ then the accumulator behaves like the
132 =cl:reduce= function: all accumulated objects are combined into one by
133 calling the given reducer function. Examples:
89a45fa @tlikonen Delete trailing whitespace from README
authored
134
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
135 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
136 GENACC> (with-accumulator (summing #'+)
137 (summing 5) (summing 7) (summing 11)
138 (summing))
139 23
89a45fa @tlikonen Delete trailing whitespace from README
authored
140
a27785d @tlikonen Add files to the repository
authored
141 GENACC> (with-accumulator (nc #'nconc)
142 (nc (list 1 2 3))
143 (nc (list 4 5 6))
144 (nc (list 7 8 9))
145 (nc))
146 (1 2 3 4 5 6 7 8 9)
89a45fa @tlikonen Delete trailing whitespace from README
authored
147
a27785d @tlikonen Add files to the repository
authored
148 GENACC> (with-accumulator (early-char (lambda (a b)
149 (if (char< a b) a b)))
150 (early-char #\o)
151 (early-char #\b)
152 (early-char #\s)
153 (early-char))
154 #\b
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
155 #+END_EXAMPLE
89a45fa @tlikonen Delete trailing whitespace from README
authored
156
a27785d @tlikonen Add files to the repository
authored
157 ** Adding a custom accumulator
89a45fa @tlikonen Delete trailing whitespace from README
authored
158
a27785d @tlikonen Add files to the repository
authored
159 The whole accumulation process is handled by three generic functions:
160 =initialize=, =accumulate= and =value=. Writing new methods for those
161 functions allow adding any kind of accumulators. The following example
162 adds an accumulator which calculates the arithmetic mean of accumulated
163 numbers.
89a45fa @tlikonen Delete trailing whitespace from README
authored
164
a27785d @tlikonen Add files to the repository
authored
165 First we define a class whose instances will keep the state of the
166 accumulator. In this case we need to store the sum and the count of
167 accumulated numbers so we create slots for them.
89a45fa @tlikonen Delete trailing whitespace from README
authored
168
a27785d @tlikonen Add files to the repository
authored
169 #+BEGIN_SRC lisp
170 (defclass mean-accumulator ()
171 ((sum :initform 0)
172 (count :initform 0)))
173 #+END_SRC
89a45fa @tlikonen Delete trailing whitespace from README
authored
174
a27785d @tlikonen Add files to the repository
authored
175 Then we add a method for initializing an instance of the class. The
176 generic function =initialize= is used for that. It is called with the
177 /object/ argument of =with-accumulator= macro and with optional
178 /keyword-arguments/. In this example we use an /EQL/ specializer for
179 symbol =:MEAN=. We don't use any keyword arguments so there's just empty
180 /&key/ at the end of the lambda list.
89a45fa @tlikonen Delete trailing whitespace from README
authored
181
a27785d @tlikonen Add files to the repository
authored
182 #+BEGIN_SRC lisp
183 (defmethod genacc:initialize ((type (eql :mean)) &key)
184 (make-instance 'mean-accumulator))
185 #+END_SRC
89a45fa @tlikonen Delete trailing whitespace from README
authored
186
a27785d @tlikonen Add files to the repository
authored
187 Now we create a method for generic function =accumulate=. The function
188 is called with two arguments:
189
190 1. the accumulator object created by =initialize=
191 2. the object that is meant to be accumulated.
192
193 This method specializes on our =mean-accumulator= class as well as on
3a7f0c9 @tlikonen Minor rephrasing in README
authored
194 the /number/ class. The new number is added to the previous value and
195 the count is increased by one.
89a45fa @tlikonen Delete trailing whitespace from README
authored
196
a27785d @tlikonen Add files to the repository
authored
197 #+BEGIN_SRC lisp
198 (defmethod genacc:accumulate ((object mean-accumulator)
199 (number number))
200 (with-slots (sum count) object
201 (incf sum number)
202 (incf count 1)))
203 #+END_SRC
89a45fa @tlikonen Delete trailing whitespace from README
authored
204
a27785d @tlikonen Add files to the repository
authored
205 For returning the accumulated mean value we create a method for the
206 generic function =value=. This method, too, must specialize on the
207 =mean-accumulator= class. We get the current accumulated mean value by
208 dividing the value of /sum/ slot with the value of /count/ slot.
89a45fa @tlikonen Delete trailing whitespace from README
authored
209
a27785d @tlikonen Add files to the repository
authored
210 #+BEGIN_SRC lisp
211 (defmethod genacc:value ((object mean-accumulator))
212 (with-slots (sum count) object
213 (/ sum count)))
214 #+END_SRC
89a45fa @tlikonen Delete trailing whitespace from README
authored
215
a27785d @tlikonen Add files to the repository
authored
216 Now the custom accumulator is ready and it can be used with the
217 =with-accumulator= macro. Example:
89a45fa @tlikonen Delete trailing whitespace from README
authored
218
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
219 #+BEGIN_EXAMPLE
a27785d @tlikonen Add files to the repository
authored
220 GENACC> (with-accumulator (mean :mean)
221 (loop repeat 10 do (mean (random 1000)))
222 (format t "The mean so far: ~A~%" (mean))
223 (loop repeat 10 do (mean (random 1000)))
224 (format t "The final mean: ~A~%" (mean)))
225 The mean so far: 2512/5
226 The final mean: 2704/5
227 NIL
357a1e1 @tlikonen Use #+BEGIN_EXAMPLE markup in examples
authored
228 #+END_EXAMPLE
f584102 @tlikonen Add author and license info
authored
229
a24ec10 @tlikonen Add an URL to the source code repository
authored
230 ** The source code repository
231
232 GitHub repository: <[[https://github.com/tlikonen/cl-general-accumulator]]>
Something went wrong with that request. Please try again.