1 ;;; Copyright (c) 2007, Matthew Lamari (matt.lamari@gmail.com). All rights reserved.
3 ;;; Redistribution and use in source and binary forms, with or without
4 ;;; modification, are permitted provided that the following conditions
7 ;;; * Redistributions of source code must retain the above copyright
8 ;;; notice, this list of conditions and the following disclaimer.
10 ;;; * Redistributions in binary form must reproduce the above
11 ;;; copyright notice, this list of conditions and the following
12 ;;; disclaimer in the documentation and/or other materials
13 ;;; provided with the distribution.
15 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
16 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 ; (load "c:/prog/lisp/common/stdutils.lisp")
33 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
34 (cl-user::load-lutils
))
38 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
41 (define-compiler-macro funcall2
(&whole form
&rest params
)
44 (error (err) (error (format nil
"~S ~S" err
,params
)))))
45 (defun funcall2 (&rest rest
) (apply #'funcall rest
))
50 (defmacro defunm
(function-name params
&body body
)
52 (defun ,function-name
,params
,(eval `(let ,(mapcar (lambda (elt) `(,elt
',elt
)) params
) ,@body
)))
53 (define-compiler-macro ,function-name
,params
,@body
)))
55 (defclass function-form
() ())
57 (defclass function-form-symbol
(function-form)
58 ((symbol :type symbol
:initarg
:symbol
:reader get-symbol
)))
60 (defclass function-form-lambda
(function-form)
61 ((args :initarg
:args
:type list
:reader get-args
)
62 (body :initarg
:body
:type list
:reader get-body
)))
64 (defclass function-form-expression
(function-form)
65 ((expression :initarg
:expression
:reader get-expression
)))
67 (defclass function-form-partial
(function-form)
68 ((sub-function-form :initarg
:sub-function-form
:type function-form
:reader get-sub-function-form
)
69 (known-args :initarg
:known-args
:type list
:reader get-known-args
)
70 (new-arg-side :initarg
:new-arg-side
:type
:symbol
:reader get-new-arg-side
))) ; new-arg-side should be :right for curried, :left for rcurried
72 (defclass function-form-composed
(function-form)
73 ((functions-reversed :initarg
:functions-reversed
:type list
:reader get-functions-reversed
)))
75 (defclass function-form-constantly
(function-form)
76 ((value :initarg
:value
:reader get-value
)))
80 (defun function-literal-to-form (function)
82 ((when (consp function
)
85 (destructuring-bind (function-sym function
)
89 (when (eql (car function
) 'lambda
)
90 (destructuring-bind (lambda args
&body body
)
92 (make-instance 'function-form-lambda
:args args
:body body
))))
93 (symbol (make-instance 'function-form-symbol
:symbol function
)))))
95 (make-instance 'function-form-lambda
:args
(second function
) :body
(cddr function
)))
97 (destructuring-bind (curried-sym curried
&rest known-args
)
99 (make-instance 'function-form-partial
:sub-function-form
(function-literal-to-form curried
) :new-arg-side
:right
:known-args known-args
)))
101 (destructuring-bind (curried-sym curried
&rest known-args
)
103 (make-instance 'function-form-partial
:sub-function-form
(function-literal-to-form curried
) :new-arg-side
:left
:known-args known-args
)))
105 (destructuring-bind (constantly-sym value
)
107 (make-instance 'function-form-constantly
:value value
)))
109 (make-instance 'function-form-composed
:functions-reversed
(nreverse (mapcar #'function-literal-to-form
(cdr function
))))))))
110 (t (make-instance 'function-form-expression
:expression function
))))
112 (defmethod get-call-form-precond-parameters ((function function-form
) (parameter-count integer
))
113 (list (loop for i from
1 to parameter-count collect
(gensym))))
115 (defmethod get-call-form-precond-parameters ((function function-form-lambda
) (parameter-count integer
))
116 (assert (eql parameter-count
(length (get-args function
))))
117 (list (get-args function
)))
119 (defmethod get-call-form-precond-parameters ((function function-form-partial
) (parameter-count integer
))
120 (let* ((known-arg-count (length (get-known-args function
)))
121 (sub-form-preconds (get-call-form-precond-parameters (get-sub-function-form function
) (+ parameter-count known-arg-count
))))
122 (ecase (get-new-arg-side function
)
123 (:right
; normal curried
124 (cons (last (first sub-form-preconds
) parameter-count
) sub-form-preconds
))
126 (cons (subseq (first sub-form-preconds
) 0 parameter-count
) sub-form-preconds
)))))
128 (defmethod get-call-form-precond-parameters ((function function-form-composed
) (parameter-count integer
))
129 (get-call-form-precond-parameters (first (get-functions-reversed function
)) parameter-count
))
133 (defmethod get-call-form ((function function-form-symbol
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-actions nil
))
134 `(,(get-symbol function
) ,@(if per-precond-parameter-actions
(mapcar #'funcall per-precond-parameter-actions
(first call-form-precond-parameters
)) (first call-form-precond-parameters
))))
136 (defmethod get-call-form ((function function-form-expression
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-actions nil
))
137 `(funcall ,(get-expression function
) ,@(first call-form-precond-parameters
)))
139 (defmethod get-call-form ((function function-form-lambda
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-actions nil
))
140 (if per-precond-parameter-actions
142 ,@(mapcar (lambda (precond-parameter action
) `(setq ,precond-parameter
,(funcall action precond-parameter
))) (first call-form-precond-parameters
) per-precond-parameter-actions
)
143 (let nil
,@(get-body function
)))
144 `(let nil
,@(get-body function
))))
146 (defmethod get-call-form ((function function-form-partial
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-actions nil
))
147 (let* ((known-arg-count (length (get-known-args function
)))
148 ; (sub-form-preconds (get-call-form-precond-parameters (get-sub-function-form function) (+ (length (first call-form-precond-parameters)) known-arg-count)))
149 (sub-form-preconds (cdr call-form-precond-parameters
))
151 (ecase (get-new-arg-side function
)
153 `(let ,(mapcar (lambda (precond known
) `(,precond
,known
)) (first sub-form-preconds
) (get-known-args function
))
154 ,@(when per-precond-parameter-actions
155 (loop for precond in
(last (first sub-form-preconds
) (length (first call-form-precond-parameters
)))
156 for action in per-precond-parameter-actions
157 collect
`(setq ,precond
,(funcall action precond
))))
158 ,(get-call-form (get-sub-function-form function
) sub-form-preconds nil
)))
160 `(let ,(mapcar (lambda (precond known
) `(,precond
,known
)) (last (first sub-form-preconds
) known-arg-count
) (get-known-args function
))
161 ,@(when per-precond-parameter-actions
162 (loop for precond in
(subseq (first sub-form-preconds
) 0 (length (first call-form-precond-parameters
)))
163 for action in per-precond-parameter-actions
164 collect
`(setq ,precond
,(funcall action precond
))))
165 ,(get-call-form (get-sub-function-form function
) sub-form-preconds nil
))))))
167 (defmethod get-call-form ((function function-form-composed
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-actions nil
))
168 (destructuring-bind (last . not-last-reversed
)
169 (get-functions-reversed function
)
170 (let ((result-sym (gensym)))
172 ,(get-call-form last call-form-precond-parameters per-precond-parameter-actions
)))
173 ,@(loop for function in not-last-reversed collect
175 ,(let ((precond-parameters (get-call-form-precond-parameters function
1)))
176 (destructuring-bind (sole-result-sym) ; there must be only one.
177 (first precond-parameters
)
178 `(let ((,sole-result-sym
,result-sym
))
179 ,(get-call-form function precond-parameters nil
))))))
182 (defmethod get-call-form ((function function-form-constantly
) (call-form-precond-parameters list
) &optional
(per-precond-parameter-action nil
))
183 (get-value function
))
185 (defun composed (&rest functions
)
188 (loop for remainder on functions do
190 (push (car remainder
) reversed
)
191 (setq last
(car remainder
))))
193 (let ((result (apply last args
)))
194 (loop for elt in reversed do
(setq result
(funcall elt result
)))
200 (defun curried (function &rest largs
)
201 (assert (functionp function
))
202 (lambda (&rest rargs
)
203 (apply function
(append largs rargs
))))
205 (defun rcurried (function &rest rargs
)
206 (assert (functionp function
))
207 (lambda (&rest largs
)
208 (apply function
(append largs rargs
))))
217 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
218 (defstruct traversal-link
220 get-link-with-tail-override
))
224 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
227 (defmacro get-traversal-result
(traversal-link)
228 `(funcall (resolved ,traversal-link
) :get-link
))
231 (defstruct unresolved call
)
232 (defmacro unresolved
(&body body
) `(make-unresolved :call
(lambda () ,@body
)))
233 (defmacro resolved
(&body body
)
234 (let ((temp-sym (gensym)))
236 `(let ((,temp-sym
,@body
)) (loop while
(typep ,temp-sym
'unresolved
) do
(setq ,temp-sym
(funcall (unresolved-call ,temp-sym
)))) ,temp-sym
)
237 (let ((current body
))
238 (loop while
(and (consp (car current
)) (not (cdr current
)) (or (eql (caar current
) 'unresolved
) (eql (caar current
) 'resolved
))) do
(setq current
(cdr (car current
))))
239 `(let ((,temp-sym
,@current
)) (loop while
(typep ,temp-sym
'unresolved
) do
(setq ,temp-sym
(funcall (unresolved-call ,temp-sym
)))) ,temp-sym
)))))
241 (defmacro tut
(&body body
)
242 "Trampoline unless TCO can be assumed"
243 `(unresolved ,@body
))
246 (defclass traversal-result
() ((value :initarg
:value
:accessor get-value
) (next :initarg
:next
:accessor get-next
)))
247 (defun traversal-result (value next
)
248 (make-instance 'traversal-result
:value value
:next next
))
251 (defmacro def-traversal-link
(cases &key
(sub-cases-sink nil
))
252 (let ((control-sym (gensym))
253 (params-sym (gensym))
254 (sub-cases-sink-sym (gensym)))
255 `(let ((,sub-cases-sink-sym
,sub-cases-sink
))
256 (lambda (,control-sym
&rest
,params-sym
)
260 (destructuring-bind (control args
&body body
)
263 (destructuring-bind ,args
267 (:get-sub-cases-sink
,sub-cases-sink-sym
)
269 (if ,sub-cases-sink-sym
270 (apply ,sub-cases-sink-sym
,control-sym
,params-sym
)
271 (error (format nil
"No sub-cases for ~A" ,control-sym
)))))))))
273 (defparameter **standard-terminating-end-call
**
275 ((:get-link
() (traversal-result nil nil
))
276 (:get-link-with-tail-override
(end-call) (unresolved (get-traversal-result end-call
)))
277 (:slam
(&rest rest
) (first rest
) (second rest
) (unresolved (funcall (second rest
) (first rest
)))))))
282 (defmacro assured-traversal-result
(&body body
)
283 (let ((result-sym (gensym)))
284 `(let ((,result-sym
(resolved (progn ,@body
))))
285 (when (not (typep ,result-sym
'traversal-result
)) (error (format nil
"Not a Traversal-result: ~S" ',body
)))
289 (defmacro! with-slam-sinks
((slam-params) &body body
)
290 `(let ((,g
!slam-params
,slam-params
))
291 (destructuring-bind (,g
!prior-count
,g
!sink-count
,g
!single-sym
,g
!sequence-sym
)
293 (labels ((slam-single (single) (funcall ,g
!single-sym single
))
294 (slam-sequence (sequence) (funcall ,g
!sequence-sym sequence
)))
295 (macrolet! ((end-call-thing (,g
!end-call-sym count
)
296 `(let ((,g
!count
,count
))
297 (unresolved (apply (resolved ,,g
!end-call-sym
) :slam
(+ ,g
!count
,',g
!prior-count
) (cdr ,',g
!slam-params
)))))
298 (slam-next (,g
!next-sym count
)
299 `(let ((,g
!count
,count
))
300 (unresolved (apply ,,g
!next-sym
:slam
(+ ,g
!count
,',g
!prior-count
) (cdr ,',g
!slam-params
)))))
301 (slam-for-continue (list sink-count
)
302 `(apply #'slam-cont
,list
,',g
!prior-count
,sink-count
(cddr ,',g
!slam-params
))))
306 (defmacro! standard-traversal-link-parametric
((build-func-sym (end-call-sym &rest build-params
) &body body
) (&rest build-actual-params
))
307 `(labels ((,build-func-sym
(,end-call-sym
,@build-params
)
308 (lambda (,g
!control-sym
&rest
,g
!params-sym
)
311 (do-slam ,g
!params-sym
,body
,end-call-sym
))
314 (ecase ,g
!control-sym
315 (:get-link
,end-call-sym
)
316 (:get-link-with-tail-override
317 (destructuring-bind (,end-call-sym
)
321 (,build-func-sym
**standard-terminating-end-call
** ,@build-actual-params
)))
324 (defmacro standard-traversal-link-sequence-slam
((build-func-sym (end-call-sym &rest build-params
) &body body
)
326 (&rest build-actual-params
))
327 `(macrolet ((do-slam (params-sym body end-call-sym
)
328 `(with-slam-sinks (,params-sym
)
329 (let* ((seq ,',sequence
)
330 (length (length seq
)))
332 (end-call-thing ,end-call-sym length
)))))
333 (standard-traversal-link-parametric (,build-func-sym
(,end-call-sym
,@build-params
) ,@body
) (,@build-actual-params
))))
336 (let ((control-sym (gensym))
337 (params-sym (gensym)))
338 `(labels ((,build-func-sym
(,end-call-sym
,@build-params
)
339 (lambda (,control-sym
&rest
,params-sym
)
342 (with-slam-sinks (,params-sym
)
343 (slam-sequence ,sequence
)
344 (tut (apply (resolved ,end-call-sym
) :slam
,params-sym
))))
348 (:get-link
,end-call-sym
)
349 (:get-link-with-tail-override
350 (destructuring-bind (,end-call-sym
)
354 (,build-func-sym
**standard-terminating-end-call
** ,@build-actual-params
))))
361 (defmacro! standard-traversal-link
((build-func-sym (end-call-sym &rest build-params
) &body body
) (&rest build-actual-params
))
362 `(macrolet! ((do-slam (params-sym body end-call-sym
)
363 `(with-slam-sinks (,params-sym
)
364 (let* ((,g
!result-sym
(resolved (progn ,@body
)))
365 (,g
!next-sym
(get-next ,g
!result-sym
)))
368 (slam-single (resolved (get-value ,g
!result-sym
)))
369 (slam-next ,g
!next-sym
1))
371 (end-call-thing ,end-call-sym
0)))))))
372 (standard-traversal-link-parametric (,build-func-sym
(,end-call-sym
,@build-params
) ,@body
) (,@build-actual-params
))))
377 (defmacro standard-traversal-link
((build-func-sym (end-call-sym &rest build-params
) &body body
) (&rest build-actual-params
))
378 (let ((control-sym (gensym))
379 (params-sym (gensym)))
380 `(labels ((,build-func-sym
(,end-call-sym
,@build-params
)
381 (lambda (,control-sym
&rest
,params-sym
)
384 (with-slam-sinks (,params-sym
)
385 (let* ((,result-sym
(resolved (progn ,@body
)))
386 (,next-sym
(get-next ,result-sym
)))
389 (slam-single (get-value ,result-sym
))
390 (tut (apply ,next-sym
:slam
,params-sym
)))
392 (tut (apply (resolved ,end-call-sym
) :slam
,params-sym
)))))))
396 (:get-link
,end-call-sym
)
397 (:get-link-with-tail-override
398 (destructuring-bind (,end-call-sym
)
402 (,build-func-sym
**standard-terminating-end-call
** ,@build-actual-params
))))
405 (defun slam-cont (lazy-list current-count sink-count sink-single sink-sequence
)
406 (funcall (get-call-for-first lazy-list
) :slam current-count sink-count sink-single sink-sequence
))
408 (defun slam (lazy-list sink-single sink-sequence
)
410 (resolved (slam-cont lazy-list
0 (lambda (count) (setq result count
)) sink-single sink-sequence
))
415 (defmacro standard-traversal-link-with-sub
((build-func-sym (end-call-sym &rest build-params
) &body body
) sub-cases
(&rest build-actual-params
))
416 `(labels ((,build-func-sym
(,end-call-sym
,@build-params
)
418 ((:get-link
() ,@body
)
419 (:get-link-with-tail-override
(,end-call-sym
) ,@body
))
420 :sub-cases-sink
(def-traversal-link ,sub-cases
))))
421 (,build-func-sym
**standard-terminating-end-call
** ,@build-actual-params
)))
426 Was experimental
/to keep sub-cases but the situation for them went away
427 (defmacro sub-case-preserving-traversal-link
((build-func-sym (end-call-sym call-sym
&rest build-params
) &body body
) (&rest build-actual-params
))
428 `(labels ((,build-func-sym
(,end-call-sym
,call-sym
,@build-params
)
430 ((:get-link
() ,@body
)
431 (:get-link-with-tail-override
(,end-call-sym
) ,@body
))
432 :sub-cases-sink
`(funcall ,call-sym
:sub-cases-sink
))))
433 (,build-func-sym
**standard-terminating-end-call
** ,@build-actual-params
)))
439 (defmacro fixed-traversal-link-from-result-form
(traversal-result-form)
440 (let ((end-call-sym (gensym))
442 (result-sym (gensym))
446 ((:get-link
() ,traversal-result-form
)
447 (:get-link-with-tail-override
(,end-call-sym
)
448 (let* ((,result-sym
(resolved ,traversal-result-form
))
449 (,next-sym
(resolved (get-next ,result-sym
))))
452 (get-value ,result-sym
)
454 (with-traversal-result
456 (funcall ,next-sym
:get-link-with-tail-override
,end-call-sym
)
457 (fixed-traversal-link ,v-sym
,n-sym
))))
458 (unresolved (get-traversal-result ,end-call-sym
)))))))))
461 (defmacro fixed-traversal-link
(value next
)
462 (let ((end-call-sym (gensym))
464 (slam-params-sym (gensym)))
466 ((:get-link
() (traversal-result ,value
,next
))
467 (:get-link-with-tail-override
(,end-call-sym
)
468 (let ((,next-sym
(resolved ,next
)))
471 ; (traversal-result ,value (unresolved (funcall ,next-sym :get-link-with-tail-override ,end-call-sym)))
472 (tail-override-for-fixed-traversal-link ,value
,next-sym
,end-call-sym
)
474 (unresolved (get-traversal-result ,end-call-sym
)))))
475 (:slam
(&rest
,slam-params-sym
)
476 (with-slam-sinks (,slam-params-sym
)
477 (let ((,next-sym
(resolved ,next
)))
479 (slam-single (resolved ,value
))
480 (unresolved (apply ,next-sym
:slam
,slam-params-sym
))))))))))
482 (defun tail-override-for-fixed-traversal-link (value next end-call
)
483 (traversal-result value
(unresolved (fixed-traversal-link-from-result-form (funcall next
:get-link-with-tail-override end-call
)))))
487 (defmacro get-traversal-result-new-end-call
(traversal-link new-end-call
)
488 `(funcall (resolved ,traversal-link
) :get-link-with-tail-override
,new-end-call
))
490 (defmacro! deferred-traversal-link-from-call-maker
(call-maker-form)
492 ((:get-link
() (get-traversal-result ,call-maker-form
))
493 (:get-link-with-tail-override
(,g
!end-call
) (get-traversal-result-new-end-call ,call-maker-form
,g
!end-call
))
494 (:slam
(&rest
,g
!slam-params
)
495 (with-slam-sinks (,g
!slam-params
)
496 (unresolved (apply ,call-maker-form
:slam
,g
!slam-params
)))))))
499 (with-traversal-result
501 (get-traversal-result ,call-maker-form
)
502 (let ((,g
!next
(resolved ,g
!next
)))
504 (slam-single (resolved ,g
!value
))
505 (unresolved (apply ,g
!next
:slam
,g
!slam-params
)))))
509 (defun confirmed-traversal-result (val)
510 (assert (typep val
'traversal-result
))
513 (defmacro with-traversal-result
((val-sym next-sym
) form
&body body
)
514 (let ((sym (gensym)))
515 `(with-slots ((,val-sym value
) (,next-sym next
))
516 ; (let ((,sym ,form)) (assert (typep ,sym 'traversal-result)) ,sym)
517 ; (confirmed-traversal-result ,form)
518 (let ((,sym
(resolved ,form
)))
519 (when (not (typep ,sym
'traversal-result
))
520 (print (list "bad type for traversal type " ,sym
',body
))
526 (defclass lazy-list
() ((call-for-first :initarg
:call-for-first
:accessor get-call-for-first
)))
529 (defmethod get-call-for-first ((list lazy-list
) (call-for-end function
))
530 (resolved (funcall (get-call-for-first-maker list
) call-for-end
)))
533 (defclass lazy-list-under-cdrs
(lazy-list)
534 ((underlying-call-for-first :initarg
:underlying-call-for-first
:accessor get-underlying-call-for-first
)
535 (cdr-count :initarg
:cdr-count
:accessor get-cdr-count
)))
537 (defclass lazy-list-with-some-persistence
(lazy-list) ())
539 (defclass lazy-list-with-persistence
(lazy-list-with-some-persistence) ())
541 (defclass lazy-list-read-point-based
(lazy-list-with-some-persistence) ((read-point :initarg
:read-point
:accessor get-read-point
)))
543 (defclass lazy-list-known-empty
(lazy-list-with-persistence) ())
545 (defclass lazy-list-list-based
(lazy-list-with-persistence)
546 ((list-head :initarg
:list-head
:accessor get-list-head
)))
548 (defclass lazy-list-pair-based
(lazy-list-with-persistence)
549 ((cons :initarg
:cons
:accessor get-cons
)))
552 (defun make-instance-2 (type &rest params
)
553 (when (eql type
'lazy-list-read-point-based
)
554 (when (not (getf params
:read-point
))
555 (error "No read-point")))
556 (apply #'make-instance type params
))
559 (defmacro lazy-list-from-call
(call)
560 (let ((call-sym (gensym)))
561 `(let ((,call-sym
,call
))
562 ; (assert (typep ,call-sym 'traversal-link))
563 (make-instance-2 'lazy-list
:call-for-first
,call-sym
))))
566 (defmacro lazy-list-from-traversal-link
(traversal-link)
567 (let ((sym (gensym)))
568 `(let ((,sym
,traversal-link
))
569 ; (assert (typep ,sym 'traversal-link))
570 (make-instance-2 'lazy-list
:call-for-first
,sym
))))
573 (defmacro deferred-lazy-list
(list-definition)
574 `(lazy-list-from-call
575 (deferred-traversal-link-from-call-maker
576 (get-call-for-first (to-lazy-list ,list-definition
)))))
580 (defparameter **in-lazy-mode
** nil
)
583 (defun in-lazy-mode ()
584 (declare (special **in-lazy-mode
**))
586 (define-compiler-macro in-lazy-mode
() `**in-lazy-mode
**)
589 (defmacro if-lazy-eager
(if-lazy if-strict
)
594 (defmacro lazy
(&body body
)
595 "Enters a \"lazy\" context - calls to functions such as tail/ defer traversal.
596 This context uses a special variable, and extends into sub-calls until overridden."
597 `(let ((**in-lazy-mode
** t
))
600 (defmacro eager
(&body body
)
601 "Enters an \"eager\" context - calls to functions such as tail/ do traversal before returning.
602 This context uses a special variable, and extends into sub-calls until overridden."
603 `(let ((**in-lazy-mode
** nil
))
608 (defparameter **respecting-thread-safety
** nil
)
610 (defstruct read-point
615 (defstruct read-point-value-resolver
618 (defstruct read-point-next-resolver
622 (defmacro respecting-lock-if-present
((lock) &body body
)
624 (bordeaux-threads::with-lock-held
(,lock
) ,@body
)
627 (defmacro respecting-read-point-lock
((read-point) &body body
)
628 (let ((lock-sym (gensym)))
629 `(let ((,lock-sym
(read-point-rp-lock ,read-point
)))
630 (respecting-lock-if-present (,lock-sym
) ,@body
))))
632 (defmacro assure-readpoint-value-resolved
(read-point)
633 (let ((sym (gensym)))
634 `(let ((,sym
(read-point-rp-value ,read-point
)))
635 (when (typep ,sym
'read-point-value-resolver
)
636 (funcall (read-point-value-resolver-run ,sym
))))))
638 (defmacro assure-readpoint-next-resolved
(read-point)
639 (let ((sym (gensym)))
640 `(let ((,sym
(read-point-rp-next ,read-point
)))
641 (when (typep ,sym
'read-point-next-resolver
)
642 (funcall (read-point-next-resolver-run ,sym
))))))
644 (defun read-point-value (read-point)
645 (assert (typep read-point
'read-point
))
646 (respecting-read-point-lock
648 (assure-readpoint-value-resolved read-point
)
649 (read-point-rp-value read-point
)))
651 (defun read-point-at-end (read-point)
652 (assert (typep read-point
'read-point
))
653 (respecting-read-point-lock
655 (assure-readpoint-next-resolved read-point
)
656 (not (read-point-rp-next read-point
))))
659 (defun read-point-advanced (read-point)
660 (assert (typep read-point
'read-point
))
661 (respecting-read-point-lock
663 (assure-readpoint-next-resolved read-point
)
664 (read-point-rp-next read-point
)))
667 (defun read-point-from-call (call &optional
(lock (when **respecting-thread-safety
** (bordeaux-threads:make-lock
))))
668 (let ((read-point nil
))
672 :rp-value
(make-read-point-value-resolver
675 (respecting-lock-if-present
677 (with-traversal-result
679 (resolved (get-traversal-result call
))
680 (setf (read-point-rp-value read-point
) (resolved value
))
681 (setf (read-point-rp-next read-point
)
682 (make-read-point-next-resolver
685 (respecting-lock-if-present
687 (setf (read-point-rp-next read-point
)
688 (let ((next (resolved next
)))
689 (when next
(read-point-from-call next
(when lock
(bordeaux-threads:make-lock
))))))))
692 (respecting-lock-if-present
694 (let ((next (resolved next
)))
695 (setf (read-point-rp-next read-point
)
696 (when next
(read-point-from-call next
(when lock
(bordeaux-threads:make-lock
)))))
698 :rp-next
(make-read-point-next-resolver
702 (respecting-lock-if-present
704 (with-traversal-result
706 (resolved (get-traversal-result call
))
707 (let ((next (resolved next
)))
708 (setf (read-point-rp-next read-point
) (when next
(read-point-from-call next
(when lock
(bordeaux-threads:make-lock
)))))
709 (setf (read-point-rp-value read-point
)
711 (if (typep value
'unresolved
)
712 (make-read-point-value-resolver
715 (respecting-lock-if-present
717 (setf (read-point-rp-value read-point
) (resolved value
)))))
721 (respecting-lock-if-present
723 (with-traversal-result
725 (resolved (get-traversal-result call
))
726 (let ((next (resolved next
)))
727 (setf (read-point-rp-next read-point
) (when next
(read-point-from-call next
(when lock
(bordeaux-threads:make-lock
)))))
728 (setf (read-point-rp-value read-point
)
730 (if (typep value
'unresolved
)
731 (make-read-point-value-resolver
734 (respecting-lock-if-present
736 (setf (read-point-rp-value read-point
) (resolved value
)))))
741 (defun read-point-built (list)
743 (lazy-list-read-point-based (get-read-point list
))
745 (read-point-from-call (get-call-for-first list
)))))
747 (defun call-for-read-point-taken-to-end (read-point)
748 (assert (typep read-point
'read-point
))
749 (standard-traversal-link
750 (build (end-call read-point
)
751 (if (read-point-at-end read-point
)
752 (unresolved (get-traversal-result end-call
))
753 (let ((advanced (read-point-advanced read-point
))) ; calc here to (potentially) advance value
754 (let ((value (read-point-rp-value read-point
)))
756 (if (typep value
'read-point-value-resolver
)
757 (unresolved (read-point-value read-point
))
759 (build end-call advanced
))))))
762 (defun call-to-detach-from-read-point (read-point)
763 (assert (typep read-point
'read-point
))
764 (standard-traversal-link
765 (build (end-call read-point
)
767 (respecting-read-point-lock
769 (let ((rp-next (read-point-rp-next read-point
)))
771 ((null rp-next
) (get-traversal-result end-call
))
774 (read-point (traversal-result (unresolved (read-point-value read-point
)) (build end-call rp-next
)))
775 (read-point-next-resolver
777 (let ((nexts-call (funcall (read-point-next-resolver-get-call rp-next
))))
780 (unresolved (read-point-value read-point
))
781 (with-traversal-result
783 (get-traversal-result-new-end-call nexts-call end-call
)
784 (let ((next (resolved next
)))
786 (fixed-traversal-link val next
)
788 (get-traversal-result end-call
))))))))))))
793 (defun lazy-list-from-read-point (read-point)
794 (make-instance-2 'lazy-list-read-point-based
:call-for-first
(call-for-read-point-taken-to-end read-point
) :read-point read-point
))
797 ; Runs in block nil (return will break out)
798 (defmacro loop-over
/ (symbol lazy-list
&body body
)
799 (let ((current-sym (gensym)) (value-sym (gensym)) (next-sym (gensym)) (top-sym (gensym)) (list-sym (gensym)))
800 "Most trivial loop construct - loops a symbol across lazy-list running body. Runs in block NIL."
801 `(let ((,list-sym
,lazy-list
))
803 (lazy-list-known-empty nil
)
804 (lazy-list-list-based (loop for
,symbol in
(get-list-head ,list-sym
) do
,@body
))
807 (let ((,current-sym
(get-call-for-first ,lazy-list
)))
810 (with-traversal-result (,value-sym
,next-sym
)
811 (resolved (get-traversal-result ,current-sym
))
812 (let ((,next-sym
(resolved ,next-sym
))
813 (,value-sym
(resolved ,value-sym
)))
815 (let ((,symbol
(resolved ,value-sym
)))
817 (setf ,current-sym
,next-sym
)
818 (go ,top-sym
)))))))))))))
820 (defmethod print-object ((lazy-list lazy-list
) stream
)
821 ; (format stream "(LIST/ #|Known Type: ~S|#" (type-of lazy-list))
822 (format stream
"(LIST/")
823 (loop-over/ elt lazy-list
(format stream
" ~S" elt
))
826 (defmacro list-to-lazy-list-call
(origin &key
(terminator-generator (lambda (rest-sym) rest-sym
)) (value-generator (lambda (rest-sym) `(car ,rest-sym
))))
827 (let* ((build-sym (gensym))
829 (end-call-sym (gensym)))
830 `(standard-traversal-link
831 (,build-sym
(,end-call-sym
,rest-sym
)
832 (if ,(funcall (eval terminator-generator
) rest-sym
)
833 (traversal-result ,(funcall (eval value-generator
) rest-sym
) (,build-sym
,end-call-sym
(cdr ,rest-sym
)))
834 (unresolved (get-traversal-result ,end-call-sym
))))
839 (defun to-lazy-list (list)
843 (make-instance-2 'lazy-list-list-based
:call-for-first
(list-to-lazy-list-call list
) :list-head list
)
844 (make-instance-2 'lazy-list-known-empty
:call-for-first
**standard-terminating-end-call
**)))
846 (let ((length (length list
)))
847 (make-instance-2 'lazy-list-with-persistence
849 (standard-traversal-link-sequence-slam
850 (build (end-call current-index
)
851 (if (eql current-index length
)
852 (unresolved (get-traversal-result end-call
))
854 (aref list current-index
)
855 (build end-call
(1+ current-index
)))))
859 (let* ((dimensions (array-dimensions list
))
860 (array-rank (array-rank list
)))
861 (make-instance-2 'lazy-list-with-persistence
863 (standard-traversal-link
864 (build (end-call current-dimension-head prior-coords current-coord
)
865 (if (eq (car current-dimension-head
) current-coord
) ; test for end of axis.
866 (unresolved (get-traversal-result end-call
))
868 (if (cdr current-dimension-head
) ; Another axis.
869 (lazy-list-from-call (build **standard-terminating-end-call
** (cdr current-dimension-head
) (append prior-coords
(list current-coord
)) 0))
870 (apply #'aref list
(append prior-coords
(list current-coord
))))
871 (build end-call current-dimension-head prior-coords
(1+ current-coord
)))))
872 (dimensions nil
0)))))))
875 (defun memoized/ (list)
876 "Caches list on first traversal (unless it's determined to already be implemented in terms of persistence)."
878 (sequence (to-lazy-list list
))
879 (lazy-list-with-some-persistence list
)
880 (lazy-list (lazy-list-from-read-point (read-point-built list
)))))
883 (defun lazy-listp (potential)
884 (typep potential
'lazy-list
))
886 (defun listp/ (potential)
887 (or (listp potential
) (typep potential
'lazy-list
)))
889 (defun list/ (&rest rest
)
890 "Lazy equivalent of CL's list function - returning a lazy-list (although one that has the parameter list at its core)."
892 (make-instance-2 'lazy-list-list-based
:call-for-first
(list-to-lazy-list-call rest
) :list-head rest
)
893 (make-instance-2 'lazy-list-known-empty
:call-for-first
**standard-terminating-end-call
**)))
896 (defun iterate/ (from-previous element
&optional
(end-before-func (constantly nil
)))
897 "Haskell's iterate function - returns element, then (funcall from-previous element), etc. against result"
898 (assert (functionp from-previous
))
900 (standard-traversal-link
901 (get-val (end-call elt
)
902 (if (funcall end-before-func elt
)
903 (unresolved (get-traversal-result end-call
))
906 (get-val end-call
(funcall from-previous elt
)))))
909 (define-compiler-macro iterate
/ (&whole form from-previous element
&optional
(end-before-func '(constantly nil
)))
910 (let ((get-val-sym (gensym))
911 (end-call-sym (gensym))
912 (end-before-precond-parameters (get-call-form-precond-parameters (function-literal-to-form end-before-func
) 1))
913 (from-previous-precond-parameters (get-call-form-precond-parameters (function-literal-to-form from-previous
) 1))
916 `(lazy-list-from-call
917 (standard-traversal-link
918 (,get-val-sym
(,end-call-sym
,elt-sym
)
919 (if (let ((,(caar end-before-precond-parameters
) ,elt-sym
)) ,(get-call-form (function-literal-to-form end-before-func
) end-before-precond-parameters nil
))
920 (unresolved (get-traversal-result ,end-call-sym
))
923 (,get-val-sym
,end-call-sym
(let ((,(caar from-previous-precond-parameters
) ,elt-sym
)) ,(get-call-form (function-literal-to-form from-previous
) from-previous-precond-parameters nil
))))))
928 ; (pprint (funcall (compiler-macro-function 'iterate/) '(iterate/ #'1+ 1 (lambda (x) (> x 20))) nil))
929 ; (defun test () (iterate/ #'1+ 1 (lambda (x) (> x 20))))
934 (defun iteratex/ (input-to-contribution initial-input
)
935 (assert (functionp input-to-contribution
))
936 (labels ((build (input)
939 (let ((current-input input
))
942 (let ((contribution (funcall input-to-contribution current-input
)))
943 (destructuring-bind (primary-result
945 (emissions #|
(list current-input
) |
# nil emissions-supplied-p
)
946 (emission nil emission-supplied-p
)
949 (next-input primary-result
))
951 (assert (not (and emissions-supplied-p emission-supplied-p
))) ; can *NOT* supply both
953 (exit-before (return (call-for-end)))
954 ((and emissions-supplied-p
(null/ emissions
)) (setq current-input next-input
) (go top
))
956 (if emission-supplied-p
961 (build next-input
))))
962 (labels ((build-for-read-point (read-point)
963 (values (read-point-value read-point
)
964 (let ((advanced (read-point-advanced read-point
)))
965 (if (read-point-at-end advanced
)
969 (lambda () (build-for-read-point advanced
)))))))
970 (return (build-for-read-point (read-point-built (to-lazy-list emissions
))))))))))))))))
971 (lazy-list-from-call (build initial-input
))))
973 (defun to-list (list)
974 "Returns the proper list corresponding to the passed-in list designator - attempts to minimize work involved if list is a CL sequence
975 or a lazy-list based upon a fixed container"
977 (lazy-list-list-based (get-list-head list
))
978 (lazy-list-pair-based (destructuring-bind (first . second
) (get-cons list
) (list first second
)))
981 (loop-over/ elt list
(push elt result
))
984 (sequence (map 'list
#'identity list
))))
986 (defun to-array (list &rest array-params
)
987 "Returns the array corresponding to the passed-in list designator - attempts minimize work involved if list is a CL sequence or lazy-list
988 based upon a fixed container"
990 (sequence (apply #'make-array
(length list
) :initial-contents list array-params
))
994 (loop-over/ elt
(to-lazy-list list
) (progn (push elt result
) (incf count
)))
995 (apply #'make-array count
:initial-contents
(nreverse result
) array-params
)))))
998 (defun string-from-chars/ (chars-list)
999 "Returns a string from the supplied chars list"
1000 (typecase chars-list
1002 (array (let ((result (make-string (length chars-list
))))
1004 for elt across chars-list do
1005 (setf (aref result i
) elt
))
1008 (with-output-to-string (str)
1009 (loop for elt in chars-list do
1010 (write-char elt str
))))
1012 (with-output-to-string (str)
1013 (loop-over/ elt
(to-lazy-list chars-list
)
1014 (write-char elt str
)))
1018 (loop-over/ elt
(to-lazy-list chars-list
) (progn (push elt result
) (incf count
)))
1019 (let ((string (make-string count
)))
1020 (loop for index from
(1- count
) downto
0
1021 for elt in result do
1022 (setf (aref string index
) elt
))
1028 (defun to-string-irresolute (chars-list)
1029 (let ((char-accumulator-r nil
)
1030 (char-count-accumulator 0))
1032 (let ((current-call (get-call-for-first (to-lazy-list chars-list
)))
1035 (with-traversal-result (value next
)
1036 (get-traversal-result (resolved current-call
))
1038 (let ((next (resolved next
)))
1042 (let ((value (resolved value
)))
1045 (push value char-accumulator-r
)
1046 (incf char-count-accumulator
)
1047 (setq current-call next
)
1049 (let ((string (make-string char-count-accumulator
)))
1050 (loop for i from
(1- char-count-accumulator
) downto
0 do
1051 (setf (aref string i
) (pop char-accumulator-r
)))
1053 (setq unresolved
(make-unresolved :call
#'run
)))))))
1058 (let ((char-accumulator-r nil
)
1059 (char-count-accumulator 0)
1060 (current-call (resolved (get-call-for-first (to-lazy-list chars-list
))))
1063 (with-traversal-result (value next
)
1064 (get-traversal-result current-call
)
1065 (let ((next (resolved next
)))
1068 (push (resolved value
) char-accumulator-r
)
1069 (incf char-count-accumulator
)
1070 (setq current-call next
)
1072 (let ((string (make-string char-count-accumulator
)))
1073 (loop for i from
(1- char-count-accumulator
) downto
0 do
1074 (setf (aref string i
) (pop char-accumulator-r
)))
1076 (setq unresolved
(make-unresolved :call
#'run
))))
1081 (defmethod to-string ((chars-list sequence
))
1082 "Returns a string from the supplied chars list"
1083 (string-from-chars/ chars-list
))
1086 (defmethod to-string ((chars-list lazy-list
))
1087 "Returns a string from the supplied chars list"
1088 (string-from-chars/ chars-list
))
1092 (defun length/ (list)
1093 "Returns the length of the supplied list, evaluating the list to the end if lazy to measure its length."
1095 (sequence (length list
))
1096 (lazy-list-list-based (length (get-list-head list
)))
1097 (lazy-list-pair-based 2)
1098 (lazy-list-known-empty 0)
1100 (let ((current (read-point-built (to-lazy-list list
)))
1102 (loop while
(not (read-point-at-end current
)) do
1103 (setq current
(read-point-advanced current
))
1107 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
1109 (defun full-cdr-based-form-resolution (form)
1110 ; Attempts to preserve evaluation order of the full expression.
1111 (let ((form-under-cdrs form
)
1113 (loop while
(and (consp form-under-cdrs
) (let ((control (car form-under-cdrs
))) (or (eql control
'cdr
/) (eql control
'nthcdr
/)))) do
1114 (push (butlast form-under-cdrs
) cdr-items-r
)
1115 (setq form-under-cdrs
(car (last form-under-cdrs
))))
1116 (let ((sum-of-known-numerics
1117 (loop for elt in cdr-items-r sum
1118 (if (eql (car elt
) 'cdr
/)
1120 (destructuring-bind (to-drop)
1122 (if (integerp to-drop
)
1125 (unevaluated-to-drops
1126 (loop for elt in cdr-items-r append
1127 (when (eql (car elt
) 'nthcdr
/)
1128 (destructuring-bind (to-drop)
1130 (unless (integerp to-drop
)
1131 (list to-drop
)))))))
1133 ((and (zerop sum-of-known-numerics
) (null unevaluated-to-drops
)) form-under-cdrs
)
1134 ((and (eql sum-of-known-numerics
1) (null unevaluated-to-drops
)) `(cdr/-implementation
,form-under-cdrs
))
1135 ((and (null unevaluated-to-drops
) `(nthcdr/-implementation
,sum-of-known-numerics
,form-under-cdrs
)))
1137 (if (and cdr-items-r
(eql (caar cdr-items-r
) 'nthcdr
/) (not (integerp (cadar cdr-items-r
))))
1138 (let ((inner-most-to-drop-sym (gensym))
1139 (sub-list-sym (gensym)))
1140 `(let ((,inner-most-to-drop-sym
,(car unevaluated-to-drops
))
1141 (,sub-list-sym
,form-under-cdrs
))
1142 (nthcdr/-implementation
(+ ,@(when (plusp sum-of-known-numerics
) (list sum-of-known-numerics
)) ,inner-most-to-drop-sym
,@(cdr unevaluated-to-drops
)) ,sub-list-sym
)))
1143 (let ((sub-list-sym (gensym)))
1144 `(let ((,sub-list-sym
,form-under-cdrs
))
1145 (nthcdr/-implementation
(+ ,@(when (plusp sum-of-known-numerics
) (list sum-of-known-numerics
)) ,@unevaluated-to-drops
) ,sub-list-sym
)))))))))
1150 (defun cdr/-implementation
(list)
1151 "Equivalent of Haskell's tail function or CL's CDR - traverses in eager context, defers in lazy."
1153 (lazy-list-known-empty list
)
1154 (list (to-lazy-list (cdr list
)))
1155 (lazy-list-list-based (to-lazy-list (cdr (get-list-head list
))))
1159 (lazy-list-under-cdrs
1160 (let ((new-cdr-count (1+ (get-cdr-count list
)))
1161 (underlying-call-for-first (get-underlying-call-for-first list
)))
1162 (assert (> new-cdr-count
0))
1163 (make-instance-2 'lazy-list-under-cdrs
1165 (standard-traversal-link
1167 (let ((current (resolved (with-traversal-result (value next
) (resolved (get-traversal-result-new-end-call underlying-call-for-first end-call
)) next
))))
1168 (loop for i from
2 to new-cdr-count
1171 (when current
(with-traversal-result (value next
) (resolved (get-traversal-result current
)) (setq current
(resolved next
)))))
1173 (get-traversal-result current
)
1174 (traversal-result nil nil
))))
1176 :cdr-count new-cdr-count
1177 :underlying-call-for-first underlying-call-for-first
)))
1179 (let ((call-for-first (get-call-for-first list
)))
1180 (make-instance-2 'lazy-list-under-cdrs
1182 (standard-traversal-link
1184 (with-traversal-result
1186 (get-traversal-result-new-end-call call-for-first end-call
)
1188 (get-traversal-result next
))))
1191 :underlying-call-for-first call-for-first
))))
1193 (lazy-list-read-point-based
1194 (let ((read-point (get-read-point list
)))
1195 (if (read-point-at-end read-point
)
1196 (make-instance-2 'lazy-list-known-empty
:call-for-first
**standard-terminating-end-call
**)
1197 (let ((advanced (read-point-advanced read-point
)))
1198 (make-instance-2 'lazy-list-read-point-based
:call-for-first
(call-for-read-point-taken-to-end advanced end-call
) :read-point advanced
)))))
1201 (case (type-of list
) ; tail keeps persistence
1202 ((lazy-list-with-persistence lazy-list-with-some-persistence
) (type-of list
))
1205 (with-traversal-result
1207 (get-traversal-result (get-call-for-first list
))
1208 (let ((next (resolved next
)))
1209 (cond (next) ; Man not having this check was HARD to track down. . . .
1210 (t **standard-terminating-end-call
**)))))))))
1211 (t (cdr/ (to-lazy-list list
)))))
1212 (defun cdr/ (list) (cdr/-implementation list
))
1213 (define-compiler-macro cdr
/ (&whole form list
)
1214 (full-cdr-based-form-resolution form
))
1219 "Equivalent of Haskell's tail function (or cdr/ ) - traverses in eager context, defers in lazy."
1221 (define-compiler-macro tail
/ (list)
1226 "Equivalent of CL's car/first or Haskell's head - returns first value in list, or nil if list is empty"
1229 (lazy-list-list-based (car (get-list-head list
)))
1231 (with-traversal-result (value next
) (get-traversal-result (get-call-for-first list
)) (resolved value
)))
1232 (t (with-traversal-result (value next
) (get-traversal-result (get-call-for-first (to-lazy-list list
))) (resolved value
)))))
1235 "Equivalent of CL's car/first or Haskell's head - returns first value in list, or nil if list is empty"
1237 (define-compiler-macro head
/ (list) `(car/ ,lst
))
1239 (defun first/ (list)
1240 "Equivalent of CL's car/first or Haskell's head - returns first value in list, or nil if list is empty"
1242 (define-compiler-macro head
/ (list) `(cdr/ ,lst
))
1244 (defmacro build-car-things
()
1246 ,@(loop for len from
2 to
5 collect
1248 ,@(labels ((build-it (bits-left val
)
1249 (if (zerop bits-left
)
1250 (list nil
#'identity
)
1251 (destructuring-bind (char-list func
)
1252 (build-it (1- bits-left
) (floor (/ val
2)))
1254 (list (cons #\a char-list
) (lambda (elt) `(car/ ,(funcall func elt
))))
1255 (list (cons #\d char-list
) (lambda (elt) `(cdr/ ,(funcall func elt
)))))))))
1256 (loop for combo from
0 to
(1- (expt 2 len
)) collect
1257 (destructuring-bind (char-list func
)
1258 (build-it len combo
)
1259 ; (format t ":~A" (concatenate 'string "c" (map 'string #'identity char-list) "r/"))
1262 (labels ((make-core-string (char-list)
1263 (concatenate 'string
"c" (map 'string
#'identity char-list
) "r"))
1264 (th (n) (case n
(1 "1st") (2 "2nd") (3 "3rd") (t (format nil
"~Ath" n
)))))
1266 (defun ,(read-from-string (concatenate 'string
(make-core-string char-list
) "/"))
1268 ,(let ((a-count (length (remove-if-not (lambda (elt) (eql elt
#\a)) char-list
)))
1269 (d-count (length (remove-if-not (lambda (elt) (eql elt
#\d
)) char-list
))))
1272 (format nil
"Returns list-designator's list with ~A item skipped, as a lazy-list" d-count
))
1274 (format nil
"Returns ~A element in list-designator" (th (1+ d-count
))))
1276 (let ((trailing-d-count (length (loop for char in
(reverse char-list
) while
(eql #\d char
) collect char
))))
1277 (case trailing-d-count
1278 (0 (format nil
"~A/ of first element in list-designator" (make-core-string (butlast char-list
))))
1280 (format nil
"~A/ of ~A element in list-designator" (make-core-string (butlast char-list
(1+ trailing-d-count
))) (th trailing-d-count
))))))))
1281 ,(funcall func
'list-designator
))
1282 ,(let ((list-sym (gensym)))
1283 `(define-compiler-macro ,(read-from-string (concatenate 'string
(make-core-string char-list
) "/"))
1285 ,(funcall func list-sym
))))))))))))
1290 ; returns head and tail as successive values
1291 (defun head-tail/ (list)
1292 "Returns head and tail of list as successive values, and whether or not head is a valid value as the third result."
1294 (list (values (car list
) (to-lazy-list (cdr list
)) (consp list
)))
1295 (lazy-list-list-based (destructuring-bind (head . tail
) (get-list-head list
) (values head
(to-lazy-list tail
) (consp (get-list-head list
)))))
1296 (t (with-traversal-result (head tail-call
) (resolved (get-traversal-result (get-call-for-first (to-lazy-list list
))))
1297 (let ((tail-call (resolved tail-call
)))
1299 (values (resolved head
) (lazy-list-from-call tail-call
) t
)
1304 (defun nthcdr/-implementation
(to-drop list
)
1305 "Equivalent to CL's nthcdr or Haskell's drop - returns list with to-drop elements skipped - traversing at point of call in eager context,
1306 deferring traversal in lazy context."
1307 (labels ((nthcdr-known-lazy-list/ (list)
1309 (lazy-list-from-call
1310 (deferred-traversal-link-from-call-maker
1311 (standard-traversal-link
1313 (let ((current (get-call-for-first list
)))
1314 (loop for i from
1 to to-drop while current do
1315 (setq current
(resolved (with-traversal-result (value next
) (get-traversal-result current
) (resolved next
)))))
1317 (get-traversal-result-new-end-call current end-call
)
1318 (get-traversal-result end-call
))))
1320 (lazy-list-from-call
1321 (let ((current (get-call-for-first list
)))
1322 (loop for i from
1 to to-drop while current do
1323 (setq current
(resolved (with-traversal-result (value next
) (get-traversal-result current
) (resolved next
)))))
1326 **standard-terminating-end-call
**)))
1329 (standard-traversal-link
1331 (let ((current (get-call-for-first list
)))
1332 (loop for i from
1 to to-drop while current do
1333 (setq current
(resolved (with-traversal-result (value next
) (get-traversal-result current
) (resolved next
)))))
1335 (get-traversal-result-new-end-call current end-call
)
1336 (get-traversal-result end-call
))))
1342 (list (to-lazy-list (nthcdr to-drop list
)))
1343 (lazy-list-list-based (to-lazy-list (nthcdr to-drop
(get-list-head list
))))
1345 (nthcdr-known-lazy-list/ list
))
1346 (t (nthcdr-known-lazy-list/ (to-lazy-list list
))))))
1347 (defun nthcdr/ (to-drop list
) (nthcdr/-implementation to-drop list
))
1348 (define-compiler-macro nthcdr
/ (&whole form to-drop list
)
1349 (full-cdr-based-form-resolution form
))
1354 (defun drop/ (to-drop list
)
1355 "Equivalent to CL's nthcdr or Haskell's drop - returns list with to-drop elements skipped - traversing at point of call in eager context,
1356 deferring traversal in lazy context."
1357 (nthcdr/ to-drop list
))
1358 (define-compiler-macro drop
/ (to-drop list
)
1359 `(nthcdr/ ,to-drop
,list
))
1364 "Returns nil if list has contents, a value otherwise. Will only traverse a single element for lazy-lists"
1368 (sequence (zerop (length list
)))
1369 (lazy-list-list-based (null (get-list-head list
)))
1370 (lazy-list-known-empty t
)
1371 (lazy-list (with-traversal-result (value next
) (resolved (get-traversal-result (get-call-for-first list
))) (not (resolved next
))))
1374 (defun non-null/ (list)
1377 (define-compiler-macro non-null
/ (list)
1378 `(not (null/ ,list
)))
1383 (defun take/ (to-take list
)
1384 "Returns a lazy-list of the first to-take elements from list. Performance note: The resulting lazy-list will tend to maintain a reference to the original list, convert to a static container
1385 (via to-list of to-array) to break this link."
1386 (assert (integerp to-take
))
1388 (make-instance-2 'lazy-list-known-empty
:call-for-first
**standard-terminating-end-call
**)
1389 (lazy-list-from-call
1390 (standard-traversal-link
1391 (build (end-call current-call num-left
)
1393 (with-traversal-result
1395 (get-traversal-result current-call
)
1396 (let ((next (resolved next
)))
1398 (let ((new-num-left (1- num-left
)))
1399 (traversal-result value
(build end-call
(if (zerop new-num-left
) nil next
) new-num-left
)))
1400 (unresolved (get-traversal-result end-call
)))))
1401 (unresolved (get-traversal-result end-call
))))
1402 ((get-call-for-first (to-lazy-list list
)) to-take
)))))
1407 (defun split-when---experimental/ (predicate list
)
1408 "Returns lazy-lists for before-split-point, and split-point-and-after, as first and second value results"
1409 (labels ((get-split-result ()
1410 (labels ((split-for-proper-list (list)
1411 (let ((current list
)
1412 (before-predicate-r nil
))
1416 (let ((val (car current
)))
1417 (when (not (funcall predicate val
))
1418 (setq current
(cdr current
))
1419 (push val before-predicate-r
)))))
1420 (values (to-lazy-list (nreverse before-predicate-r
)) (to-lazy-list current
)))))
1421 (let* ((list (to-lazy-list list
))
1422 (current (read-point-built list
))
1423 (before-predicate-r nil
))
1426 (when (not (read-point-at-end current
))
1427 (let ((val (read-point-value current
)))
1428 (when (not (funcall predicate val
))
1429 (setq current
(read-point-advanced current
))
1430 (push val before-predicate-r
)
1433 (to-lazy-list (nreverse before-predicate-r
))
1435 (lazy-list-read-point-based (lazy-list-from-read-point current
))
1436 (lazy-list-with-persistence (make-instance-2 'lazy-list-with-persistence
:call-for-first
(call-to-detach-from-read-point current
)))
1437 (t (make-instance-2 'lazy-list
:call-for-first
(call-to-detach-from-read-point current
)))))))))
1439 (let ((lock (make-thread-lock))
1442 (result-second nil
))
1443 (labels ((ensure-result ()
1444 (when (not result-known
) (respecting-lock-if-present (lock) (when (not result-known
) (multiple-value-setq (result-first result-second
) (get-split-result)) (setq result-known t
))))))
1446 (lazy-list-from-call (lambda () (ensure-result) (funcall (get-call-for-first result-first
))))
1447 (lazy-list-from-call (lambda () (ensure-result) (funcall (get-call-for-first result-second
)))))))
1448 (get-split-result))))
1452 (defun intersperse/ (val list
)
1453 "Equivalent of Haskell's intersperse function - returns a lazy-list of val interspersed between elements of list. If list is of length 0 or 1, val does not appear."
1454 (let ((traversal-result (resolved (get-traversal-result (get-call-for-first (to-lazy-list list
))))))
1455 (let ((next (resolved (get-next traversal-result
))))
1457 (lazy-list-from-call
1458 (standard-traversal-link
1459 (build (end-call current-value current-resolved-next
)
1462 (fixed-traversal-link-from-result-form
1463 (if current-resolved-next
1464 (with-traversal-result
1466 (get-traversal-result current-resolved-next
)
1467 (let ((next (resolved next
)))
1471 (build end-call value next
))
1472 (get-traversal-result end-call
))))
1473 (get-traversal-result end-call
)))))
1474 ((get-value traversal-result
) next
)))
1475 (make-instance-2 'lazy-list-known-empty
:call-for-first
**standard-terminating-end-call
**)))))
1478 ; returns 3 values - lazy-list to predicate true, lazy-list of remainder, and (lambda () (values value true-if-found)) at predicate true
1479 (defun split-on-test/ (test list
)
1480 (let* ((split-value-known nil
)
1481 (known-split-value nil
)
1482 (known-post-value-remainder nil
)
1483 (rest-of-pre-predicate-read-point
1484 (read-point-from-call
1485 (standard-traversal-link
1486 (build (end-call current-read-point
)
1487 (if (read-point-at-end current-read-point
)
1489 (setq rest-of-pre-predicate-read-point
(read-point-from-call **standard-terminating-end-call
**))
1490 (setq known-post-value-remainder
(read-point-from-call **standard-terminating-end-call
**))
1491 (get-traversal-result end-call
))
1492 (let ((value (read-point-value current-read-point
))
1493 (advanced (read-point-advanced current-read-point
)))
1494 (if (funcall test value
)
1496 (setq known-split-value value
)
1497 (setq split-value-known t
)
1498 (setq rest-of-pre-predicate-read-point
(read-point-from-call **standard-terminating-end-call
**))
1499 (setq known-post-value-remainder advanced
)
1500 (get-traversal-result end-call
))
1502 (setq rest-of-pre-predicate-read-point advanced
)
1503 (traversal-result value
(build end-call advanced
)))))))
1504 ((read-point-built (to-lazy-list list
)))))))
1506 (lazy-list-from-read-point rest-of-pre-predicate-read-point
)
1507 (lazy-list-from-call
1508 (standard-traversal-link
1510 (loop while
(progn (read-point-at-end rest-of-pre-predicate-read-point
) (not known-post-value-remainder
)) do
(setq rest-of-pre-predicate-read-point
(read-point-advanced rest-of-pre-predicate-read-point
)))
1511 (get-traversal-result-new-end-call (call-to-detach-from-read-point known-post-value-remainder
) end-call
))
1514 (loop while
(progn (read-point-at-end rest-of-pre-predicate-read-point
) (not known-post-value-remainder
)) do
(setq rest-of-pre-predicate-read-point
(read-point-advanced rest-of-pre-predicate-read-point
)))
1515 (values known-split-value split-value-known
)))))
1519 (defun split-on-test-to-first-non-empty-before/ (test list
)
1520 (multiple-value-bind (before after call
)
1521 (split-on-test/ test list
)
1522 (let ((before before
)
1525 (let ((before-null (null/ before
))
1526 (after-null (null/ after
)))
1527 (loop while
(and before-null
(not after-null
)) do
1528 (multiple-value-setq (before after call
)
1529 (split-on-test/ test after
))
1530 (setq before-null
(null/ before
))
1531 (setq after-null
(null/ after
)))
1532 (multiple-value-bind (split-val split-val-present
)
1534 (if (and before-null after-null
(not split-val-present
))
1536 (values split-val split-val-present before before-null after after-null
)))))))
1539 ; returns list of list, value, list, value, list, value, list where value = something that triggers test
1540 (defun split-down-on-test/ (test list
&key
(keep-split-causing-elements nil
) (keep-empty-non-split t
) (process-split-causing-element #'identity
) (process-non-split-causing-elements-list #'identity
))
1541 (lazy-list-from-call
1542 (if keep-split-causing-elements
1543 (standard-traversal-link
1544 (build-keep (end-call list
)
1545 (multiple-value-bind (before after val-maker
)
1546 (split-on-test/ test list
)
1547 (multiple-value-bind (v exists
)
1550 ((and exists
(null/ before
) (not keep-empty-non-split
)) (traversal-result (funcall process-split-causing-element v
) (build-keep end-call after
)))
1551 (exists (traversal-result
1552 (funcall process-non-split-causing-elements-list before
)
1553 (fixed-traversal-link (funcall process-split-causing-element v
) (build-keep end-call after
))))
1554 ((not (null/ before
)) (traversal-result
1555 (funcall process-non-split-causing-elements-list before
)
1557 (t (unresolved (get-traversal-result end-call
)))))))
1559 (standard-traversal-link
1560 (build-no-keep (end-call list
)
1561 ; Find first non-null "before"
1562 ; (progn (to-list list) (print "list good 1"))
1563 (multiple-value-bind (before after call
)
1564 (split-on-test/ test list
)
1565 (let ((before before
)
1568 (let ((before-null (null/ before
))
1569 (after-null (null/ after
)))
1570 (unless keep-empty-non-split
1571 (loop while
(and before-null
(not after-null
)) do
1572 (multiple-value-setq (before after call
)
1573 (split-on-test/ test after
))
1574 (setq before-null
(null/ before
))
1575 (setq after-null
(null/ after
))))
1576 (if (and before-null after-null
)
1577 (unresolved (get-traversal-result end-call
))
1581 (build-no-keep end-call after
))))))))
1588 (defun map/ (function first
&rest other-lazy-lists
)
1589 (assert (functionp function
))
1590 (lazy-list-from-call
1591 (standard-traversal-link (build (end-call callers-list
)
1593 (loop for caller in callers-list collect
1594 (with-traversal-result (value next
)
1595 (get-traversal-result caller
)
1596 (let ((next (resolved next
)))
1602 (apply function
(mapcar (lambda (elt) (resolved (cdr elt
))) result-stash
))
1603 (build end-call
(mapcar #'car result-stash
)))
1604 (unresolved (get-traversal-result end-call
)))))
1606 (lambda (elt) (get-call-for-first (to-lazy-list elt
)))
1607 (cons first other-lazy-lists
))))))
1612 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
1613 (defparameter **sequence-sources
**
1615 (:standard-lazy-list
1617 `(:get-first-link
(get-call-for-first (to-lazy-list ,input
))
1618 :get-value-next-extractor
,(lambda (link-sym exit-form
)
1619 `(with-traversal-result (value next
)
1620 (get-traversal-result ,link-sym
)
1621 (let ((next (resolved next
)))
1622 (unless next
,exit-form
)
1623 (values value next
))))
1624 :get-value-resolution
,(lambda (value-sym) `(resolved ,value-sym
)))))
1629 ;? Temporarily shelved.
1631 (define-compiler-macro map
/ (&whole form func first
&rest rest
)
1632 (let* ((call-form-precond-parameters (get-call-form-precond-parameters (function-literal-to-form func
) (1+ (length rest
))))
1633 (result-sym-lists (mapcar #'list
* (first call-form-precond-parameters
) (loop for i from
0 to
(length rest
) collect
(list (gensym) (gensym) (gensym)))))
1634 (per-source-generators (loop for input in
(cons first rest
) collect
(funcall (second (assoc :standard-lazy-list
**sequence-sources
**)) input
)))
1635 (end-call-sym (gensym))
1638 (value-sym (gensym))
1639 (build-func-sym (gensym)))
1640 `(lazy-list-from-call
1641 (standard-traversal-link
1642 (,build-func-sym
(,end-call-sym
,@(mapcar #'fourth result-sym-lists
))
1644 (let ,(loop for result-sym-list in result-sym-lists append
1645 (list (second result-sym-list
) (third result-sym-list
)))
1646 ,@(loop for result-sym-list in result-sym-lists
1647 for per-source-generator in per-source-generators
1649 `(multiple-value-bind (,value-sym
,next-sym
)
1650 ,(funcall (getf per-source-generator
:get-value-next-extractor
)
1651 (fourth result-sym-list
)
1652 `(return-from ,exit-sym
(unresolved (get-traversal-result ,end-call-sym
))))
1653 (setq ,(second result-sym-list
) ,next-sym
)
1654 (setq ,(third result-sym-list
) ,value-sym
)))
1656 (let ,(loop for result-sym-list in result-sym-lists collect
`(,(first result-sym-list
) ,(third result-sym-list
)))
1657 ,(get-call-form (function-literal-to-form func
) call-form-precond-parameters
(mapcar (rcurried #'getf
:get-value-resolution
) per-source-generators
)))
1658 (,build-func-sym
,end-call-sym
,@(mapcar #'second result-sym-lists
))))))
1659 ; ,(mapcar (lambda (input) `(get-call-for-first (to-lazy-list ,input))) (cons first rest))
1660 ,(mapcar (rcurried #'getf
:get-first-link
) per-source-generators
)
1665 ; (funcall (compiler-macro-function 'map/) '(map/ #'1+ '(1 2 3 4)) nil)
1666 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (lambda (x) (* x 2)) '(1 2 3 4)) nil))
1667 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (lambda (x y) (* x y 2)) '(1 2 3 4) '(5 6 7 8)) nil))
1668 ; (defun test () (map/ (lambda (x y) (* x y 2)) '(1 2 3 4) '(5 6 7 8)))
1669 ; (defun test () (map/ #'+ '(1 2 3 4) '(5 6 7 8)))
1670 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (curried (curried #'+ 100) 200) '(1 2 3 4)) nil))
1671 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (curried (curried (lambda (a b c) (+ a b c)) 100) 200) '(1 2 3 4)) nil))
1672 ; (defun test () (map/ (curried (curried (lambda (a b c) (+ a b c)) 100) 200) '(1 2 3 4)))
1673 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (composed #'1+ #'1+) '(1 2 3 4)) nil))
1674 ; (defun test () (map/ (composed #'1+ #'1+) '(1 2 3 4)))
1675 ; (pprint (funcall (compiler-macro-function 'map/) '(map/ (constantly 69) '(1 2 3 4)) nil))
1681 (defun split-positional/ (positional list
)
1682 "Splits on positional - positional can be an integer zero-index, a function
1683 (that validates that an index is a split-point), or a list of indices that is assumed to already be sorted."
1684 (typecase positional
1685 (integer (multiple-value-bind (before after call
)
1686 (split-on-test/ (lambda (elt) (= (cdr elt
) positional
)) (map/ (lambda (elt pos
) (cons elt pos
)) list
(iterate/ #'1+ 0)))
1687 (multiple-value-bind (split-val split-val-valid
)
1689 (values (map/ #'car before
) (map/ #'car
(append/ (when split-val-valid split-val
) after
))))))
1692 (typecase positional
1693 (function (map/ positional
(iterate/ #'1+ 0)))
1696 (lambda (elt) (eql (car elt
) (first/ (cdr elt
))))
1700 (destructuring-bind (index . remainder
) elt
(cons (1+ index
) (if (eql index
(car/ remainder
)) (cdr/ remainder
) remainder
)))))
1701 (cons 0 positional
)))))))
1702 (labels ((build (split-remainder)
1704 (multiple-value-bind (head tail valid
)
1705 (head-tail/ split-remainder
)
1709 (values (list/ head
) (lambda () nil nil
))
1710 (multiple-value-bind (th tt tv
)
1713 (values (list/ head
) (build tail
))
1714 (values (list*/ head th
) (build tt
)))))
1715 (values head
(build tail
)))
1717 (map/ (curried #'map
/ #'car
) (lazy-list-from-call (build (split-down-on-test/ #'cdr
(map/ #'cons list split-masks
) :keep-split-causing-elements t
:keep-empty-non-split nil
)))))))))
1721 (defun take-while/ (test list
)
1722 "Returns a lazy-list representing elements of list while test (run against values) returns true. Performance note: Will tend to maintain reference to the original list,
1723 create a new static list (via to-list or to-array) if this is a concern."
1724 (assert (functionp test
))
1725 (lazy-list-from-call
1726 (standard-traversal-link
1727 (build (end-call current-call
)
1729 (with-traversal-result
1731 (get-traversal-result current-call
)
1732 (let ((next (resolved next
)))
1734 (let ((value (resolved value
)))
1735 (if (funcall test value
)
1736 (traversal-result value
(build end-call next
))
1737 (unresolved (get-traversal-result end-call
))))
1738 (unresolved (get-traversal-result end-call
)))))
1739 (unresolved (get-traversal-result end-call
))))
1740 ((resolved (get-call-for-first (to-lazy-list list
)))))))
1744 (defun drop-while/ (test list
)
1745 "Returns the subset of list after test returns false - in eager context, traverses immediately - in lazy, upon first traversal of resultant lazy-list. Performance note: If list uses
1746 some form of memoization/caching, and another instance has \"cached ahead\", the result lazy-list will be bound to the cache until it can overtake it."
1747 (assert (functionp test
))
1748 (labels ((get-read-point-after-test ()
1749 (let ((current (read-point-built (to-lazy-list list
))))
1752 (when (and (not (read-point-at-end current
)) (funcall test
(read-point-value current
)))
1753 (setq current
(read-point-advanced current
))
1757 (lazy-list-from-call (fixed-traversal-link-from-result-form (get-traversal-result (call-to-detach-from-read-point (get-read-point-after-test)))))
1758 (lazy-list-from-call (call-to-detach-from-read-point (get-read-point-after-test))))))
1761 (defun position/ (item list
&key
(test #'eql
))
1762 "Returns the first 0-index of item in list that satisfies test, nil if not found"
1763 (let ((current (read-point-built (to-lazy-list list
)))
1767 (when (and (not (read-point-at-end current
)) (not (funcall test
(read-point-value current
) item
)))
1768 (setq current
(read-point-advanced current
))
1771 (if (read-point-at-end current
)
1777 (defun nth/ (index list
)
1778 "Equivalent of CL's NTH; but traverses CL sequences or lazy-lists"
1779 (assert (integerp index
))
1781 (array (aref list index
))
1782 (list (nth index list
))
1784 (let ((read-point (read-point-built (to-lazy-list list
)))
1786 (setq list nil
) ; to help make "list" eligible for gc.
1787 (loop for i from
1 to index
1788 while
(not (setq known-at-end
(read-point-at-end read-point
)))
1790 (setq read-point
(read-point-advanced read-point
)))
1791 (unless known-at-end
1792 (read-point-value read-point
))))))
1795 (defun second/ (list)
1796 "Like CL's second; but can acommodate lazy-lists or CL sequences"
1799 (define-compiler-macro second
/ (list) `(cadr/ ,list
))
1801 (defun third/ (list)
1802 "Like CL's third; but can acommodate lazy-lists or CL sequences"
1803 (car/ (cdr/ (cdr/ list
))))
1804 (define-compiler-macro third
/ (list) `(caddr/ ,list
))
1808 (defun tails/ (list)
1809 "Returns list of lists, with each list being the (cdr/) of the previous one. Final list in sequence is empty list."
1810 (labels ((tails-list-for-proper-list (list)
1811 (make-instance-2 'lazy-list-with-persistence
1813 (standard-traversal-link
1814 (build (end-call remainder
)
1816 (traversal-result (to-lazy-list remainder
) (build end-call
(cdr remainder
)))
1817 (traversal-result (list/) end-call
)))
1820 (list (tails-list-for-proper-list list
))
1821 (lazy-list-list-based (tails-list-for-proper-list (get-list-head list
)))
1823 (let ((new-class-type
1825 ((typep list
'lazy-list-with-persistence
) 'lazy-list-with-persistence
) ; list based or with full persist, this persist (minor calc)
1827 ((typep list
'lazy-list-with-some-persistence
) 'lazy-list-with-some-persistence
) ; will not grant the memoize - may want memoized to
1828 ; surrender the readpoint
1830 (make-instance-2 new-class-type
1832 (standard-traversal-link
1833 (build (end-call call
)
1834 (with-traversal-result (value next
)
1835 (get-traversal-result call
)
1836 (let ((next (resolved next
)))
1838 (let ((value (resolved value
)))
1840 (make-instance-2 new-class-type
:call-for-first
(fixed-traversal-link value next
))
1841 (build end-call next
)))
1842 (traversal-result (list/) (fixed-traversal-link-from-result-form (get-traversal-result end-call
)))))))
1843 ((get-call-for-first (to-lazy-list list
))))))))))
1852 (defun concat/ (list)
1853 (lazy-list-from-call
1854 (macrolet! ((do-slam (params-sym body end-call-sym
)
1856 (with-slam-sinks (,params-sym
)
1857 (labels ((,g
!slam-func
(,g
!tlc
,g
!accum
)
1858 (with-traversal-result (,g
!sub-list
,g
!call-for-next
)
1859 (resolved (get-traversal-result ,g
!tlc
))
1860 (let ((,g
!call-for-next
(resolved ,g
!call-for-next
)))
1861 (if ,g
!call-for-next
1862 (slam-for-continue (to-lazy-list (resolved ,g
!sub-list
))
1864 (,g
!slam-func
,g
!call-for-next
(+ ,g
!count
,g
!accum
))))
1865 (end-call-thing ,end-call-sym
,g
!accum
))))))
1866 (,g
!slam-func top-level-call
0))))))
1867 (standard-traversal-link-parametric
1868 (build (end-call top-level-call
)
1869 (with-traversal-result (sub-list call-for-next-sublist
)
1870 (resolved (get-traversal-result top-level-call
))
1871 (let ((call-for-next-sublist (resolved call-for-next-sublist
)))
1872 (if call-for-next-sublist
1874 (get-traversal-result-new-end-call
1875 (get-call-for-first (to-lazy-list (resolved sub-list
)))
1876 (unresolved (build end-call call-for-next-sublist
))))
1877 (unresolved (get-traversal-result end-call
))))))
1878 ((get-call-for-first (to-lazy-list list
)))))))
1881 (defun append/ (&rest list-of-lists
)
1882 (if (cdr list-of-lists
) ; i.e. more than one
1883 (concat/ list-of-lists
)
1884 (to-lazy-list (first list-of-lists
))))
1886 ; (A B C) == (cons A (cons B C))
1887 (defun list*/ (&rest list-list-terminated
)
1888 "Basically CL's list* - \"conses\" all elements but last onto list in last parameter, returning a lazy-list."
1889 (lazy-list-from-call
1890 (standard-traversal-link
1891 (build (end-call remainder
)
1892 (destructuring-bind (car-remainder &rest cdr-remainder
) ; so as to only capture required pieces.
1895 (traversal-result car-remainder
(build end-call cdr-remainder
))
1896 (unresolved (get-traversal-result-new-end-call (get-call-for-first (to-lazy-list car-remainder
)) end-call
)))))
1897 (list-list-terminated))))
1902 (defun assoc/ (item alist
&rest rest
)
1903 "CL's assoc; but works with lazy-lists of cons pairs"
1905 (list (apply #'assoc item alist rest
))
1907 (destructuring-bind (&key
(test #'eql
) (key #'identity
))
1909 (let ((current (read-point-built alist
)))
1912 (when (not (read-point-at-end current
))
1913 (when (not (funcall test item
(funcall key
(first (read-point-value current
)))))
1914 (setq current
(read-point-advanced current
))
1916 (when (not (read-point-at-end current
))
1917 (read-point-value current
)))))))
1920 (defun prepend/ (&rest list-list-terminated
)
1921 "CL's list*, returning a lazy-list"
1922 (apply #'list
*/ list-list-terminated
))
1926 (defun filter/ (predicate list
)
1927 (lazy-list-from-call
1928 (standard-traversal-link
1929 (filter-call (end-call current-call
)
1930 (with-traversal-result
1932 (get-traversal-result current-call
)
1933 (let ((next (resolved next
))
1939 (let ((val (resolved value
)))
1940 (if (funcall predicate val
)
1941 (return (traversal-result val
(filter-call end-call next
)))
1942 (with-traversal-result
1944 (get-traversal-result next
)
1948 (return (get-traversal-result end-call
))))))))
1949 ((get-call-for-first (to-lazy-list list
))))))
1957 ; Needs optimization, to put
1958 (defun nub-by/ (equality list
)
1959 (let ((hash (make-hash-table :test equality
))
1960 (readpoint-seeking-end nil
))
1964 (lazy-list-from-call
1965 (standard-traversal-link
1966 (read-point-to-call (end-call start
)
1967 (let ((current start
)
1971 (when (not (read-point-at-end current
))
1972 (setq value
(read-point-value current
))
1973 (multiple-value-bind (current-val current-val-valid
)
1974 (gethash value hash
)
1975 (if current-val-valid
1977 (setq current
(read-point-advanced current
))
1979 (setf (gethash value hash
) t
)))))
1980 (if (read-point-at-end current
)
1981 (unresolved (get-traversal-result end-call
))
1984 (read-point-to-call end-call
(read-point-advanced current
))))))
1985 ((read-point-built (to-lazy-list list
))))))))
1986 (setq readpoint-seeking-end
(read-point-built return-list
))
1989 (when readpoint-seeking-end
1990 (loop while
(not (read-point-at-end readpoint-seeking-end
)) do
(setq readpoint-seeking-end
(read-point-advanced readpoint-seeking-end
))))
1991 (multiple-value-bind (dummy exists
) (gethash key hash
) exists
)))))
1993 (defun nub/ (list) (nub-by/ #'eql list
))
1996 "Returns last element or nil"
1999 (loop-over/ elt
(to-lazy-list list
)
2002 (return-from :exit nil
)))
2006 ; "Returns first non-nil element or nil"
2008 (loop-over/ elt
(to-lazy-list list
)
2010 (return-from :exit elt
)))
2013 (defun latch-on/ (func list
&key
(initial-value nil
))
2014 (labels ((build (read-point latched latched-val
)
2016 (if (read-point-at-end read-point
)
2019 (values latched-val
(build (read-point-advanced read-point
) t latched-val
))
2020 (let ((val (read-point-value read-point
)))
2021 (if (funcall func val
)
2022 (values val
(build (read-point-advanced read-point
) t val
))
2025 (build (read-point-advanced read-point
) nil nil
)))))))))
2026 (lazy-list-from-call (build (read-point-built (to-lazy-list list
)) nil nil
))))
2028 (defun foldl/ (function first list
)
2029 (assert (functionp function
))
2031 (sequence (reduce function list
:from-end nil
:initial-value first
))
2032 (lazy-list-list-based
2033 (reduce function
(get-list-head list
) :from-end nil
:initial-value first
))
2036 (current (get-call-for-first list
)))
2039 (with-traversal-result (val next
)
2040 (get-traversal-result current
)
2041 (let ((next (resolved next
)))
2043 (setf accum
(funcall function accum
(resolved val
)))
2051 (defun foldl1/ (function list
)
2053 (sequence (reduce function list
:from-end nil
))
2054 (lazy-list-list-based (reduce function
(get-list-head list
) :from-end nil
))
2056 (with-traversal-result (value next
)
2057 (get-traversal-result (get-call-for-first (to-lazy-list list
)))
2058 (let ((current (resolved next
))
2059 (accum (resolved value
)))
2060 (loop while current do
2061 (with-traversal-result (value next
)
2062 (get-traversal-result current
)
2063 (let ((next (resolved next
)))
2066 (setq accum
(funcall function accum
(resolved value
)))))))
2071 (defun foldr/ (function first list
)
2072 (assert (functionp function
))
2074 (sequence (reduce function list
:from-end t
:initial-value first
))
2075 (lazy-list-list-based
2076 (reduce function
(get-list-head list
) :from-end t
:initial-value first
))
2078 (reduce function
(to-list list
) :from-end t
:initial-value first
))))
2080 (defun foldr1/ (function list
)
2081 (assert (functionp function
))
2083 (sequence (reduce function list
:from-end t
))
2084 (lazy-list-list-based
2085 (reduce function
(get-list-head list
) :from-end t
))
2087 (reduce function
(to-list list
) :from-end t
))))
2090 (defun scanl/ (function first list
)
2091 (lazy-list-from-call
2092 (standard-traversal-link
2093 (build (end-call first call
)
2094 (with-traversal-result
2096 (get-traversal-result call
)
2097 (let ((next (resolved next
)))
2099 (traversal-result first
(build end-call
(funcall function first
(resolved val
)) next
))
2100 (traversal-result first end-call
)))))
2101 (first (get-call-for-first (to-lazy-list list
))))))
2104 (defun scanl1/ (function list
)
2105 (lazy-list-from-call
2106 (standard-traversal-link
2107 (build (end-call first first-valid call
)
2108 (with-traversal-result
2110 (get-traversal-result call
)
2111 (let ((next (resolved next
)))
2114 (traversal-result first
(build end-call
(funcall function first
(resolved val
)) t next
))
2115 (unresolved (get-traversal-result (build end-call
(resolved val
) t next
))))
2116 (traversal-result first end-call
)))))
2117 (nil nil
(get-call-for-first (to-lazy-list list
))))))
2120 (defun scanr/ (function first list
)
2121 (labels ((build-result-list-call ()
2122 (let ((result (list first
)))
2123 (loop for elt in
(reverse (to-list list
)) do
2124 (push (funcall function elt
(car result
)) result
))
2125 (list-to-lazy-list-call result
))))
2127 (lazy-list-from-call
2128 (deferred-traversal-link-from-call-maker (build-result-list-call)))
2129 (lazy-list-from-call (build-result-list-call)))))
2133 (defun scanr1/ (function list
)
2134 (labels ((build-result-list-call ()
2135 (let* ((reversed (reverse (to-list list
)))
2136 (result (list (first reversed
))))
2139 (loop for elt in
(cdr reversed
) do
2140 (push (funcall function elt
(car result
)) result
))
2141 (list-to-lazy-list-call result
))
2142 (list-to-lazy-list-call nil
)))))
2144 (lazy-list-from-call
2145 (deferred-traversal-link-from-call-maker (build-result-list-call)))
2146 (lazy-list-from-call (build-result-list-call)))))
2150 (defun grouped-by-firsts/ (test list-of-pair-conses
)
2151 (labels ((build-list ()
2152 (let ((hash (make-hash-table :test test
)))
2155 (to-lazy-list list-of-pair-conses
)
2156 (destructuring-bind (key . value
) (to-list elt
)
2157 (setf (gethash key hash
) (cons value
(gethash key hash
)))))
2160 (map/ (lambda (key) (cons key
(gethash key hash
)))
2161 (loop for key being the hash-keys of hash collect
(progn (setf (gethash key hash
) (nreverse (gethash key hash
))) key
))))
2163 (gethash key hash
))))))
2165 (let ((build-call-values-list nil
))
2166 (labels ((verify-data-ready ()
2167 (cond (build-call-values-list)
2168 (t (setq build-call-values-list
(multiple-value-list (build-list)))))))
2170 (lazy-list-from-call
2171 (fixed-traversal-link-from-result-form (get-traversal-result (first (verify-data-ready)))))
2172 (second (verify-data-ready)))))
2173 (multiple-value-bind (list query
)
2176 (lazy-list-from-call list
)
2181 (defun grouped-cdrs-by-car/ (list-of-cons-pairs &key
(test 'eql
))
2182 "Takes a list of cons pairs, of the form (first . second) - returns a list of conses of the form (first . (second 0 second1 second2 second3....)) as the first value, where the seconds are matches on first.
2183 Second return value is a function, that returns a list of seconds based on a search key/first as first value, found (T or NIL) as second.
2184 When run in an eager context, grouped-by-first-in-cons-pairs/ calculates the internal hash immediately.
2185 When run in a lazy context, the creation of the internal hash is deferred - and is on the first request of either the resultant list, or execution of the second return value."
2186 (grouped-by-firsts/ test list-of-cons-pairs
))
2188 (defun grouped-seconds-by-first/ (list-of-list-pairs &key
(test 'eql
))
2189 "Equivalent to grouped-cdrs-by-car/ , except that the input pairs come as a list of lists, instead of a list of conses."
2190 (grouped-by-firsts/ test
(map/ (curried #'apply
#'cons
) list-of-list-pairs
)))
2195 (defun sort-by/ (ordering list
)
2196 (labels ((get-as-distinct-sortable ()
2198 (list (copy-seq list
))
2199 (sequence (map 'list
#'identity list
))
2200 (lazy-list-list-based (copy-seq (to-list list
)))
2201 (t (to-list list
))))) ; based on assumption that only sequences and lazy-list-list-based will to-list to a sequence
2203 (assert (functionp ordering
))
2205 (lazy-list-from-call
2206 (fixed-traversal-link-from-result-form
2207 (let ((sorted (get-as-distinct-sortable)))
2208 (setq sorted
(sort sorted ordering
))
2209 (get-traversal-result
2210 (get-call-for-first (to-lazy-list sorted
))))))
2211 (let ((sorted (get-as-distinct-sortable)))
2212 (setq sorted
(sort sorted ordering
))
2213 (to-lazy-list sorted
)))))
2216 (sort-by/ #'< list
))
2223 (defmacro self-ref-list
/ (ref-name &body definition
)
2224 (let ((self-sym (gensym))
2225 (end-call-sym (gensym)))
2226 `(lazy-list-from-call
2227 (fixed-traversal-link-from-result-form
2228 (get-traversal-result
2230 (let ((,self-sym
:error
))
2231 (symbol-macrolet ((,ref-name
(lazy-list-from-call (fixed-traversal-link-from-result-form (get-traversal-result ,self-sym
)))))
2232 (let* ((ref (memoized/ (lazy ,@definition
)))
2233 (call (get-call-for-first ref
)))
2234 (setq ,self-sym call
)
2239 (defmacro let
/ (definitions &body body
)
2244 (destructuring-bind (var-name value-clause
)
2245 (if (consp entry
) entry
(list entry nil
))
2247 (self-ref-list/ ,var-name
,value-clause
)))
2254 (defstruct hash-table-description
2255 (hash-function :error
:type function
:read-only t
)
2256 (test :error
:type function
:read-only t
))
2258 (defstruct (const-hash-table
2259 (:constructor new-const-hash-table
(hash-table-description root-node
)))
2260 (hash-table-description :error
:read-only t
)
2261 (root-node :error
:read-only t
))
2262 ; (defconstant old-make-const-hash-table #'make-const-hash-table)
2266 (defmethod print-object ((const-hash-table const-hash-table
) stream
)
2267 (format stream
"Const Hashtable"))
2270 (defstruct equal-hash-key-value-pairs
2271 (count :error
:type fixnum
:read-only t
)
2272 (key-value-pairs :error
:type cons
:read-only t
)) ; this is a list, BIGGER than one; but ending not on nil but on the hash value.
2273 ; hash value is only needed when strikign the end. Hash value is a fixnum.
2275 (defstruct hash-leaf-node
2276 (hash :error
:type fixnum
:read-only t
)
2277 (key-value :error
:type cons
:read-only t
))
2279 (defstruct (hash-bucket-node
2280 (:constructor new-hash-bucket-node
(count contents-mask lookup
)))
2281 (count :error
:type fixnum
:read-only t
)
2282 (contents-mask :error
:type fixnum
:read-only t
)
2283 (lookup :error
:type simple-array
:read-only t
))
2286 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
2287 (defparameter **bucket-node-bucket-size
** 16)
2288 (defparameter **per-level-shift
** 4)
2291 (defmacro shift-at-end
(shift)
2295 (defun make-const-hash-table (&key
(hash-function #'sxhash
) (test #'eql
) (key-value-pairs nil
))
2296 (let ((result (new-const-hash-table (make-hash-table-description :test test
:hash-function hash-function
) nil
)))
2298 (const-hash-table-with-changes result nil key-value-pairs
)
2302 (defun const-hash-table-count (const-hash-table)
2303 (let ((root-node (const-hash-table-root-node const-hash-table
)))
2304 (etypecase root-node
2305 (hash-bucket-node (hash-bucket-node-count root-node
))
2308 (equal-hash-key-value-pairs (equal-hash-key-value-pairs-count root-node
))
2312 ; second value is nil if not found
2313 (defun const-hash-table-lookup (const-hash-table key
)
2314 (with-accessors ((hash-table-description const-hash-table-hash-table-description
))
2316 (with-accessors ((hash-function hash-table-description-hash-function
)
2317 (test hash-table-description-test
))
2318 hash-table-description
2319 (let* ((hash (funcall hash-function key
))
2321 (node (const-hash-table-root-node const-hash-table
)))
2322 (declare (type fixnum hash rolling-hash
))
2327 (let ((bucket-to-find (logand rolling-hash
#.
(1- **bucket-node-bucket-size
**)))
2328 (contents-mask (hash-bucket-node-contents-mask node
)))
2329 (declare (type fixnum bucket-to-find contents-mask
))
2330 (if (plusp (logand contents-mask
(ash 1 bucket-to-find
))) ; see if there's an entry at the bucket we want.
2331 (let ((current-bucket-index 0)) ; loop through others to get the index in lookup
2332 (declare (type fixnum current-bucket-index
))
2333 (loop for bucket from
0 to
(1- bucket-to-find
) do
2334 (when (plusp (logand contents-mask
(ash 1 bucket
)))
2335 (incf current-bucket-index
)))
2336 (setq node
(aref (hash-bucket-node-lookup node
) current-bucket-index
))
2337 (setq rolling-hash
(ash rolling-hash
#.
(- **per-level-shift
**))))
2338 (return-from :exit
(values nil nil
)))))
2341 (if (funcall test key
(car (hash-leaf-node-key-value node
)))
2342 (values (cdr (hash-leaf-node-key-value node
)) t
)
2346 (if (funcall test key
(car node
))
2347 (values (cdr node
) t
)
2349 (equal-hash-key-value-pairs
2350 (loop for key-value-remainder on
(equal-hash-key-value-pairs-key-value-pairs node
) do
2351 (declare (type cons key-value-remainder
))
2352 (let ((key-value (car key-value-remainder
)))
2353 (declare (type cons key-value
))
2354 (when (funcall test key
(car key-value
))
2355 (return-from :exit
(values (cdr key-value
) t
)))))
2356 (return-from :exit
(values nil nil
)))
2357 (null (return-from :exit
(values nil nil
))))))))))
2360 (defun const-hash-table-with-changes (const-hash-table keys-to-remove key-value-pairs-to-add
)
2361 (with-accessors ((hash-table-description const-hash-table-hash-table-description
)
2362 (root-node const-hash-table-root-node
))
2364 (let ((test (hash-table-description-test hash-table-description
))
2365 (hash-function (hash-table-description-hash-function hash-table-description
)))
2366 (labels ((get-node-element-count (node)
2368 (hash-bucket-node (hash-bucket-node-count node
))
2371 (equal-hash-key-value-pairs (equal-hash-key-value-pairs-count node
))))
2372 (from-hash-leaf-nodes (hash-leaf-nodes-to-add shift
)
2373 (declare (type fixnum shift
))
2375 ((null hash-leaf-nodes-to-add
) nil
)
2376 ((cdr hash-leaf-nodes-to-add
) ; more than one to add - if at shift-end, they're all equal-hash else make lookup.
2377 (if (shift-at-end shift
)
2379 (key-value-pairs-r (hash-leaf-node-hash (cdar hash-leaf-nodes-to-add
))) ; list will dot-end with hash value instead of nil
2380 ; (known-hash (hash-leaf-node-hash (cdar hash-leaf-nodes-to-add)))
2382 (declare (type fixnum count known-hash
))
2383 (loop while hash-leaf-nodes-to-add do
2384 (let* ((current hash-leaf-nodes-to-add
) ; we'll be recycling the cons "current"
2385 (new-key-value (hash-leaf-node-key-value (cdar current
)))
2386 (new-key (car new-key-value
)))
2387 (setf hash-leaf-nodes-to-add
(cdr current
))
2388 (unless ; loop returns true if replacement made
2389 (loop for key-value-pairs-r-remainder on key-value-pairs-r do
2390 (when (funcall test
(caar key-value-pairs-r-remainder
) new-key
)
2391 (setf (car key-value-pairs-r-remainder
) new-key-value
)
2393 (incf count
) ; only count additions, not the replacement inside the loop.
2394 (setf (car current
) new-key-value
) ; recycle cons "current"
2395 (setf (cdr current
) key-value-pairs-r
)
2396 (setf key-value-pairs-r current
))))
2398 (1 (car key-value-pairs-r
)) ; safe assumption - if we only have one, all ins must have been identical and we kept the last.
2399 (t (make-equal-hash-key-value-pairs :count count
:key-value-pairs key-value-pairs-r
)))) ; reversal doesn't matter here - list is new and unique
2400 (let ((contents-mask 0))
2401 (declare (type fixnum num-additions
))
2402 ; Modify all the cars in the hash-leaf-nodes-to-add list to contain the bucket-hash
2403 (loop for hash-leaf-node-to-add in hash-leaf-nodes-to-add do
2404 (let ((bucket (logand (ash (hash-leaf-node-hash (cdr hash-leaf-node-to-add
)) shift
) #.
(1- **bucket-node-bucket-size
**))))
2405 (declare (type fixnum bucket
))
2406 (setf contents-mask
(logior contents-mask
(ash 1 bucket
)))
2407 (setf (car hash-leaf-node-to-add
)
2409 (let* ((current-ordered (stable-sort hash-leaf-nodes-to-add
(lambda (a b
) (< (the fixnum
(car a
)) (the fixnum
(car b
))))))
2410 (lookup (make-array (the fixnum
(logcount contents-mask
)))) ; safe to assume as no additions to nil will return 0 count/nil
2412 (sub-shift (- shift
#.
**per-level-shift
**))
2413 (basis-if-single nil
)
2414 (current-insertion-index 0))
2415 (declare (type fixnum num-buckets-represented count current-insertion-index sub-shift
))
2416 (loop while current-ordered do
2417 (let* ((bucket-number (caar current-ordered
))
2418 (additions-for-bucket-r current-ordered
))
2419 (setf current-ordered
(cdr current-ordered
))
2420 (setf (cdr additions-for-bucket-r
) nil
)
2421 (loop while
(and current-ordered
(eql (caar current-ordered
) bucket-number
)) do
2422 (let ((temp current-ordered
))
2423 (setf current-ordered
(cdr current-ordered
))
2424 (setf (cdr temp
) additions-for-bucket-r
)
2425 (setf additions-for-bucket-r temp
)))
2426 (setq basis-if-single
(cdar additions-for-bucket-r
))
2427 (let ((result (from-hash-leaf-nodes (nreverse additions-for-bucket-r
) sub-shift
)))
2428 (incf count
(get-node-element-count result
))
2429 (setf (aref lookup current-insertion-index
) result
)
2430 (incf current-insertion-index
))))
2431 (if (and (= count
1) basis-if-single
)
2434 (new-hash-bucket-node count contents-mask lookup
))))))
2435 ((shift-at-end shift
) (hash-leaf-node-key-value (cdar hash-leaf-nodes-to-add
)))
2436 (t (cdar hash-leaf-nodes-to-add
))))
2437 (with-removals-and-additions (node hash-key-pairs-to-remove hash-leaf-nodes-to-add shift
)
2438 (declare (type fixnum shift
)
2439 (type list hash-key-pairs-to-remove hash-leaf-nodes-to-add
))
2441 (null (from-hash-leaf-nodes hash-leaf-nodes-to-add shift
))
2443 (if (block :full-removal-test
2444 (loop for hash-key-pair-to-remove in hash-key-pairs-to-remove do
2445 (let ((actual-pair-to-remove (cdr hash-key-pair-to-remove
)))
2447 (eql (car actual-pair-to-remove
) (hash-leaf-node-hash node
)) ; hashes equal
2448 (funcall test
(cdr actual-pair-to-remove
) (car (hash-leaf-node-key-value node
))))
2449 (return-from :full-removal-test t
))))
2450 (loop for hash-leaf-node-to-add in hash-leaf-nodes-to-add do
2451 (let ((actual-hash-leaf-node (cdr hash-leaf-node-to-add
)))
2453 (eql (hash-leaf-node-hash actual-hash-leaf-node
) (hash-leaf-node-hash node
))
2454 (funcall test
(car (hash-leaf-node-key-value node
)) (car (hash-leaf-node-key-value actual-hash-leaf-node
))))
2455 (return-from :full-removal-test t
))))) ; test to see if "node" should be removed.
2456 (from-hash-leaf-nodes hash-leaf-nodes-to-add shift
) ; forget about this, and build off a new nil with the adds only.
2457 (from-hash-leaf-nodes (cons (cons nil node
) hash-leaf-nodes-to-add
) shift
))) ; order not important - no match
2458 (equal-hash-key-value-pairs
2459 ; note - by the time we get here, all hashes should match already. Only thing to do is deletions and additions based on equality tests.
2460 ; first thing to do is find the unaffected sublist, i.e. the one that will not be modded by removal or addition (overwrite).
2461 (let ((intact-retained-sublist (equal-hash-key-value-pairs-key-value-pairs node
))
2462 (intact-retained-sublist-start-index 0)
2463 (indices-to-remove-r nil
)
2464 (num-indices-to-remove 0)
2465 (spare-cons-bank nil
))
2466 (declare (type fixnum num-indices-to-remove intact-retained-sublist-start-index
))
2467 (macrolet ((cons-from-spares (car cdr
)
2468 (let ((sym (gensym)))
2469 `(let ((,sym spare-cons-bank
))
2470 (setq spare-cons-bank
(cdr spare-cons-bank
))
2471 (setf (car ,sym
) ,car
)
2472 (setf (cdr ,sym
) ,cdr
)
2474 (cons-from-spares-if-available (car cdr
)
2475 `(if spare-cons-bank
2476 (cons-from-spares ,car
,cdr
)
2478 (recycle-cons (cons)
2479 (let ((sym (gensym)))
2480 `(let ((,sym
,cons
))
2481 (setf (cdr ,sym
) spare-cons-bank
)
2482 (setq spare-cons-bank
,sym
))))
2483 (advance-cons-recycling-prior (var)
2484 (assert (symbolp var
))
2485 (let ((next (gensym)))
2486 (assert (symbolp var
))
2487 `(let ((,next
(cdr ,var
)))
2489 (setq ,var
,next
))))
2490 (strip-data-slots-for-cons-spares (list)
2491 (let ((current-sym (gensym))
2492 (temp-sym (gensym)))
2493 `(let ((,current-sym
,list
))
2494 (loop while
,current-sym do
2495 (let ((,temp-sym
(car ,current-sym
)))
2496 (setf (car ,current-sym
) (cdar ,current-sym
))
2497 (setf (cdr ,temp-sym
) spare-cons-bank
)
2498 (setf spare-cons-bank
,temp-sym
)
2499 (setf ,current-sym
(cdr ,current-sym
))))))))
2500 ; note - data slots are being stripped out of the input vars
2501 (strip-data-slots-for-cons-spares hash-key-pairs-to-remove
)
2502 (strip-data-slots-for-cons-spares hash-leaf-nodes-to-add
)
2503 ; destroy the hash-leaf-nodes-to-add by pulling out the key-value-pairs to list instead
2504 (let ((key-value-pairs-to-add hash-leaf-nodes-to-add
))
2505 (loop for elt on hash-leaf-nodes-to-add do
(setf (car elt
) (hash-leaf-node-key-value (car elt
))))
2506 ; Following code works on the following assumption: Everything CURRENTLY in the list
2507 ; is unique. So there should be enough conses in "spare-cons-bank", as
2508 ; there can't be more values destroyed or overwritten than there were overwriters.
2509 (loop for key-value-remainder on
(equal-hash-key-value-pairs-key-value-pairs node
)
2510 for current-index from
0 do
2511 (let* ((key-value (the cons
(car key-value-remainder
)))
2512 (key (car key-value
)))
2514 ((loop for hash-key-pair-to-remove in hash-key-pairs-to-remove do
2515 (when (funcall test
(cdr hash-key-pair-to-remove
) key
)
2518 (loop for key-value-pair-to-add in key-value-pairs-to-add do
2519 (when (funcall test
(car key-value-pair-to-add
) key
)
2521 (setq intact-retained-sublist
(cdr key-value-remainder
))
2522 (setq intact-retained-sublist-start-index
(1+ current-index
))
2523 (incf num-indices-to-remove
)
2524 (setf indices-to-remove-r
(cons-from-spares current-index indices-to-remove-r
)))))
2525 ; hash-key-pairs-to-remove no longer required. Recycle the conses.
2526 (let ((current hash-key-pairs-to-remove
))
2527 (loop while current do
2528 (let ((next (cdr current
)))
2529 (setf (cdar current
) spare-cons-bank
)
2530 (setf spare-cons-bank
(car current
))
2531 (setf (cdr current
) spare-cons-bank
)
2532 (setf spare-cons-bank current
)
2533 (setq current next
))))
2534 ; note - cannot damage any of node's key-valuepairs or their conses.
2535 (let ((copied-out-sublist-r intact-retained-sublist
)
2536 (vulnerable-range-of-cos 0)
2538 (current-index-to-remove (nreverse indices-to-remove-r
)))
2539 (declare (type fixnum vulnerable-range-of-cos
))
2540 (loop for key-value-pair-remainder on
(equal-hash-key-value-pairs-key-value-pairs node
)
2541 for current-index from
0 to
(1- intact-retained-sublist-start-index
) do
2542 (let ((key-value-pair (the cons
(car (the cons key-value-pair-remainder
)))))
2543 (if (eql current-index
(car current-index-to-remove
))
2545 (incf count-delta -
1)
2546 (advance-cons-recycling-prior current-index-to-remove
))
2548 (incf vulnerable-range-of-cos
)
2549 (setq copied-out-sublist-r
(cons-from-spares-if-available key-value-pair copied-out-sublist-r
))))))
2550 (let ((remaining-key-value-pairs-to-add key-value-pairs-to-add
))
2551 (loop while remaining-key-value-pairs-to-add do
2552 (let ((key-value-pair-to-add (car remaining-key-value-pairs-to-add
)))
2553 (cond ((loop for copied-out-sub-head on copied-out-sublist-r
2554 for dummy from
1 to vulnerable-range-of-cos
2556 (when (funcall test
(caar copied-out-sub-head
) (car key-value-pair-to-add
))
2557 (setf (car copied-out-sub-head
) key-value-pair-to-add
)
2558 (advance-cons-recycling-prior remaining-key-value-pairs-to-add
)
2559 (incf count-delta
) ; added a new. Will be a wash if a replacement caused by a prior removal building copied-out-sublist-r originally.
2562 (let ((next (cdr remaining-key-value-pairs-to-add
)))
2563 (setf (cdr remaining-key-value-pairs-to-add
) copied-out-sublist-r
)
2564 (setf copied-out-sublist-r remaining-key-value-pairs-to-add
)
2565 (setf remaining-key-value-pairs-to-add next
)
2566 (incf vulnerable-range-of-cos
)))))))
2567 (let ((count (+ count-delta
(equal-hash-key-value-pairs-count node
))))
2568 (declare (type fixnum count
))
2571 (1 (make-hash-leaf-node :hash
(cdr copied-out-sublist-r
) :key-value
(first copied-out-sublist-r
)))
2572 (t (make-equal-hash-key-value-pairs
2573 :count
(+ count-delta
(equal-hash-key-value-pairs-count node
))
2574 :key-value-pairs copied-out-sublist-r
)))))))))
2576 (macrolet ((hash-to-mask (hash)
2577 `(ash 1 (logand (ash ,hash shift
) #.
(1- **bucket-node-bucket-size
**)))))
2578 (let ((original-contents-mask (hash-bucket-node-contents-mask node
))
2579 (all-removals-mask 0)
2580 (additions-to-existing-buckets-mask 0)
2581 (additions-to-new-buckets-mask 0))
2582 (declare (type fixnum original-contents-mask additions-to-existing-buckets-mask additions-to-new-buckets-mask
))
2583 ; first, go through hash-key-pairs-to-remove and update the car to masks.
2584 ; any whose masks don't "and" with original-contents-mask can be outright discarded.
2585 (let ((hash-key-pairs-to-remove-r nil
))
2586 (let ((current hash-key-pairs-to-remove
))
2587 (loop while current do
2588 (let ((next (cdr current
))
2589 (mask (hash-to-mask (cadar current
))))
2590 (declare (type fixnum mask
))
2591 (unless (zerop (logand mask original-contents-mask
)) ; make sure it's removing something that may be there.
2592 (setf all-removals-mask
(logior mask all-removals-mask
))
2593 (setf (caar current
) mask
)
2594 (setf (cdr current
) hash-key-pairs-to-remove-r
)
2595 (setf hash-key-pairs-to-remove-r current
))
2596 (setq current next
))))
2597 (setq hash-key-pairs-to-remove-r
(sort hash-key-pairs-to-remove-r
(lambda (a b
) (< (the fixnum
(car a
)) (the fixnum
(car b
))))))
2598 ; hash-key-pairs-to-remove-r is what should be used, hash-key-pairs-to-remove is now destroyed.
2599 ; Now, go through additions and give them masks too. Sort into 2 lists - new-bucket and clashing.
2600 (let ((additions-existing-bucket-r nil
)
2601 (additions-new-bucket-r nil
))
2602 (let ((current hash-leaf-nodes-to-add
))
2603 (loop while current do
2604 (let ((next (cdr current
))
2605 (mask (hash-to-mask (hash-leaf-node-hash (cdar current
)))))
2606 (declare (type fixnum mask
))
2607 (setf (caar current
) mask
)
2608 (if (zerop (logand mask original-contents-mask
))
2610 (setf additions-to-new-buckets-mask
(logior mask additions-to-new-buckets-mask
))
2611 (setf (cdr current
) additions-new-bucket-r
)
2612 (setf additions-new-bucket-r current
))
2614 (setf additions-to-existing-buckets-mask
(logior mask additions-to-existing-buckets-mask
))
2615 (setf (cdr current
) additions-existing-bucket-r
)
2616 (setf additions-existing-bucket-r current
)))
2617 (setq current next
))))
2618 (let ((additions-existing-bucket (stable-sort (nreverse additions-existing-bucket-r
) (lambda (a b
) (< (the fixnum
(car a
)) (the fixnum
(car b
))))))
2619 (additions-new-bucket (stable-sort (nreverse additions-new-bucket-r
) (lambda (a b
) (< (the fixnum
(car a
)) (the fixnum
(car b
)))))))
2620 ; additions-existing-bucket and additions-new-bucket set up, hash-leaf-nodes-to-add should be considered destroyed.
2621 ; I'll go to hell for this unhygienic macro action :(
2622 (macrolet ((get-changed-bucket (&body body
)
2623 `(let ((old-lookup (hash-bucket-node-lookup node
))
2624 (current-read-index 0)
2625 (current-read-mask 1)
2626 (sub-shift (- shift
#.
**per-level-shift
**))
2627 (positive-contents-mask (logior additions-to-existing-buckets-mask additions-to-new-buckets-mask original-contents-mask
))
2628 (changes-to-existing-mask (logior additions-to-existing-buckets-mask all-removals-mask
)))
2629 (declare (type fixnum current-read-index current-read-mask positive-contents-mask changes-to-existing-mask sub-shift
))
2630 (loop while
(<= current-read-mask positive-contents-mask
) do
2631 (cond ((plusp (logand changes-to-existing-mask current-read-mask
))
2632 (let ((additions-r nil
)
2634 (loop while
(and additions-existing-bucket
(eql (caar additions-existing-bucket
) current-read-mask
)) do
2635 (let ((next (cdr additions-existing-bucket
)))
2636 (setf (cdr additions-existing-bucket
) additions-r
)
2637 (setq additions-r additions-existing-bucket
)
2638 (setq additions-existing-bucket next
)))
2639 (loop while
(and hash-key-pairs-to-remove-r
(eql (caar hash-key-pairs-to-remove-r
) current-read-mask
)) do
2640 (let ((next (cdr hash-key-pairs-to-remove-r
)))
2641 (setf (cdr hash-key-pairs-to-remove-r
) removals-r
)
2642 (setq removals-r hash-key-pairs-to-remove-r
)
2643 (setq hash-key-pairs-to-remove-r next
)))
2644 (let ((node-if-single (when (not removals-r
) (if additions-r
(cdar additions-r
) (aref old-lookup current-read-index
))))
2645 (result (with-removals-and-additions (aref old-lookup current-read-index
) removals-r
(nreverse additions-r
) sub-shift
)))
2646 (incf current-read-index
)
2647 (sink-result current-read-mask result node-if-single
))))
2648 ((plusp (logand current-read-mask additions-to-new-buckets-mask
))
2649 (let ((additions-r nil
))
2650 (loop while
(and additions-new-bucket
(eql (caar additions-new-bucket
) current-read-mask
)) do
2651 (let ((next (cdr additions-new-bucket
)))
2652 (setf (cdr additions-new-bucket
) additions-r
)
2653 (setq additions-r additions-new-bucket
)
2654 (setq additions-new-bucket next
)))
2655 (let ((node-if-single (when additions-r
(cdar additions-r
)))
2656 (result (from-hash-leaf-nodes (nreverse additions-r
) sub-shift
)))
2657 (sink-result current-read-mask result node-if-single
))))
2658 ((plusp (logand current-read-mask original-contents-mask
))
2659 (sink-result current-read-mask
(aref old-lookup current-read-index
))
2660 (incf current-read-index
))) ; no change to count.
2661 (setf current-read-mask
(ash current-read-mask
1)))
2663 (if (zerop (logand all-removals-mask
(lognot additions-to-existing-buckets-mask
))) ; no removals without subsequent additions - deterministic array size.
2664 (let ((lookup-array-length (logcount (logior original-contents-mask additions-to-new-buckets-mask
))))
2665 (declare (type fixnum lookup-array-length
))
2666 (let ((lookup (make-array lookup-array-length
))
2667 (current-insertion-index 0)
2668 ; (outer-node-if-single nil)
2670 (declare (type fixnum current-insertion-index count
))
2671 (macrolet ((sink-result (insertion-mask result
&optional
(node-if-single nil
))
2673 ; (when ,node-if-single (setq outer-node-if-single ,node-if-single))
2674 (incf count
(get-node-element-count (setf (aref lookup current-insertion-index
) ,result
)))
2675 (incf current-insertion-index
))))
2677 (if (and (= count
1) (typep (aref lookup
0) 'hash-leaf-node
))
2678 (aref lookup
0) ; only one under this bucket, and it's a hash-leaf-node - just return it.
2679 (new-hash-bucket-node count positive-contents-mask lookup
))))))
2680 (let ((lookup-elements-r nil
)
2681 (lookup-element-count 0)
2682 (final-contents-mask 0)
2683 ; (outer-node-if-single nil)
2685 (declare (type fixnum count lookup-element-count final-contents-mask
))
2686 (macrolet ((sink-result (insertion-mask result
&optional
(node-if-single nil
))
2688 (let ((result ,result
))
2689 (when result
; nil = don't add to the array
2690 ; (when ,node-if-single (setq outer-node-if-single ,node-if-single))
2691 (incf count
(get-node-element-count result
))
2692 (incf lookup-element-count
)
2693 (incf final-contents-mask
,insertion-mask
)
2694 (push result lookup-elements-r
))))))
2696 (if lookup-elements-r
; return nil when empty - element above will accept it
2697 (if (and (= count
1) (typep (first lookup-elements-r
) 'hash-leaf-node
))
2698 (first lookup-elements-r
)
2699 (new-hash-bucket-node count final-contents-mask
(make-array lookup-element-count
:initial-contents
(nreverse lookup-elements-r
))))
2701 (assert (zerop count
))
2703 (new-const-hash-table
2704 hash-table-description
2705 (with-removals-and-additions
2707 (let ((keys-to-remove-r nil
))
2708 (loop-over/ key-to-remove
(to-lazy-list keys-to-remove
)
2709 (push (list* nil
(funcall hash-function key-to-remove
) key-to-remove
) keys-to-remove-r
))
2710 (nreverse keys-to-remove-r
))
2711 (let ((key-value-pairs-to-add-r nil
))
2712 (loop-over/ key-value-pair-to-add
(to-lazy-list key-value-pairs-to-add
)
2713 (push (list* nil
(make-hash-leaf-node :hash
(funcall hash-function
(car key-value-pair-to-add
)) :key-value key-value-pair-to-add
)) key-value-pairs-to-add-r
))
2714 (nreverse key-value-pairs-to-add-r
))
2718 (defun const-hash-table-with-additions (const-hash-table key-value-pairs-to-add
)
2719 (const-hash-table-with-changes const-hash-table nil key-value-pairs-to-add
))
2720 (define-compiler-macro const-hash-table-with-additions
(const-hash-table key-value-pairs-to-add
)
2721 `(const-hash-table-with-changes ,const-hash-table nil
,key-value-pairs-to-add
))
2722 (defun const-hash-table-with-addition (const-hash-table key value
)
2723 (const-hash-table-with-changes const-hash-table nil
(list (cons key value
))))
2724 (define-compiler-macro const-hash-table-with-addition
(const-hash-table key value
)
2725 `(const-hash-table-with-changes ,const-hash-table nil
(list (cons ,key
,value
))))
2728 (defun const-hash-table-with-removals (const-hash-table keys-to-remove
)
2729 (const-hash-table-with-changes const-hash-table keys-to-remove nil
))
2730 (define-compiler-macro const-hash-table-with-removals
(const-hash-table keys-to-remove
)
2731 `(const-hash-table-with-changes ,const-hash-table
,keys-to-remove nil
))
2732 (defun const-hash-table-with-removal (const-hash-table key
)
2733 (const-hash-table-with-changes const-hash-table
(list key
) nil
))
2734 (define-compiler-macro const-hash-table-with-removal
(const-hash-table key
)
2735 `(const-hash-table-with-changes ,const-hash-table
(list ,key
) nil
))
2738 (defun const-hash-table-key-value-pairs (const-hash-table)
2739 (labels ((get-key-value-pairs (node)
2741 (hash-bucket-node (concat/ (map/ #'get-key-value-pairs
(hash-bucket-node-lookup node
))))
2742 (hash-leaf-node (list/ (hash-leaf-node-key-value node
)))
2744 (equal-hash-key-value-pairs
2745 (lazy-list-from-call
2746 (standard-traversal-link
2747 (build (end-call remaining-key-value-pairs
)
2748 (if (consp remaining-key-value-pairs
)
2750 (car remaining-key-value-pairs
)
2751 (build end-call
(cdr remaining-key-value-pairs
)))
2752 (get-traversal-result end-call
)))
2753 ((equal-hash-key-value-pairs-key-value-pairs node
))))))))
2754 (let ((root-node (const-hash-table-root-node const-hash-table
)))
2756 (get-key-value-pairs root-node
)
2759 (defun const-hash-table-keys (const-hash-table)
2760 (map/ #'car
(const-hash-table-key-value-pairs const-hash-table
)))
2761 (define-compiler-macro const-hash-table-keys
(const-hash-table)
2762 `(map/ #'car
(const-hash-table-key-value-pairs ,const-hash-table
)))
2764 (defun const-hash-table-values (const-hash-table)
2765 (map/ #'cdr
(const-hash-table-key-value-pairs const-hash-table
)))
2766 (define-compiler-macro const-hash-table-values
(const-hash-table)
2767 `(map/ #'cdr
(const-hash-table-key-value-pairs ,const-hash-table
)))
2773 (defparameter **unit-tests
**
2777 ("Proper List" (let ((lista (loop for elt from
1 to
10 collect elt
))
2778 (listb (loop for elt from
1 to
10 collect elt
)))
2779 (values (and (equal (to-list (to-lazy-list lista
)) listb
) (equal lista listb
)))))
2781 ("Array" (let ((arraya (make-array 10 :initial-contents
(loop for elt from
1 to
10 collect elt
)))
2782 (arrayb (make-array 10 :initial-contents
(loop for elt from
1 to
10 collect elt
))))
2783 (values (and (equal (to-list (to-lazy-list arraya
)) (map 'list
#'identity arrayb
)) (equalp arraya arrayb
)))))))
2785 ("Standard operations"
2787 (loop for in-type in
`(("list" ,#'identity
)
2788 ("list-based lazy list" ,#'to-lazy-list
)
2789 ("lazy-list eager-value" ,(curried #'map
/ #'identity
))
2790 ("lazy-list lazy-value" ,(curried #'map
/ (lambda (elt) (unresolved elt
))))) collect
2793 `(,(concatenate 'string
(first test
) " " (first in-type
))
2795 (labels ((transformed (list) `(funcall ,(second in-type
) ',list
)))
2796 (let ((equality-check-sets
2797 `(("foldl/" (= (foldl/ #'/ 64 ,(transformed '(4 2 4))) 2))
2798 ("foldl1/" (= (foldl1/ #'/ ,(transformed '(64 4 2 8))) 1))
2799 ("foldr/" (= (foldr/ #'/ 2 ,(transformed '(8 12 24 4))) 8))
2800 ("foldr1/" (= (foldr1/ #'/ ,(transformed '(8 12 24 4))) 4))
2802 ("head-tail/ multiple"
2804 (multiple-value-bind (head tail
) (head-tail/ ,(transformed '(1 2 3 4))) (list head
(to-list tail
)))
2808 (multiple-value-bind (head tail
) (head-tail/ ,(transformed '(1))) (list head
(to-list tail
)))
2811 (equal (nth/ 3 ,(transformed nil
)) nil
))
2813 (equal (nth/ 3 ,(transformed '(10 20 30 40))) 40))
2816 (equal (assoc/ 3 ,(transformed '((2 .
"A") (3 .
"B") (4 .
"C")))) '(3 .
"B")))
2818 ("and/ true" (and/ ,(transformed '(1 2 3 4))))
2819 ("and/ false" (equal (and/ ,(transformed '(1 2 nil
3 4))) nil
))
2821 ; ("scanl/" (equal (to-list (scanl/ #'/ 64 ,(transformed '(4 2 4)))) '(64 16 8 2)))
2822 ; ("scanl1/" (equal (to-list (scanl1/ #'/ ,(transformed '(64 4 2 8)))) '(64 16 8 1)))
2823 ; ("scanr/" (equal (to-list (scanr/ #'/ 2 ,(transformed '(8 12 24 4)))) '(8 1 12 2 2)))
2824 ; ("scanr1/" (equal (to-list (scanr1/ #'/ ,(transformed '(8 12 24 2)))) '(8 1 12 2)))
2825 ; ("nub/" (equal (to-list (nub/ ,(transformed '(9 8 4 4 1 4 9)))) '(9 8 4 1)))
2826 ; ("append/" (equal (to-list (append/ ,(transformed '(1 2 3 4)) ,(transformed '(5 6 7 8)))) '(1 2 3 4 5 6 7 8)))
2827 ; ("concat/" (equal (to-list (concat/ ,(transformed '((1 2 3) (4 5 6))))) '(1 2 3 4 5 6)))
2828 ("car/" (equal (car/ ,(transformed '(5 6 7 8))) 5))
2829 ; ("cdr/" (equal (to-list (cdr/ ,(transformed '(5 6 7 8)))) '(6 7 8)))
2830 ; ,@(loop for i from 0 to 10 collect `(,(format nil "nthcdr/ ~S" i) (equal (to-list (nthcdr/ ,i ,(transformed (loop for i from 1 to 8 collect i)))) (nthcdr i (loop for i from 1 to 8 collect i)))))
2833 `(("map/" (map/ #'+ ,(transformed '(1 2 3)) ,(transformed '(4 5 6 7))) '(5 7 9))
2834 ("scanl/" (scanl/ #'/ 64 ,(transformed '(4 2 4))) '(64 16 8 2))
2835 ("scanl1/" (scanl1/ #'/ ,(transformed '(64 4 2 8))) '(64 16 8 1))
2836 ("scanr/" (scanr/ #'/ 2 ,(transformed '(8 12 24 4))) '(8 1 12 2 2))
2837 ("scanr1/" (scanr1/ #'/ ,(transformed '(8 12 24 2))) '(8 1 12 2))
2838 ("nub/" (nub/ ,(transformed '(9 8 4 4 1 4 9))) '(9 8 4 1))
2839 ("append/" (append/ ,(transformed '(1 2 3 4)) ,(transformed '(5 6 7 8))) '(1 2 3 4 5 6 7 8))
2840 ("concat/" (concat/ ,(transformed '((1 2 3) (4 5 6)))) '(1 2 3 4 5 6))
2841 ("intersperse/ empty-case" (intersperse/ "Intersp" ,(transformed nil
)) nil
)
2842 ("intersperse/ single-case" (intersperse/ "Intersp" ,(transformed '(1))) '(1))
2843 ("intersperse/ multiple-case" (intersperse/ "Intersp" ,(transformed '(1 2 3 4))) '(1 "Intersp" 2 "Intersp" 3 "Intersp" 4))
2844 ("take-while/ empty-case" (take-while/ #'identity
,(transformed nil
)) nil
)
2845 ("take-while/ single-case inc" (take-while/ #'identity
,(transformed '(1))) '(1))
2846 ("take-while/ single-case exc" (take-while/ #'null
,(transformed '(1))) nil
)
2847 ("take-while/ multiple partial" (take-while/ #'identity
,(transformed '(1 2 nil
3 4))) '(1 2))
2848 ("take-while/ multiple end" (take-while/ #'identity
,(transformed '(1 2 3 4 nil
))) '(1 2 3 4))
2849 ("take-while/ multiple start" (take-while/ #'identity
,(transformed '(nil 1 2 3 4))) nil
)
2850 ("take-while/ multiple full" (take-while/ #'identity
,(transformed '(1 2 3 4))) '(1 2 3 4))
2852 ("drop-while/ empty-case" (drop-while/ #'identity
,(transformed nil
)) nil
)
2853 ("drop-while/ single-case inc" (drop-while/ #'identity
,(transformed '(1))) nil
)
2854 ("drop-while/ single-case exc" (drop-while/ #'null
,(transformed '(1))) '(1))
2855 ("drop-while/ multiple partial" (drop-while/ #'identity
,(transformed '(1 2 nil
3 4))) '(nil 3 4))
2856 ("drop-while/ multiple end" (drop-while/ #'identity
,(transformed '(1 2 3 4 nil
))) '(nil))
2857 ("drop-while/ multiple start" (drop-while/ #'identity
,(transformed '(nil 1 2 3 4))) '(nil 1 2 3 4))
2858 ("drop-while/ multiple full" (drop-while/ #'identity
,(transformed '(1 2 3 4))) nil
)
2860 ("list*/ empty" (list*/ ,(transformed nil
)) nil
)
2861 ("list*/ frontloaded only" (list*/ 1 2 3 4 ,(transformed nil
)) '(1 2 3 4))
2862 ("list*/ backloaded only" (list*/ ,(transformed '(1 2 3 4))) '(1 2 3 4))
2863 ("list*/ mixed" (list*/ 1 2 ,(transformed '(3 4))) '(1 2 3 4))
2865 ("tails/" (map/ #'to-list
(tails/ ,(transformed '(1 2 3 4)))) '((1 2 3 4) (2 3 4) (3 4) (4) nil
))
2866 ("tails/ lazy-list path" (to-list (concat/ (filter/ #'non-null
/ (tails/ (map/ #'identity
,(transformed '(1 2 3 4))))))) '(1 2 3 4 2 3 4 3 4 4))
2868 ("filter/" (filter/ #'identity
,(transformed '(1 2 nil
3 4))) '(1 2 3 4))
2870 ("grouped-by-firsts/" (grouped-by-firsts/ #'eql
'((1 .
2) (1 .
3) (2 .
4) (1 .
2))) '((1 2 3 2) (2 4)))
2871 ("sort/" (sort/ ,(transformed '(5 3 2 1 9))) '(1 2 3 5 9))
2872 ("iterate/" (take/ 100 (iterate/ #'1+ 1)) (loop for i from
1 to
100 collect i
))
2873 ("nthcdr/" (nthcdr/ 3 ,(transformed '(1 2 3 4 5 6))) '(4 5 6))
2875 ("cdr/" (cdr/ ,(transformed '(5 6 7 8))) '(6 7 8))
2877 ,@(loop for i from
0 to
10 collect
2878 `(,(format nil
"nthcdr/ ~S" i
) (nthcdr/ ,i
,(transformed (loop for i from
1 to
8 collect i
))) (nthcdr ,i
(loop for i from
1 to
8 collect i
))))
2879 ,@(loop for i from
0 to
10 collect
2880 `(,(format nil
"take/ ~S" i
) (take/ ,i
,(transformed (loop for i from
1 to
8 collect i
))) (subseq (loop for i from
1 to
8 collect i
) 0 (min ,i
8))))
2885 (mapcan (lambda (elt)
2886 (destructuring-bind (name lazy-form result-form
)
2888 `((,name
(equal (to-list ,lazy-form
) ,result-form
))
2889 (,(concatenate 'string name
" concat test")
2891 (to-list (append/ (append/ ,lazy-form
,lazy-form
,lazy-form
) (append/ ,lazy-form
,lazy-form
,lazy-form
)))
2892 (append (append ,result-form
,result-form
,result-form
) (append ,result-form
,result-form
,result-form
)))))))
2895 ("Multifunctionality Sanity tests"
2898 ("Cliched Fibonacci to 100"
2899 (funcall (compile nil
(lambda () (= (nth/ 100 (self-ref-list/ fib
(list*/ 1 1 (map/ #'+ fib
(tail/ fib
))))) 573147844013817084101)))))
2902 ("Fibonacci capped but taken to 1,000,000 - leak test"
2904 (self-ref-list/ fib
(list*/ 1 1 (map/ (curried #'max
10) fib
(tail/ fib
))))))
2906 ("CSV Parsing Test (split-down-on-test and others)"
2909 "1,2, 3 , I contain \" Quoted, commas, \" you see, 99
2911 third_line,stuff here"))
2913 '(("1" "2" " 3 " " I contain \" Quoted, commas, \" you see" " 99") ("g" " \"hijk\"lmn") ("third_line" "stuff here"))
2915 (map/ (composed #'to-list
(curried #'map
/ (composed #'to-string
(curried #'map
/ #'car
))))
2917 (lambda (line) (split-down-on-test/ (curried #'equal
'(#\
, . nil
)) line
))
2918 (curried #'scanl1
/ (lambda (a b
) (cons (car b
) (if (cdr a
) (not (cdr b
)) (cdr b
)))))
2919 (curried #'map
/ (lambda (elt) (cons elt
(eql elt
#\")))))
2920 (split-down-on-test/ (curried #'eql
#\newline
) csv-file
)))))))
2927 ("grouped-by-firsts*"
2928 ,(let ((pairs-as-lists '(("Brown" "Bill") ("Smith" "Ian") ("Stein" "Fred") ("Brown" "Sarah") ("Brown" "Lance"))))
2930 (multiple-value-bind (result-pairs query
)
2931 (grouped-seconds-by-first/ pairs-as-lists
:test
'equal
)
2939 (defstruct diff-hash-table
2944 (defstruct hash-table-delta
2945 base
; diff-hash-table we're based on
2946 removals
; keys removed from base
2947 additions
; keys added or replaced - search this first - alist
2952 (defun diff-hash-table (key-value-pairs &key
(test #'eql
))
2953 (make-diff-hash-table :lock nil
2955 (let ((hash (make-hash-table :test test
)))
2956 (loop-over/ pair
(to-lazy-list key-value-pairs
)
2957 (setf (gethash (car pair
) hash
) (cdr pair
)))
2960 (defun diff-hash-table-changed (diff-hash-table key-value-pairs-to-add keys-to-remove
)
2961 (let ((contents (diff-hash-table-contents diff-hash-table
)))
2964 (let* ((result (make-diff-hash-table :lock nil
:contents contents
))
2965 (test (hash-table-test contents
))
2968 (loop-over/ key
(to-lazy-list keys-to-remove
)
2969 (multiple-value-bind (value is-valid
)
2970 (gethash key contents
)
2972 (push (cons key value
) additions
))
2973 (remhash key contents
)))
2974 (loop-over/ key-value-pair
(to-lazy-list key-value-pairs-to-add
)
2975 (destructuring-bind (key . value
)
2977 (multiple-value-bind (value is-valid
)
2978 (gethash key contents
)
2980 (push (cons key value
) additions
)
2981 (push key removals
)))
2982 (setf (gethash key contents
) value
)))
2983 (setf (diff-hash-table-contents diff-hash-table
) (make-hash-table-delta :base result
:removals removals
:additions additions
:test test
))
2986 (make-diff-hash-table :lock nil
:contents
(make-hash-table-delta :base diff-hash-table
:removals
(to-list keys-to-remove
) :additions
(to-list key-value-pairs-to-add
) :test
(hash-table-delta-test contents
)))))))
2988 (defun diff-hash-table-with-additions (diff-hash-table key-value-pair-additions
)
2989 (diff-hash-table-changed diff-hash-table key-value-pair-additions nil
))
2991 (defun diff-hash-table-with-addition (diff-hash-table key value
)
2992 (diff-hash-table-changed diff-hash-table
(list (cons key value
)) nil
))
2995 (defun diff-hash-table-with-removals (diff-hash-table keys-to-remove
)
2996 (diff-hash-table-changed diff-hash-table nil keys-to-remove
))
2998 (defun diff-hash-table-with-removal (diff-hash-table key-to-remove
)
2999 (diff-hash-table-changed diff-hash-table nil
(list key-to-remove
)))
3002 (defun get-diff-hash (key diff-hash-table
)
3003 (let ((contents (diff-hash-table-contents diff-hash-table
)))
3006 (gethash key contents
))
3008 (let* ((test (hash-table-delta-test contents
))
3009 (from-additions (assoc key
(hash-table-delta-additions contents
) :test test
)))
3011 (values (cdr from-additions
) t
)
3012 (unless (position key
(hash-table-delta-removals contents
))
3013 (let ((base (hash-table-delta-base contents
)))
3014 (unresolved (get-diff-hash key base
))))))))))
3017 (loop for named-test in
**unit-tests
** do
3018 (destructuring-bind (identity sub-test-list
)
3020 (format t
"Testing ~A" (string identity
))
3023 (loop for laziness in
'(eager lazy
) do
3024 (loop for sub-test in sub-test-list for sub-test-number from
1 do
3025 (loop for compiled in
'(nil t
) do
3026 (destructuring-bind (sub-test-identity test
)
3027 (if (> (length sub-test
) 1)
3029 (list (format nil
"~A: " sub-test-number
) (car sub-test
)))
3030 ; (format t " ~A: " sub-test-identity)
3032 (let ((identity-string (format nil
" ~A in ~A mode, ~A: " sub-test-identity laziness
(if compiled
"compiled" "not compiled"))))
3034 (multiple-value-bind (passed info
)
3036 (eval `(funcall (compile nil
(lambda () (,laziness
,test
)))))
3037 (eval `(,laziness
,test
)))
3039 nil
;(format t (concatenate 'string identity-string " passed"))
3040 (progn (format t
(concatenate 'string identity-string
(format nil
"!!!failed!!!") (when info
(format nil
" ~A" info
)))) (terpri)))
3043 (format t
(concatenate 'string identity-string
"failed hard ~A ~S") err err
)