Browse code
feat(transducer): implement COMPRESSING-RUNS, add one-arity rf
Showing 1 changed files
... | ... |
@@ -27,32 +27,64 @@ |
27 | 27 |
exit-early taking dropping transduce |
28 | 28 |
hash-table-builder vector-builder list-builder)) |
29 | 29 |
|
30 |
-(defmacro define-functional-transducer (name () &body body) |
|
31 |
- `(defun ,name (function &rest args) |
|
32 |
- (flet ((call-function (it) (apply function it args))) |
|
33 |
- (lambda (rf) |
|
34 |
- (lambda (acc next) |
|
35 |
- ,@body))))) |
|
36 |
- |
|
37 |
-(define-functional-transducer mapping () |
|
38 |
- (funcall rf acc (call-function next))) |
|
39 |
- |
|
40 |
-(define-functional-transducer mv-mapping () |
|
41 |
- (funcall rf acc (multiple-value-list (call-function next)))) |
|
42 |
- |
|
43 |
-(define-functional-transducer mv-selecting () |
|
44 |
- (multiple-value-bind (value use-p) (call-function next) |
|
45 |
- (if use-p |
|
46 |
- (funcall rf acc value) |
|
47 |
- acc))) |
|
30 |
+(defmacro transducer-lambda (&body (((two-arg-acc two-arg-next) &body two-arg-body) |
|
31 |
+ &optional (((one-arg-arg) &body one-arg-body) |
|
32 |
+ '((it) it)))) |
|
33 |
+ (alexandria:with-gensyms (arg1 arg2 next-sym-p) |
|
34 |
+ `(lambda (,arg1 &optional (,arg2 nil ,next-sym-p)) |
|
35 |
+ (if ,next-sym-p |
|
36 |
+ (let ((,two-arg-acc ,arg1) |
|
37 |
+ (,two-arg-next ,arg2)) |
|
38 |
+ ,@two-arg-body) |
|
39 |
+ (let ((,one-arg-arg ,arg1)) |
|
40 |
+ ,@one-arg-body))))) |
|
41 |
+ |
|
42 |
+ |
|
43 |
+(defun mapping (function &rest args) |
|
44 |
+ (flet ((call-function (it) |
|
45 |
+ (apply function it args))) |
|
46 |
+ (lambda (rf) |
|
47 |
+ (transducer-lambda |
|
48 |
+ ((acc next) |
|
49 |
+ (funcall rf acc (call-function next))) |
|
50 |
+ ((it) (funcall rf it)))))) |
|
51 |
+ |
|
52 |
+(defun mv-mapping (function &rest args) |
|
53 |
+ (flet ((call-function (it) |
|
54 |
+ (apply function it args))) |
|
55 |
+ (lambda (rf) |
|
56 |
+ (transducer-lambda |
|
57 |
+ ((acc next) |
|
58 |
+ (funcall rf acc |
|
59 |
+ (multiple-value-list (call-function next)))) |
|
60 |
+ ((it) (funcall rf it)))))) |
|
61 |
+ |
|
62 |
+(defun mv-selecting (function &rest args) |
|
63 |
+ (flet ((call-function (it) |
|
64 |
+ (apply function it args))) |
|
65 |
+ (lambda (rf) |
|
66 |
+ (transducer-lambda |
|
67 |
+ ((acc next) |
|
68 |
+ (multiple-value-bind (value use-p) |
|
69 |
+ (call-function next) |
|
70 |
+ (if use-p |
|
71 |
+ (funcall rf acc value) |
|
72 |
+ acc))) |
|
73 |
+ ((it) (funcall rf it)))))) |
|
48 | 74 |
|
49 | 75 |
(defun hash-table-select (hash-table) |
50 | 76 |
(mv-selecting #'gethash hash-table)) |
51 | 77 |
|
52 |
-(define-functional-transducer filtering () |
|
53 |
- (if (call-function next) |
|
54 |
- (funcall rf acc next) |
|
55 |
- acc)) |
|
78 |
+(defun filtering (function &rest args) |
|
79 |
+ (flet ((call-function (it) |
|
80 |
+ (apply function it args))) |
|
81 |
+ (lambda (rf) |
|
82 |
+ (transducer-lambda |
|
83 |
+ ((acc next) |
|
84 |
+ (if (call-function next) |
|
85 |
+ (funcall rf acc next) |
|
86 |
+ acc)) |
|
87 |
+ ((it) (funcall rf it)))))) |
|
56 | 88 |
|
57 | 89 |
(defun mv-filtering (function &rest args) |
58 | 90 |
(filtering (lambda (it) |
... | ... |
@@ -61,16 +93,45 @@ |
61 | 93 |
(defun deduping (&optional (test 'eql)) |
62 | 94 |
(lambda (rf) |
63 | 95 |
(let (last) |
64 |
- (lambda (acc next) |
|
65 |
- (prog1 (if (funcall test last next) |
|
66 |
- acc |
|
67 |
- (funcall rf acc next)) |
|
68 |
- (setf last next)))))) |
|
96 |
+ (transducer-lambda |
|
97 |
+ ((acc next) |
|
98 |
+ (prog1 (if (or (null last) |
|
99 |
+ (funcall test last next)) |
|
100 |
+ acc |
|
101 |
+ (funcall rf acc next)) |
|
102 |
+ (setf last next))) |
|
103 |
+ ((it) (funcall rf it)))))) |
|
104 |
+ |
|
105 |
+(defun seq (a b) a b) |
|
106 |
+(defun compressing-runs (&optional (test 'eql) (combiner 'seq)) |
|
107 |
+ (lambda (rf) |
|
108 |
+ (let (last leftovers) |
|
109 |
+ (transducer-lambda |
|
110 |
+ ((acc next) |
|
111 |
+ (if (or (null last) |
|
112 |
+ (funcall test last next)) |
|
113 |
+ (progn (setf last (funcall combiner last next) |
|
114 |
+ leftovers t) |
|
115 |
+ acc) |
|
116 |
+ (progn (prog1 (funcall rf acc last) |
|
117 |
+ (setf last next))))) |
|
118 |
+ ((it) |
|
119 |
+ (funcall rf |
|
120 |
+ (if leftovers |
|
121 |
+ (funcall rf it last) |
|
122 |
+ it))))))) |
|
123 |
+ |
|
69 | 124 |
|
70 | 125 |
(defun catting () |
71 | 126 |
(lambda (rf) |
72 |
- (lambda (acc next) |
|
73 |
- (reduce rf next :initial-value acc)))) |
|
127 |
+ (transducer-lambda |
|
128 |
+ ((acc next) |
|
129 |
+ (reduce rf next :initial-value acc)) |
|
130 |
+ ((it) (funcall rf it))))) |
|
131 |
+ |
|
132 |
+(defun mapcatting (fun) |
|
133 |
+ (data-lens:• (mapping fun) |
|
134 |
+ (catting))) |
|
74 | 135 |
|
75 | 136 |
(defun splitting (&rest functions) |
76 | 137 |
(let ((splitter (apply #'data-lens:juxt functions))) |
... | ... |
@@ -82,27 +143,33 @@ |
82 | 143 |
(defun taking (n) |
83 | 144 |
(lambda (rf) |
84 | 145 |
(let ((taken 0)) |
85 |
- (lambda (acc next) |
|
86 |
- (incf taken) |
|
87 |
- (if (< taken n) |
|
88 |
- (funcall rf acc next) |
|
89 |
- (exit-early (funcall rf acc next))))))) |
|
146 |
+ (transducer-lambda |
|
147 |
+ ((acc next) |
|
148 |
+ (incf taken) |
|
149 |
+ (if (<= taken n) |
|
150 |
+ (funcall rf acc next) |
|
151 |
+ (exit-early acc))) |
|
152 |
+ ((it) (funcall rf it)))))) |
|
90 | 153 |
|
91 | 154 |
(defun dropping (n) |
92 | 155 |
(lambda (rf) |
93 | 156 |
(let ((taken 0)) |
94 |
- (lambda (acc next) |
|
95 |
- (if (< taken n) |
|
96 |
- (progn (incf taken) |
|
97 |
- acc) |
|
98 |
- (funcall rf acc next)))))) |
|
157 |
+ (transducer-lambda |
|
158 |
+ ((acc next) |
|
159 |
+ (if (< taken n) |
|
160 |
+ (progn (incf taken) |
|
161 |
+ acc) |
|
162 |
+ (funcall rf acc next))) |
|
163 |
+ ((it) (funcall rf it)))))) |
|
99 | 164 |
|
100 | 165 |
(defun transduce (xf build seq) |
101 |
- (unwrap build |
|
102 |
- (catch 'done |
|
103 |
- (reduce-generic seq |
|
104 |
- (funcall xf (stepper build)) |
|
105 |
- (init build))))) |
|
166 |
+ (let ((transducer (funcall xf (stepper build)))) |
|
167 |
+ (unwrap build |
|
168 |
+ (funcall transducer |
|
169 |
+ (catch 'done |
|
170 |
+ (reduce-generic seq |
|
171 |
+ transducer |
|
172 |
+ (init build))))))) |
|
106 | 173 |
(defun eduction (xf seq) |
107 | 174 |
(lambda (build) |
108 | 175 |
(unwrap |
... | ... |
@@ -115,17 +182,19 @@ |
115 | 182 |
(defmethod init ((it (eql 'hash-table-builder))) |
116 | 183 |
(make-hash-table)) |
117 | 184 |
(defmethod stepper ((it (eql 'hash-table-builder))) |
118 |
- (lambda (acc next) |
|
119 |
- (destructuring-bind (k v) next |
|
120 |
- (setf (gethash k acc) v)) |
|
121 |
- acc)) |
|
185 |
+ (transducer-lambda |
|
186 |
+ ((acc next) |
|
187 |
+ (destructuring-bind (k v) next |
|
188 |
+ (setf (gethash k acc) v)) |
|
189 |
+ acc))) |
|
122 | 190 |
|
123 | 191 |
(defmethod init ((it (eql 'vector-builder))) |
124 | 192 |
(make-array 0 :fill-pointer t :adjustable t)) |
125 | 193 |
(defmethod stepper ((it (eql 'vector-builder))) |
126 |
- (lambda (acc next) |
|
127 |
- (vector-push-extend next acc) |
|
128 |
- acc)) |
|
194 |
+ (transducer-lambda |
|
195 |
+ ((acc next) |
|
196 |
+ (vector-push-extend next acc) |
|
197 |
+ acc))) |
|
129 | 198 |
|
130 | 199 |
(defmethod init ((it (eql 'list-builder))) |
131 | 200 |
(declare (optimize (speed 3))) |
... | ... |
@@ -133,13 +202,14 @@ |
133 | 202 |
(coerce (vector it it) |
134 | 203 |
'(simple-array list (2))))) |
135 | 204 |
(defmethod stepper ((it (eql 'list-builder))) |
136 |
- (lambda (acc a) |
|
137 |
- (declare (optimize (speed 3)) |
|
138 |
- (type (simple-array list (2)) acc)) |
|
139 |
- (let* ((to-build (elt acc 1))) |
|
140 |
- (push a (cdr to-build)) |
|
141 |
- (setf (elt acc 1) (cdr to-build))) |
|
142 |
- acc)) |
|
205 |
+ (transducer-lambda |
|
206 |
+ ((acc a) |
|
207 |
+ (declare (optimize (speed 3)) |
|
208 |
+ (type (simple-array list (2)) acc)) |
|
209 |
+ (let* ((to-build (elt acc 1))) |
|
210 |
+ (push a (cdr to-build)) |
|
211 |
+ (setf (elt acc 1) (cdr to-build))) |
|
212 |
+ acc))) |
|
143 | 213 |
(defmethod unwrap ((it (eql 'list-builder)) obj) |
144 | 214 |
(cdr (elt obj 0))) |
145 | 215 |
|