diff --git a/Code/defs.lisp b/Code/defs.lisp index 07a388e..3326b28 100644 --- a/Code/defs.lisp +++ b/Code/defs.lisp @@ -79,6 +79,7 @@ #:define-tuple-key #:def-tuple-key #:get-tuple-key #:tuple-key-name #:tuple-key? #:tuple-merge #:fset-setup-readtable #:*fset-readtable* + #:fset-setup-rereading-readtable #:*fset-rereading-readtable* #:$ #:% ; for the 'map' and 'bag' constructor macros #:? ; for `query' on 'list-relation' ;; Used by the bag methods that convert to and from lists. @@ -101,8 +102,8 @@ #:all-queries #:do-all-queries #:lookup-multi #:forward-key #:lookup-restricted #:lookup-multi-restricted - ;; named-readtable readtable - #:fset-readtable)) + ;; named-readtable readtables + #:fset-readtable #:fset-rereading-readtable)) ;;; The need has arisen to define a second FSet package. There are two motivations: @@ -183,6 +184,7 @@ #:define-tuple-key #:def-tuple-key #:get-tuple-key #:tuple-key-name #:tuple-key? #:tuple-merge #:fset-setup-readtable #:*fset-readtable* + #:fset-setup-rereading-readtable #:*fset-rereading-readtable* #:$ #:% ; for the 'map' and 'bag' constructor macros #:? ; for `query' on 'list-relation' ;; Used by the bag methods that convert to and from lists. @@ -205,8 +207,8 @@ #:all-queries #:do-all-queries #:lookup-multi #:forward-key #:lookup-restricted #:lookup-multi-restricted - ;; named-readtable readtable - #:fset-readtable)) + ;; named-readtable readtables + #:fset-readtable #:fset-rereading-readtable)) ;;; A convenient package for experimenting with FSet. Also serves as an example diff --git a/Code/fset.lisp b/Code/fset.lisp index 3ba2477..22ed904 100644 --- a/Code/fset.lisp +++ b/Code/fset.lisp @@ -2285,9 +2285,11 @@ the default implementation of maps in FSet." (if (member comp '(:less :greater)) comp (let ((def-comp (compare (map-default map1) (map-default map2)))) - (if (or (eq comp ':unequal) (eq def-comp ':unequal)) - ':unequal - ':equal))))) + (if (member def-comp '(:less :greater)) + def-comp + (if (or (eq comp ':unequal) (eq def-comp ':unequal)) + ':unequal + ':equal)))))) (defgeneric internal-do-map (map elt-fn &optional value-fn) (:documentation @@ -2975,9 +2977,11 @@ This is the default implementation of seqs in FSet." (if (member comp '(:less :greater)) comp (let ((def-comp (compare (seq-default s1) (seq-default s2)))) - (if (or (eq comp ':unequal) (eq def-comp ':unequal)) - ':unequal - ':equal))))) + (if (member def-comp '(:less :greater)) + def-comp + (if (or (eq comp ':unequal) (eq def-comp ':unequal)) + ':unequal + ':equal)))))) (defmethod compare-lexicographically ((s1 wb-seq) (s2 wb-seq)) (WB-Seq-Tree-Compare-Lexicographically (wb-seq-contents s1) (wb-seq-contents s2))) diff --git a/Code/macros.lisp b/Code/macros.lisp index c165aa4..3d54786 100644 --- a/Code/macros.lisp +++ b/Code/macros.lisp @@ -256,6 +256,12 @@ However, the implementation tries very hard to prevent this." (defun ximage (coll fn) (image fn coll)) +(define-modify-macro updatef (fn &rest keys) + xupdate) + +(defun xupdate (coll fn &rest keys) + (apply #'update fn coll keys)) + (define-modify-macro composef (fn) compose) diff --git a/Code/reader.lisp b/Code/reader.lisp index f2d4520..2f32f9c 100644 --- a/Code/reader.lisp +++ b/Code/reader.lisp @@ -34,7 +34,13 @@ ;;; ;;; The reader macros expand directly into invocations of the constructor macros, ;;; so the syntax is similar. Loading this file does _not_ cause these macros -;;; to be defined in the current readtable; see `fset-setup-readtable' below. +;;; to be defined in the current readtable. To use them, the recommended approach +;;; is to load system Named-Readables (it's in Quicklisp), and then do: +;;; +;;; > (named-readtables:in-readtable fset:fset-readtable) +;;; +;;; If you don't want to do that, you can use `*fset-readtable', or call +;;; `fset-setup-readtable' on an existing readtable. ;;; ;;; Set syntax: ;;; @@ -551,6 +557,7 @@ contains the pairs <1, a>, <1, b>, <2, a>, and <2, b>." ;;; ================================================================================ ;;; Reader macros +;;; See the discussion at the top of this file before using these. (defun |#{-reader| (stream subchar arg) (declare (ignore subchar arg)) (case (peek-char nil stream t nil t) @@ -566,6 +573,16 @@ contains the pairs <1, a>, <1, b>, <2, a>, and <2, b>." (read-delimited-list #\% stream t) (unless (eql (read-char stream) #\}) (error "Incorrect #{% ... %} syntax"))))) + (#\= + (read-char stream t nil t) + (if (eql (peek-char nil stream t nil t) #\|) + (progn + (read-char stream t nil t) + `(replay-map . ,(prog1 + (read-delimited-list #\| stream t) + (unless (eql (read-char stream) #\}) + (error "Incorrect #{=| ... |} syntax"))))) + `(replay-set . ,(read-delimited-list #\} stream t)))) (otherwise `(set . ,(read-delimited-list #\} stream t))))) @@ -593,18 +610,29 @@ contains the pairs <1, a>, <1, b>, <2, a>, and <2, b>." (defun fset-setup-readtable (readtable) "Adds FSet reader macros to `readtable'. Returns `readtable'." - (set-dispatch-macro-character #\# #\{ #'|#{-reader| readtable) + (set-dispatch-macro-character #\# #\{ '|#{-reader| readtable) (set-macro-character #\} (get-macro-character #\)) nil readtable) - (set-dispatch-macro-character #\# #\[ #'|#[-reader| readtable) + (set-dispatch-macro-character #\# #\[ '|#[-reader| readtable) (set-macro-character #\] (get-macro-character #\)) nil readtable) - (set-dispatch-macro-character #\# #\~ #'|#~-reader| readtable) - (set-dispatch-macro-character #\# #\$ #'|#$-reader| readtable) - (set-dispatch-macro-character #\# #\% #'|#%-reader| readtable) + (set-dispatch-macro-character #\# #\~ '|#~-reader| readtable) + (set-dispatch-macro-character #\# #\$ '|#$-reader| readtable) + (set-dispatch-macro-character #\# #\% '|#%-reader| readtable) readtable) (defvar *fset-readtable* (fset-setup-readtable (copy-readtable nil)) "A copy of the standard readtable with FSet reader macros installed.") +;;; Named-Readtables provides a better way to switch readtables. +(named-readtables:defreadtable fset-readtable + (:merge :standard) + (:dispatch-macro-char #\# #\{ '|#{-reader|) + (:macro-char #\} (get-macro-character #\)) nil) + (:dispatch-macro-char #\# #\[ '|#[-reader|) + (:macro-char #\] (get-macro-character #\)) nil) + (:dispatch-macro-char #\# #\~ '|#~-reader|) + (:dispatch-macro-char #\# #\$ '|#$-reader|) + (:dispatch-macro-char #\# #\% '|#%-reader|)) + ;;; These function in the traditional Lisp manner, constructing the structures ;;; at read time. They can therefore be used to read back previously printed @@ -612,30 +640,39 @@ contains the pairs <1, a>, <1, b>, <2, a>, and <2, b>." (defun |rereading-#{-reader| (stream subchar arg) (declare (ignore subchar arg) (notinline empty-bag)) - (case (peek-char nil stream t nil t) - (#\| - (read-char stream t nil t) - (let ((map (convert 'map (read-delimited-list #\| stream t) :value-fn #'cadr))) - (unless (eql (read-char stream) #\}) - (error "Incorrect #{| ... |} syntax")) - (if (eql #\/ (peek-char nil stream nil nil t)) - (progn - (read-char stream t nil t) - (with-default map (read stream t nil t))) - map))) - (#\% - (read-char stream t nil t) - (let ((stuff (read-delimited-list #\% stream t)) - (result (empty-bag))) - (unless (eql (read-char stream) #\}) - (error "Incorrect #{% ... %} syntax")) - (dolist (x stuff) - (if (and (consp x) (eq (car x) '%)) - (adjoinf result (cadr x) (caddr x)) - (adjoinf result x))) - result)) - (otherwise - (convert 'set (read-delimited-list #\} stream t))))) + (flet ((read-map (tag) + (read-char stream t nil t) + (let ((pairs (read-delimited-list #\| stream t))) + (unless (eql (read-char stream) #\}) + (error "Incorrect #{~A| ... |} syntax" tag)) + (if (eql #\/ (peek-char nil stream nil nil t)) + (progn + (read-char stream t nil t) + (values pairs (read stream t nil t))) + (values pairs nil))))) + (case (peek-char nil stream t nil t) + (#\| + (let ((pairs default (read-map ""))) + (with-default (convert 'map pairs :value-fn #'cadr) default))) + (#\% + (read-char stream t nil t) + (let ((stuff (read-delimited-list #\% stream t)) + (result (empty-bag))) + (unless (eql (read-char stream) #\}) + (error "Incorrect #{% ... %} syntax")) + (dolist (x stuff) + (if (and (consp x) (eq (car x) '%)) + (adjoinf result (cadr x) (caddr x)) + (adjoinf result x))) + result)) + (#\= + (read-char stream t nil t) + (if (eql (peek-char nil stream t nil t) #\|) + (let ((pairs default (read-map "="))) + (with-default (convert 'replay-map pairs :value-fn #'cadr) default)) + (convert 'replay-set (read-delimited-list #\} stream t)))) + (otherwise + (convert 'set (read-delimited-list #\} stream t)))))) (defun |rereading-#[-reader| (stream subchar arg) (declare (ignore subchar arg)) @@ -662,12 +699,12 @@ contains the pairs <1, a>, <1, b>, <2, a>, and <2, b>." "Adds the FSet rereading reader macros to `readtable'. These reader macros will correctly read structure printed by the FSet print functions. Returns `readtable'." - (set-dispatch-macro-character #\# #\{ #'|rereading-#{-reader| readtable) + (set-dispatch-macro-character #\# #\{ '|rereading-#{-reader| readtable) (set-macro-character #\} (get-macro-character #\)) nil readtable) - (set-dispatch-macro-character #\# #\[ #'|rereading-#[-reader| readtable) + (set-dispatch-macro-character #\# #\[ '|rereading-#[-reader| readtable) (set-macro-character #\] (get-macro-character #\)) nil readtable) - (set-dispatch-macro-character #\# #\~ #'|rereading-#~-reader| readtable) - (set-dispatch-macro-character #\# #\% #'|#%-reader| readtable) + (set-dispatch-macro-character #\# #\~ '|rereading-#~-reader| readtable) + (set-dispatch-macro-character #\# #\% '|#%-reader| readtable) readtable) (defvar *fset-rereading-readtable* (fset-setup-rereading-readtable (copy-readtable nil)) @@ -675,12 +712,11 @@ will correctly read structure printed by the FSet print functions. Returns installed. This readtable can be used to read structure printed by the FSet print functions.") -(named-readtables:defreadtable fset-readtable +(named-readtables:defreadtable fset-rereading-readtable (:merge :standard) - (:dispatch-macro-char #\# #\{ #'|#{-reader|) + (:dispatch-macro-char #\# #\{ '|rereading-#{-reader|) (:macro-char #\} (get-macro-character #\)) nil) - (:dispatch-macro-char #\# #\[ #'|#[-reader|) + (:dispatch-macro-char #\# #\[ '|rereading-#[-reader|) (:macro-char #\] (get-macro-character #\)) nil) - (:dispatch-macro-char #\# #\~ #'|#~-reader|) - (:dispatch-macro-char #\# #\$ #'|#$-reader|) - (:dispatch-macro-char #\# #\% #'|#%-reader|)) + (:dispatch-macro-char #\# #\~ '|rereading-#~-reader|) + (:dispatch-macro-char #\# #\% '|rereading-#%-reader|)) diff --git a/Code/replay.lisp b/Code/replay.lisp index 14f8d48..dcd48ec 100644 --- a/Code/replay.lisp +++ b/Code/replay.lisp @@ -21,8 +21,10 @@ (:copier nil)) "A replay set is like a set, except that its iteration order is the order in which members were added to it. It does not support all set operations, but you can convert it to a set. -Note that in the current implementation, `less' on a replay set takes O(n) time. Replay sets -are printed as \"#{= ... }\"." +Note that in the current implementation, `less' on a replay set takes O(n) time. Also, two +replay sets are equal only if they both contain the same elements and have the same iteration +order; if you just want to compare the contents, convert them to ordinary sets first. Replay +sets are printed as \"#{= ... }\"." (contents nil :read-only t) (ordering nil :read-only t)) @@ -48,6 +50,36 @@ are printed as \"#{= ... }\"." (if tree (values (wb-set-tree-arb tree) t) (values nil nil)))) +(defmethod first ((s wb-replay-set)) + (let ((val? val (WB-Seq-Tree-Subscript (wb-replay-set-ordering s) 0))) + (values val val?))) + +(defmethod last ((s wb-replay-set)) + (let ((tree (wb-replay-set-ordering s)) + ((val? val (WB-Seq-Tree-Subscript tree (1- (WB-Seq-Tree-Size tree)))))) + (values val val?))) + +(defmethod least ((s wb-replay-set)) + (let ((tree (wb-replay-set-contents s))) + (if tree (values (WB-Set-Tree-Least tree) t) + (values nil nil)))) + +(defmethod greatest ((s wb-replay-set)) + (let ((tree (wb-replay-set-contents s))) + (if tree (values (WB-Set-Tree-Greatest tree) t) + (values nil nil)))) + +(defmethod at-index ((m wb-replay-set) index) + (let ((ordering (wb-replay-set-ordering m)) + ((size (wb-seq-tree-size ordering)))) + (unless (and (>= index 0) (< index size)) + (error 'simple-type-error :datum index :expected-type `(integer 0 (,size)) + :format-control "Index ~D out of bounds on ~A" + :format-arguments (list index m))) + (let ((ignore val (wb-seq-tree-subscript ordering index))) + (declare (ignore ignore)) + val))) + (defmethod contains? ((s wb-replay-set) x &optional (y nil y?)) (declare (ignore y)) (check-two-arguments y? 'contains? 'wb-set) @@ -56,6 +88,17 @@ are printed as \"#{= ... }\"." (defmethod lookup ((s wb-replay-set) value) (wb-set-tree-find-equal (wb-replay-set-contents s) value)) +(defmethod compare ((set1 wb-replay-set) (set2 wb-replay-set)) + (let ((comp (wb-set-tree-compare (wb-replay-set-contents set1) (wb-replay-set-contents set2)))) + (if (member comp '(:less :greater)) + comp + (let ((ord-comp (wb-seq-tree-compare (wb-replay-set-ordering set1) (wb-replay-set-ordering set2)))) + (if (member ord-comp '(:less :greater)) + ord-comp + (if (or (eq comp ':unequal) (eq ord-comp ':unequal)) + ':unequal + ':equal)))))) + (defmethod convert ((to-type (eql 'seq)) (s wb-replay-set) &key) (make-wb-seq (wb-replay-set-ordering s))) (defmethod convert ((to-type (eql 'wb-seq)) (s wb-replay-set) &key) @@ -76,6 +119,16 @@ are printed as \"#{= ... }\"." (defmethod convert ((to-type (eql 'wb-replay-set)) (s wb-set) &key) (make-wb-replay-set (wb-set-contents s) (wb-seq-contents (convert 'wb-seq s)))) +(defmethod convert ((to-type (eql 'replay-set)) (l list) &key) + (make-wb-replay-set (wb-set-tree-from-list l) (wb-seq-tree-from-list l))) +(defmethod convert ((to-type (eql 'wb-replay-set)) (l list) &key) + (make-wb-replay-set (wb-set-tree-from-list l) (wb-seq-tree-from-list l))) + +(defmethod convert ((to-type (eql 'replay-set)) (v vector) &key) + (make-wb-replay-set (wb-set-tree-from-cl-sequence v) (wb-seq-tree-from-vector v))) +(defmethod convert ((to-type (eql 'wb-replay-set)) (v vector) &key) + (make-wb-replay-set (wb-set-tree-from-cl-sequence v) (wb-seq-tree-from-vector v))) + (defmethod with ((s wb-replay-set) value &optional (arg2 nil arg2?)) (declare (ignore arg2)) (check-two-arguments arg2? 'with 'wb-replay-set) @@ -181,7 +234,9 @@ mapped function, in the order in which they were first encountered." "A replay map is like a map, except that its iteration order is the order in which keys were first added to it. It does not support all map operations, but you can convert it to a map. Note that in the current implementation, `less' on a replay map takes O(n) time. -Replay maps are printed as \"#{=| ... |}\"." +Also, two replay maps are equal only if they both contain the same pairs and have the same +iteration order; if you just want to compare the contents, convert them to ordinary maps +first. Replay maps are printed as \"#{=| ... |}\"." contents ordering) @@ -214,6 +269,49 @@ Replay maps are printed as \"#{=| ... |}\"." (values key val t)) (values nil nil nil)))) +(defmethod first ((m wb-replay-map)) + (let ((key? key (wb-seq-tree-subscript (wb-replay-map-ordering m) 0))) + (values (if key? key (map-default m)) + (and key? (let ((ignore val (wb-map-tree-lookup (wb-replay-map-contents m) key))) + (declare (ignore ignore)) + val)) + key?))) + +(defmethod last ((m wb-replay-map)) + (let ((tree (wb-replay-map-ordering m)) + ((key? key (wb-seq-tree-subscript tree (1- (wb-seq-tree-size tree)))))) + (values (if key? key (map-default m)) + (and key? (let ((ignore val (wb-map-tree-lookup (wb-replay-map-contents m) key))) + (declare (ignore ignore)) + val)) + key?))) + +(defmethod least ((m wb-replay-map)) + (let ((tree (wb-replay-map-contents m))) + (if tree + (let ((key val (wb-map-tree-least-pair tree))) + (values key val t)) + (values nil nil nil)))) + +(defmethod greatest ((m wb-replay-map)) + (let ((tree (wb-replay-map-contents m))) + (if tree + (let ((key val (wb-map-tree-greatest-pair tree))) + (values key val t)) + (values nil nil nil)))) + +(defmethod at-index ((m wb-replay-map) index) + (let ((ordering (wb-replay-map-ordering m)) + ((size (wb-seq-tree-size ordering)))) + (unless (and (>= index 0) (< index size)) + (error 'simple-type-error :datum index :expected-type `(integer 0 (,size)) + :format-control "Index ~D out of bounds on ~A" + :format-arguments (list index m))) + (let ((ignore1 key (wb-seq-tree-subscript ordering index)) + ((ignore2 val (wb-map-tree-lookup (wb-replay-map-contents m) key)))) + (declare (ignore ignore1 ignore2)) + (values key val)))) + (defmethod size ((m wb-replay-map)) (WB-Map-Tree-Size (wb-replay-map-contents m))) @@ -222,6 +320,43 @@ Replay maps are printed as \"#{=| ... |}\"." (defmethod convert ((to-type (eql 'wb-map)) (m wb-replay-map) &key) (make-wb-map (wb-replay-map-contents m) (map-default m))) +(defmethod convert ((to-type (eql 'replay-map)) (list list) + &key (key-fn #'car) (value-fn #'cdr)) + (wb-replay-map-from-list list key-fn value-fn)) + +(defmethod convert ((to-type (eql 'wb-replay-map)) (list list) + &key (key-fn #'car) (value-fn #'cdr)) + (wb-replay-map-from-list list key-fn value-fn)) + +(defun wb-replay-map-from-list (list key-fn value-fn) + (let ((m nil) + (ord nil) + (key-fn (coerce key-fn 'function)) + (value-fn (coerce value-fn 'function))) + (dolist (pr list) + (let ((key (funcall key-fn pr))) + (setq m (WB-Map-Tree-With m key (funcall value-fn pr))) + (setq ord (WB-Seq-Tree-Insert ord (WB-Seq-Tree-Size ord) key)))) + (make-wb-replay-map m ord))) + +(defmethod convert ((to-type (eql 'replay-map)) (s sequence) + &key (key-fn #'car) (value-fn #'cdr)) + (wb-replay-map-from-cl-sequence s key-fn value-fn)) + +(defmethod convert ((to-type (eql 'wb-replay-map)) (s sequence) + &key (key-fn #'car) (value-fn #'cdr)) + (wb-replay-map-from-cl-sequence s key-fn value-fn)) + +(defun wb-replay-map-from-cl-sequence (s key-fn value-fn) + (let ((m nil) + (ord nil)) + (dotimes (i (length s)) + (let ((pr (elt s i)) + ((key (funcall key-fn pr)))) + (setq m (WB-Map-Tree-With m key (funcall value-fn pr))) + (setq ord (WB-Seq-Tree-Insert ord (WB-Seq-Tree-Size ord) key)))) + (make-wb-replay-map m ord))) + (defmethod lookup ((m wb-replay-map) key) (let ((val? val (wb-map-tree-lookup (wb-replay-map-contents m) key))) (values (if val? val (map-default m)) val?))) @@ -229,6 +364,20 @@ Replay maps are printed as \"#{=| ... |}\"." (defmethod domain-contains? ((m wb-replay-map) x) (wb-map-tree-lookup (wb-replay-map-contents m) x)) +(defmethod compare ((map1 wb-replay-map) (map2 wb-replay-map)) + (let ((comp (wb-map-tree-compare (wb-replay-map-contents map1) (wb-replay-map-contents map2)))) + (if (member comp '(:less :greater)) + comp + (let ((def-comp (compare (map-default map1) (map-default map2)))) + (if (member def-comp '(:less :greater)) + def-comp + (let ((ord-comp (wb-seq-tree-compare (wb-replay-map-ordering map1) (wb-replay-map-ordering map2)))) + (if (member ord-comp '(:less :greater)) + ord-comp + (if (or (eq comp ':unequal) (eq def-comp ':unequal) (eq ord-comp ':unequal)) + ':unequal + ':equal)))))))) + (defmethod with ((m wb-replay-map) key &optional (value nil value?)) (check-three-arguments value? 'with 'wb-replay-map) (let ((contents (wb-replay-map-contents m)) diff --git a/Code/testing.lisp b/Code/testing.lisp index eaa7d70..9315d19 100644 --- a/Code/testing.lisp +++ b/Code/testing.lisp @@ -253,6 +253,8 @@ (test (less-than? (tuple (+K0+ 1)) (tuple (+K0+ 2)))) (test (unequal? (tuple (+K0+ 1.0) (+K1+ 'c)) (tuple (+K0+ 1) (+K1+ 'c)))) (test (less-than? (tuple (+K0+ 1.0) (+K1+ 'c)) (tuple (+K0+ 1) (+K1+ 'd)))) + (test (not (equal? (map (3 7) :default 0) (map (3 7) :default 1)))) + (test (not (equal? (with-default (seq 42 17) 6) (with-default (seq 42 17) 9)))) (test (equal? (image +K0+ (set)) (set))) (test (equal? (image +K0+ (set (tuple))) (set nil))) diff --git a/Code/wb-trees.lisp b/Code/wb-trees.lisp index 8303a92..0f8012a 100644 --- a/Code/wb-trees.lisp +++ b/Code/wb-trees.lisp @@ -941,41 +941,17 @@ between equal trees." ;;; ================================================================================ ;;; Miscellany -;;; &&& Even with the pair special case, this is actually still 70% slower than -;;; repeated `with', though it conses slightly less. -;;; The right way is to sort the list, then do something like WB-Seq-Tree-From-List. (defun WB-Set-Tree-From-List (lst) - (labels ((recur (lst n) - (cond ((= n 0) nil) - ((= n 1) (vector (car lst))) - ;; Reduces consing about 12%, improves speed. - ((= n 2) - (ecase (Compare (car lst) (cadr lst)) - (:equal (vector (car lst))) - (:less (let ((v (make-array 2))) - (setf (svref v 0) (car lst) - (svref v 1) (cadr lst)) - v)) - (:greater (let ((v (make-array 2))) - (setf (svref v 0) (cadr lst) - (svref v 1) (car lst)) - v)) - (:unequal (WB-Set-Tree-With (vector (car lst)) (cadr lst))))) - (t - (let ((n2 (floor n 2))) - (WB-Set-Tree-Union (recur lst n2) - (recur (nthcdr n2 lst) - (- n n2)))))))) - (recur lst (length lst)))) + (let ((tree nil)) + (dolist (x lst) + (setq tree (WB-Set-Tree-With tree x))) + tree)) (defun WB-Set-Tree-From-CL-Sequence (seq) - (labels ((recur (n m) - (cond ((= n m) nil) - ((= n (1- m)) (vector (elt seq n))) - (t - (let ((n2 (floor (+ n m) 2))) - (WB-Set-Tree-Union (recur n n2) (recur n2 m))))))) - (recur 0 (length seq)))) + (let ((tree nil)) + (dotimes (i (length seq)) + (setq tree (WB-Set-Tree-With tree (elt seq i)))) + tree)) ;;; ================================================================================