diff --git a/TODO b/TODO
index 978d38fe6d9dbe97976f394639b5fad2ba7f7d5a..bc21098d5c130b09e69a746c1555fdbf4735c6c6 100644
--- a/TODO
+++ b/TODO
@@ -5,3 +5,5 @@ TODO
 * import trie from pangram thingie
 
 * DECLAIM - distributed execution of common-lisp agents with intent and mobility
+
+* move stateful datastructures to a stateful: or st: or sf: package.
diff --git a/fare-utils.asd b/fare-utils.asd
index 70eca7d7cedb8f4c7fc972bcfe948cca09654e51..5b134dcfba6fb228b2e8d7a0f63ff0a18582a81b 100644
--- a/fare-utils.asd
+++ b/fare-utils.asd
@@ -49,7 +49,7 @@
                (:file "pure-alist" :depends-on ("pure-maps"))
                (:file "pure-trees" :depends-on ("pure-maps" "order"))
                (:file "pure-hash-tables" :depends-on ("pure-trees" "pure-alist"))
-               (:file "faim" :depends-on ("pure-maps" "pure-trees"))
+               (:file "fmim" :depends-on ("pure-maps" "pure-trees"))
 
                ;;; Stateful containers
                (:file "containers" :depends-on ("order" "basic-macros" "basic-utils"))
diff --git a/faim.lisp b/fmim.lisp
similarity index 80%
rename from faim.lisp
rename to fmim.lisp
index 4e62b2a55224ceaa19d7bb239627f47afc1f04da..d54076ffb728f17f866da701f4472ffc2ee2b03e 100644
--- a/faim.lisp
+++ b/fmim.lisp
@@ -1,41 +1,32 @@
 ;;; -*- Mode: Lisp ; Base: 10 ; Syntax: ANSI-Common-Lisp -*-
-;;; Fast Appendable Integer Maps
-;;;
-;;; See "Fast Mergable Integer Maps"
-;;; Chris Okasaki & Andrew Gill, 1998
+;;; "Fast Mergable Integer Maps"
+;;; See article of same name by Chris Okasaki & Andrew Gill, 1998
 ;;; http://www.eecs.usma.edu/webs/people/okasaki/ml98maps.ps
 ;;; Under the hood: Big Endian Patricia Trees (Tries).
-;;; Except that in our API, what *they* call Merge is called Append.
+;;; Note however that in our API, what they call "merge" is called "join".
 
 #+xcvb (module (:depends-on ("pure-maps" "pure-trees")))
 
-(in-package :fare-utils)
+(in-package :pure)
 
-;;; Generic tree interface
-
-(defclass pf:<faim>
-    (tree:<tree> pf:<map>
-     fmap-simple-empty fmap-simple-decons fmap-simple-update
-     fmap-simple-merge fmap-simple-append/list fmap-simple-count)
+(defclass <fmim>
+    (<map> <tree>
+     map-simple-empty map-simple-decons map-simple-update-key
+     map-simple-map/2 map-simple-join/list map-simple-size)
   ()
-  (:documentation "Keys in binary trees increase from left to right"))
-
-(defparameter pf:<faim> (make-instance 'pf:<faim>))
+  (:documentation "Fast Merge Integer Maps"))
 
-(defclass pure-box ()
-  ((datum
-    :initarg :datum
-    :reader datum)))
+(defparameter <fmim> (make-instance '<fmim>))
 
 ;;; (big-endian) patricia tree (aka trie)
-(defclass trie-head (pure-box)
+(defclass trie-head (box)
   ((height
     :type fixnum
     :initform 0
     :initarg :height
     :reader node-height)))
 (defclass trie-node () ())
-(defclass trie-skip (trie-node pure-box)
+(defclass trie-skip (trie-node box)
   ((prefix-bits
     :type (integer 0 *)
     :initarg :prefix-bits
@@ -46,15 +37,10 @@
     :reader node-prefix-length)))
 (defclass trie-branch (trie-node binary-branch) ())
 (defclass full-trie-branch (trie-branch) ())
-;;; Not needed: position tells us! (defclass trie-leaf (trie-node pure-box) ())
+;;; Not needed: position tells us! (defclass trie-leaf (trie-node box) ())
 
-(defmethod pf:check-invariant ((i pf:<faim>) role map)
-  (declare (optimize (debug 3)))
-  (declare (ignore role))
-  (when map
-    (check-type map trie-head)
-    (trie-check-invariant (datum map) (node-height map) 0))
-  map)
+(defmethod check-invariant ((i <fmim>) (map trie-head))
+  (trie-check-invariant (datum map) (node-height map) 0))
 
 (defun trie-check-invariant (trie position key)
   (declare (optimize (debug 3)))
@@ -78,9 +64,8 @@
            (trie-check-invariant (right trie) pos (dpb 1 (byte 1 pos) key))))))
   (values))
 
-
-(defmethod pf:lookup ((i pf:<faim>) map key)
-  (check-type map trie-head)
+(defmethod lookup ((i <fmim>) map key)
+  (check-type map (or null trie-head))
   (check-type key (integer 0 *))
   (if map
       (let ((len (integer-length key))
@@ -160,7 +145,7 @@
         (make-instance 'trie-head :height height :datum trie))
       (make-instance 'trie-head :height height :datum trie)))
 
-(defmethod pf:insert ((i pf:<faim>) map key value)
+(defmethod insert ((i <fmim>) map key value)
   (check-type map (or null trie-head))
   (check-type key (integer 0 *))
   (let ((len (integer-length key)))
@@ -214,18 +199,18 @@
                 pos
                 (left trie)
                 (trie-insert (right trie) pos key value))))))))
-(defmethod pf:remove ((i pf:<faim>) map key)
+(defmethod drop ((i <fmim>) map key)
   (check-type map (or null trie-head))
   (multiple-value-bind (v f)
-      (pf:lookup i map key)
+      (lookup i map key)
     (if f
         (values (make-trie-head
                  (node-height map)
-                 (trie-remove (datum map) (node-height map) key))
+                 (trie-drop (datum map) (node-height map) key))
                 v f)
         (values map nil nil))))
-(defun trie-remove (trie position key)
-  ;; from our contract with pf:remove,
+(defun trie-drop (trie position key)
+  ;; from our contract with drop,
   ;; we do assume the key IS in fact in the trie.
   (if (zerop position)
       (values trie nil nil)
@@ -237,21 +222,21 @@
            (assert (= pbits (ldb (byte plen pos) key)))
            (make-trie-skip
             position plen pbits
-            (trie-remove (datum trie) pos key))))
+            (trie-drop (datum trie) pos key))))
         (trie-branch
          (let ((pos (1- position)))
            (if (zerop (ldb (byte 1 pos) key))
                (make-trie-branch
                 pos
-                (trie-remove (left trie) pos key)
+                (trie-drop (left trie) pos key)
                 (right trie))
                (make-trie-branch
                 pos
                 (left trie)
-                (trie-remove (right trie) pos key))))))))
-(defmethod pf:first-key-value ((i pf:<faim>) map)
-  (tree:leftmost i map))
-(defmethod pf:fold-left ((i pf:<faim>) map f seed)
+                (trie-drop (right trie) pos key))))))))
+(defmethod first-key-value ((i <fmim>) map)
+  (leftmost i map))
+(defmethod fold-left ((i <fmim>) map f seed)
   (if (null map)
       seed
       (trie-fold-left (datum map) (node-height map) 0 f seed)))
@@ -271,7 +256,7 @@
             (right trie) pos (dpb 1 (byte 1 pos) key) f
             (trie-fold-left
              (left trie) pos key f seed)))))))
-(defmethod pf:fold-right ((i pf:<faim>) map f seed)
+(defmethod fold-right ((i <fmim>) map f seed)
   (if (null map)
       seed
       (trie-fold-right (datum map) (node-height map) 0 f seed)))
@@ -291,10 +276,10 @@
             (left trie) pos key f
             (trie-fold-right
              (right trie) pos (dpb 1 (byte 1 pos) key) f seed)))))))
-(defmethod tree:leftmost ((i pf:<faim>) map)
-  (if map
-      (trie-leftmost (datum map) (node-height map) 0)
-      (values nil nil nil)))
+(defmethod leftmost ((i <fmim>) map)
+  (if (null map)
+      (values nil nil nil)
+      (trie-leftmost (datum map) (node-height map) 0)))
 (defun trie-leftmost (trie position key)
   (if (zerop position)
       (values key trie t)
@@ -307,10 +292,10 @@
             (datum trie) pos (dpb pbits (byte plen pos) key))))
         (trie-branch
          (trie-leftmost (left trie) (1- position) key)))))
-(defmethod tree:rightmost ((i pf:<faim>) map)
-  (if map
-      (trie-rightmost (datum map) (node-height map) 0)
-      (values nil nil nil)))
+(defmethod rightmost ((i <fmim>) map)
+  (if (null map)
+      (values nil nil nil)
+      (trie-rightmost (datum map) (node-height map) 0)))
 (defun trie-rightmost (trie position key)
   (if (zerop position)
       (values key trie t)
@@ -325,15 +310,15 @@
          (let ((pos (1- position)))
            (trie-rightmost (right trie) pos (dpb 1 (byte 1 pos) key)))))))
 
-(defmethod pf:divide ((i pf:<faim>) node)
+(defmethod divide ((i <fmim>) node)
   (NIY))
-(defmethod pf:divide/list ((i pf:<faim>) node)
+(defmethod divide/list ((i <fmim>) node)
   (NIY))
-(defmethod tree:join ((i pf:<faim>) a b)
+(defmethod join-nodes ((i <fmim>) a b)
   (NIY))
 
-;;; The whole point of faim is that we could do a fast "append",
-(defmethod pf:append ((i pf:<faim>) a b)
+;;; The whole point of fmim is that we could do a fast "append",
+(defmethod join ((i <fmim>) a b)
   (cond
     ((null a) b)
     ((null b) a)
@@ -344,10 +329,10 @@
             (hb (node-height b))
             (h (max ha hb)))
        (make-trie-head
-        h (trie-append (make-trie-skip h (- h ha) 0 (datum a))
-                       (make-trie-skip h (- h hb) 0 (datum b))
-                       h))))))
-(defun trie-append (a b position)
+        h (trie-join (make-trie-skip h (- h ha) 0 (datum a))
+                     (make-trie-skip h (- h hb) 0 (datum b))
+                     h))))))
+(defun trie-join (a b position)
   (if (zerop position) a
       (etypecase a
         (full-trie-branch a)
@@ -357,8 +342,8 @@
              (trie-branch
               (make-trie-branch
                position
-               (trie-append (left a) (left b) pos)
-               (trie-append (right a) (right b) pos)))
+               (trie-join (left a) (left b) pos)
+               (trie-join (right a) (right b) pos)))
              (trie-skip
               (let* ((pbits (node-prefix-bits b))
                      (plen (node-prefix-length b))
@@ -369,9 +354,9 @@
                        (ldb (byte (1- plen) 0) pbits) (datum b))))
                 (if (zerop bh)
                     (make-trie-branch
-                     position (trie-append (left a) b1 pos) (right a))
+                     position (trie-join (left a) b1 pos) (right a))
                     (make-trie-branch
-                     position (left a) (trie-append (right a) b1 pos))))))))
+                     position (left a) (trie-join (right a) b1 pos))))))))
         (trie-skip
          (let* ((pbits (node-prefix-bits a))
                 (plen (node-prefix-length a))
@@ -385,9 +370,9 @@
              (trie-branch
                 (if (zerop ah)
                     (make-trie-branch
-                     position (trie-append a1 (left b) pos) (right b))
+                     position (trie-join a1 (left b) pos) (right b))
                     (make-trie-branch
-                     position (left b) (trie-append a1 (right b) pos))))
+                     position (left b) (trie-join a1 (right b) pos))))
              (trie-skip
               (let* ((pbitsb (node-prefix-bits b))
                      (plenb (node-prefix-length b))
@@ -397,7 +382,21 @@
                        pos (1- plenb)
                        (ldb (byte (1- plenb) 0) pbitsb) (datum b))))
                 (if (= ah bh)
-                    (make-trie-skip position 1 0 (trie-append a1 b1 pos))
+                    (make-trie-skip position 1 0 (trie-join a1 b1 pos))
                     (if (zerop ah)
                         (make-trie-branch position a1 b1)
                         (make-trie-branch position b1 a1)))))))))))
+
+#|
+You could implement sets of integers as bitmaps,
+as a list of integers, as a binary tree,
+or as big-endian patricia tries mapping integers to the unit type.
+In the latter case, using multiple dispatch for sub-operations
+instead of the typecases I used above would allow to easily add an
+optimization to my patricia trie implementation in the case the
+target type is the unit type (eql t), by i.e. short-circuiting
+data representation and membership test on full subtrees.
+
+See also
+http://paste.lisp.org/display/95321
+|#
diff --git a/pure-alist.lisp b/pure-alist.lisp
index 369a51e90c16470f26eb387a918aae1f29957f7b..7bf2c460e40a4463ab1b0ba75e117edf68bc3f65 100644
--- a/pure-alist.lisp
+++ b/pure-alist.lisp
@@ -3,67 +3,60 @@
 
 #+xcvb (module (:depends-on ("pure-maps")))
 
-(in-package :fare-utils)
+(in-package :pure)
 
-
-(defclass pf:<alist>
-    (pf:<map> eq:<hashable>
-     fmap-simple-empty fmap-simple-decons fmap-simple-update fmap-simple-divide/list
-     fmap-simple-merge fmap-simple-append fmap-simple-append/list)
+(defclass <alist>
+    (<map>
+     map-simple-empty map-simple-decons map-simple-update-key map-simple-divide/list
+     map-simple-map/2 map-simple-join map-simple-join/list)
   ((eq-interface
     :initarg :eq
     :initform eq:<eq>
     :reader eq-interface)))
 
-(defmethod pf:check-invariant ((i pf:<alist>) role map)
-  (declare (ignore role))
+(defmethod check-invariant ((i <alist>) map)
   (loop :for ((key . val) . rest) :on map :do
-    (assert (not (member key rest :key 'car :test (eq:test-function i))) ()
-            "Key ~S is present twice in alist ~S" key map))
-  map)
-
-(defun pf:<alist> (&optional (eq eq:<eq>))
-  (memo:memoized 'make-instance 'pf:<alist> :eq eq))
-
-(defparameter pf:<alist> (pf:<alist>))
-(defmethod eq:= ((i pf:<alist>) x y)
-  (eq:= (eq-interface i) x y))
-(defmethod eq:test-function ((i pf:<alist>))
-  (eq:test-function (eq-interface i)))
-
-(defmethod pf:lookup ((i pf:<alist>) map key)
-  (let ((pair (assoc key map :test (eq:test-function i))))
-    (if pair
-        (values (cdr pair) t)
-        (values nil nil))))
-    
-(defmethod pf:insert ((i pf:<alist>) map key value)
-  (acons key value (pf:remove i map key)))
-(defmethod pf:remove ((i pf:<alist>) map key)
-  (multiple-value-bind (v f) (pf:lookup i map key)
-    (if f
-        (values (remove key map :key 'car :test (eq:test-function i)) v t)
-        (values map nil nil))))
-(defmethod pf:first-key-value ((i pf:<alist>) map)
+    (assert (not (member key rest
+                         :key 'car
+                         :test (eq:test-function (eq-interface i))))
+            () "Key ~S is present twice in alist ~S" key map)))
+
+(defun <alist> (&optional (eq eq:<eq>))
+  (memo:memoized 'make-instance '<alist> :eq eq))
+
+(defparameter <alist> (<alist>))
+
+(defmethod lookup ((i <alist>) map key)
+  (if (null map)
+      (values nil nil)
+      (let ((pair (assoc key map :test (eq:test-function (eq-interface i)))))
+        (if pair
+            (values (cdr pair) t)
+            (values nil nil)))))
+
+(defmethod insert ((i <alist>) map key value)
+  (acons key value (drop i map key)))
+(defmethod drop ((i <alist>) map key)
+  (if (null map)
+      (values nil nil nil)
+      (multiple-value-bind (v f) (lookup i map key)
+        (if f
+            (values (remove key map :key 'car :test (eq:test-function (eq-interface i))) v t)
+            (values map nil nil)))))
+(defmethod first-key-value ((i <alist>) map)
   (values (caar map) (cdar map) (not (null map))))
-(defmethod pf:fold-left ((i pf:<alist>) map f seed)
+(defmethod fold-left ((i <alist>) map f seed)
   (reduce (lambda (acc pair) (funcall f acc (car pair) (cdr pair)))
           map :initial-value seed))
-(defmethod pf:fold-right ((i pf:<alist>) map f seed)
+(defmethod fold-right ((i <alist>) map f seed)
   (reduce (lambda (pair acc) (funcall f (car pair) (cdr pair) acc))
           map :initial-value seed :from-end t))
-(defmethod pf:for-each ((i pf:<alist>) map f)
+(defmethod for-each ((i <alist>) map f)
   (loop :for (key . val) :in map :do (funcall f key val))
   (values))
-(defmethod pf:divide ((i pf:<alist>) map)
+(defmethod divide ((i <alist>) map)
   (let* ((l (length map))
          (l1 (floor l 2)))
     (values (subseq map 0 l1) (nthcdr l1 map))))
-(defmethod pf:count ((i pf:<alist>) map)
+(defmethod size ((i <alist>) map)
   (length map))
-
-(defmethod pf:convert (i2 i1 map1)
-  (pf:fold-right
-   i1 map1
-   (lambda (k v map2) (pf:insert i2 map2 k v))
-   (pf:empty i2)))
diff --git a/pure-hash-tables.lisp b/pure-hash-tables.lisp
index d0006e79264a62cbcd7c17e0d3a468a98bba11c3..035ea01b8ba1ea4c2a37a299aad5924972e5696b 100644
--- a/pure-hash-tables.lisp
+++ b/pure-hash-tables.lisp
@@ -3,103 +3,98 @@
 
 #+xcvb (module (:depends-on ("pure-trees")))
 
-(in-package :fare-utils)
+(in-package :pure)
 
-(defclass pf:<hash-table>
-    (pf:<map> eq:<hashable>
-     fmap-simple-empty fmap-simple-append)
-  ((alist-interface :accessor alist-interface))
+(defclass <hash-table>
+    (<map>
+     map-simple-join)
+  ((key-interface :reader key-interface :initarg :key)
+   (hashmap-interface :reader hashmap-interface :initarg :hashmap)
+   (bucketmap-interface :reader bucketmap-interface :initarg :bucketmap))
   (:documentation "pure hash table"))
 
-(defmethod shared-initialize :after ((i pf:<hash-table>)
-                                     slot-names &rest initargs &key &allow-other-keys)
-  (declare (ignore slot-names initargs))
-  (setf (alist-interface i) (pf:<alist> i)))
+(defun <hash-table> (&key (key eq:<equal>)
+                     (hashmap <im>)
+                     (bucketmap (<alist> key)))
+  (assert (typep key 'eq:<hashable>))
+  (assert (typep hashmap '<map>))
+  (assert (typep bucketmap '<map>))
+  (memo:memoized 'make-instance '<hash-table>
+                 :key key :hashmap hashmap :bucketmap bucketmap))
+(defparameter <hash-table> (<hash-table>))
 
-(defparameter pf:<hash-table>
-  (memo:memoized 'make-instance 'pf:<hash-table>))
-(defparameter pf:<ht> pf:<hash-table>)
-
-(defclass pf:<equal-hash-table> (pf:<hash-table> eq:<equal>) ())
-(defparameter pf:<equal-hash-table>
-  (memo:memoized 'make-instance 'pf:<equal-hash-table>))
-(defparameter pf:<equal-ht> pf:<equal-hash-table>)
-
-(defmethod pf:check-invariant ((i pf:<hash-table>) role map)
-  (pf:check-invariant pf:<im> role map)
-  (pf:for-each
-   pf:<im> map
+(defmethod check-invariant ((i <hash-table>) map)
+  (check-invariant (hashmap-interface i) map)
+  (for-each
+   (hashmap-interface i) map
    (lambda (hash bucket)
      (declare (ignore hash))
-     (pf:check-invariant (alist-interface i) role bucket)))
-  map)
+     (check-invariant (bucketmap-interface i) bucket))))
 
-(defmethod pf:lookup ((i pf:<hash-table>) node key)
-  (if (null node) (values nil nil)
-      (let ((bucket (pf:lookup pf:<im> node (eq:hash i key))))
-        (if bucket
-            (pf:lookup (alist-interface i) bucket key)
-            (values nil nil)))))
-(defmethod pf:insert ((i pf:<hash-table>) node key value)
-  (let ((hash (eq:hash i key)))
-    (pf:insert
-     pf:<im> node hash
-     (pf:insert (alist-interface i)
-                  (pf:lookup pf:<im> node hash)
-                  key value))))
-(defmethod pf:remove ((i pf:<hash-table>) node key)
-  (if (null node)
-      (values nil nil nil)
-      (let* ((hash (node-key node))
-             (bucket (node-value node))
-             (key (caar bucket))
-             (value (cdar bucket))
-             (rest (rest bucket)))
-        (values
-         (if rest
-             (pf:insert pf:<im> node hash rest)
-             (pf:remove pf:<im> node hash))
-         key value t))))
-(defmethod pf:first-key-value ((i pf:<hash-table>) map)
-  (if map
-      (pf:first-key-value (alist-interface i)
-                            (nth 1 (pf:first-key-value pf:<im> map)))
-      (values nil nil nil)))
-(defmethod pf:fold-left ((i pf:<hash-table>) node f seed)
-  (pf:fold-left pf:<im> node
-                  (lambda (a h bucket)
-                    (declare (ignore h))
-                    (pf:fold-left (alist-interface i) bucket f a))
-                  seed))
-(defmethod pf:fold-right ((i pf:<hash-table>) node f seed)
-  (pf:fold-right pf:<im> node
-                   (lambda (h bucket a)
-                     (declare (ignore h))
-                     (pf:fold-right (alist-interface i) bucket f a))
-                  seed))
-(defmethod pf:for-each ((i pf:<hash-table>) map f)
-  (pf:for-each
-   pf:<im> map
+(defmethod empty ((i <hash-table>))
+  (empty (hashmap-interface i)))
+(defmethod empty-p ((i <hash-table>) map)
+  (empty-p (hashmap-interface i) map))
+(defmethod lookup ((i <hash-table>) map key)
+  (let ((bucket (lookup (hashmap-interface i) map
+                        (eq:hash (key-interface i) key))))
+    (lookup (bucketmap-interface i) bucket key)))
+(defmethod insert ((i <hash-table>) node key value)
+  (let ((hash (eq:hash (key-interface i) key)))
+    (insert
+     (hashmap-interface i) node hash
+     (insert (bucketmap-interface i)
+             (multiple-value-bind (bucket foundp)
+                 (lookup (hashmap-interface i) node hash)
+               (if foundp bucket (empty (bucketmap-interface i))))
+             key value))))
+(defmethod drop ((i <hash-table>) map key)
+  (multiple-value-bind (hash bucket) ;; hashfoundp
+      (first-key-value (hashmap-interface i) map)
+    (multiple-value-bind (new-bucket key value) ;; foundp
+        (decons (bucketmap-interface i) bucket)
+      (values
+       (if new-bucket
+           (insert (hashmap-interface i) map hash new-bucket)
+           (drop (hashmap-interface i) map hash))
+       key value t))))
+(defmethod first-key-value ((i <hash-table>) map)
+  (multiple-value-bind (hash bucket foundp)
+      (first-key-value (hashmap-interface i) map)
+    (declare (ignore hash))
+    (if foundp
+        (first-key-value (bucketmap-interface i) bucket)
+        (values nil nil nil))))
+(defmethod fold-left ((i <hash-table>) node f seed)
+  (fold-left (hashmap-interface i) node
+             (lambda (a h bucket)
+               (declare (ignore h))
+               (fold-left (bucketmap-interface i) bucket f a))
+             seed))
+(defmethod fold-right ((i <hash-table>) node f seed)
+  (fold-right (hashmap-interface i) node
+              (lambda (h bucket a)
+                (declare (ignore h))
+                (fold-right (bucketmap-interface i) bucket f a))
+              seed))
+(defmethod for-each ((i <hash-table>) map f)
+  (for-each
+   (hashmap-interface i) map
    (lambda (hash bucket)
      (declare (ignore hash))
-     (pf:for-each (alist-interface i) bucket f))))
-(defmethod pf:divide ((i pf:<hash-table>) node)
+     (for-each (bucketmap-interface i) bucket f))))
+(defmethod divide ((i <hash-table>) node)
   (cond
-    ((null node)
-     (values nil nil))
     ((and (null (left node)) (null (right node)))
      (let ((hash (node-key node))
            (bucket (node-value node)))
-       (multiple-value-bind (b1 b2) (pf:divide (alist-interface i) bucket)
-         (values (when b1 (pf:insert i nil hash b1))
-                 (when b2 (pf:insert i nil hash b2))))))
-    (t
-     (pf:divide pf:<im> node))))
-(defmethod pf:divide/list ((i pf:<hash-table>) node)
-  (cond
-    ((null node)
-     (values nil nil))
-    ((and (null (left node)) (null (right node)))
-     (multiple-value-list (pf:divide i node)))
+       (multiple-value-bind (b1 b2) (divide (bucketmap-interface i) bucket)
+         (values (when b1 (insert i nil hash b1))
+                 (when b2 (insert i nil hash b2))))))
     (t
-     (pf:divide/list pf:<im> node))))
+     (divide (hashmap-interface i) node))))
+(defmethod divide/list ((i <hash-table>) node)
+  (let ((list (divide/list (hashmap-interface i) node)))
+    (if (cdr list)
+        list
+        (multiple-value-list (divide i node)))))
diff --git a/pure-maps.lisp b/pure-maps.lisp
index a539d894eb28410c037a78e1900077b130392223..e9f11bd02722e9f6280c7ed87a66f205dd4233b3 100644
--- a/pure-maps.lisp
+++ b/pure-maps.lisp
@@ -3,81 +3,81 @@
 
 #+xcvb (module (:depends-on ("eq" "pure")))
 
-(in-package :fare-utils)
+(in-package :pure)
 
 ;;; On this "Interface-Passing Style" of programming, see
 ;;;  http://fare.livejournal.com/155094.html
 
-(defclass pf:<map> (eq:<eq>) ())
+(defclass <map> () ())
 
-(defgeneric pf:empty (interface)
+(defgeneric empty (<map>)
   (:documentation "Return an empty map"))
-(defgeneric pf:empty-p (interface map)
+(defgeneric empty-p (<map> map)
   (:documentation "Return a boolean indicating whether the map was empty"))
-(defgeneric pf:lookup (interface map key)
+(defgeneric lookup (<map> map key)
   (:documentation "Lookup what map associates to a key,
 return two values, the associated value and
 a boolean that is true iff an association was found"))
-(defgeneric pf:insert (interface map key value)
+(defgeneric insert (<map> map key value)
   (:documentation "Add a key-value pair to a map,
 replacing any previous association for this key,
 return a new map."))
-(defgeneric pf:remove (interface map key)
-  (:documentation "Remove from a map the association corresponding to given key,
+(defgeneric drop (<map> map key)
+  (:documentation "Drop from a map the association corresponding to given key,
 returning three values:
 a new map without that association,
-the value from the removed association,
+the value from the dropped association,
 and a boolean that is true iff an association was found."))
-(defgeneric pf:first-key-value (interface map)
+(defgeneric first-key-value (<map> map)
   (:documentation "Return three values:
 a key, a value, and a boolean indicating
 whether the map was already empty."))
-(defgeneric pf:decons (interface map)
-  (:documentation "Remove an association from a map,
+(defgeneric decons (<map> map)
+  (:documentation "Drop the first association from a map,
 returning four values:
 a new map, a key, a value, and a boolean indicating
 whether the map was already empty."))
-(defgeneric pf:fold-left (interface map f seed)
+(defgeneric fold-left (<map> map f seed)
   (:documentation "Fold a map with a function,
 by repeatedly deconstructing it as by decons,
 yielding association k_1 v_1 .. k_n v_n, and computing
 (f (f ... (f (f seed k_1 v_1) k2 v_2) ... k_n-1 v_n-1) k_n v_n)"))
-(defgeneric pf:fold-right (interface map f seed)
+(defgeneric fold-right (<map> map f seed)
   (:documentation "Fold a map with a function,
 by repeatedly deconstructing it as by decons,
 yielding association k_1 v_1 .. k_n v_n, and computing
 (f k_1 v_1 (f k2 v_2 (f ... (f k_n-1 v_n-1 (f k_n v_n seed))...)))"))
-(defgeneric pf:for-each (interface map f)
+(defgeneric for-each (<map> map f)
   (:documentation "For every key value pair in map, (funcall f k v)"))
-(defgeneric pf:append (interface map1 map2)
-  (:documentation "Merge two maps, returning a merged map.
+(defgeneric join (<map> map1 map2)
+  (:documentation "Join two maps, returning a joined map.
 Mappings from MAP1 override those from MAP2."))
-(defgeneric pf:divide (interface map)
+(defgeneric divide (<map> map)
   (:documentation "Divide a map in two,
 returning two maps MAP1 and MAP2 that each have strictly
 fewer associations than MAP unless MAP is of size one or two."))
-(defgeneric pf:count (interface map)
-  (:documentation "Count the number of elements in a map"))
-(defgeneric pf:append/list (interface list)
-  (:documentation "Merge a list of maps,
-returning a merged map where mappings from
+(defgeneric size (<map> map)
+  (:documentation "Size the number of elements in a map"))
+(defgeneric join/list (<map> list)
+  (:documentation "Join a list of maps,
+returning a joined map where mappings from
 earlier mappings override those from latter mappings."))
-(defgeneric pf:divide/list (interface map)
+(defgeneric divide/list (<map> map)
   (:documentation "Divide a map in a list of several submaps and return that list,
-such that merging those maps with append/list
+such that merging those maps with join/list
 will return a map similar to the original one,
 that the returned list is empty iff the initial map is empty,
 that the returned list is of length one iff the initial map is a singleton,
 and that otherwise, each element of the list is non-empty."))
-(defgeneric pf:update (interface map key fun)
+(defgeneric update-key (<map> map key fun)
   (:documentation "Update the association of a map for a given key and return a new map,
 calling fun with the previous associated value and T if found, with NIL and NIL otherwise,
 where fun will return two values,
 the new value and a boolean,
-the association being removed if the boolean is NIL,
+the association being dropped if the boolean is NIL,
 otherwise a new association being setup with the new value."))
-(defgeneric pf:merge (interface fun map1 map2)
-  (:documentation "Merge two maps, returning a merged map.
+(defgeneric map/2 (<map> fun map1 map2)
+  (:documentation "Join two maps, returning a joined map.
 For each key K present in either MAP1 or MAP2,
 the function FUN is called with arguments K V1 F1 V2 F2 where
 V1 and F1 are the value and found flag for MAP1, and
@@ -85,74 +85,90 @@ V2 and F2 are the value and found flag for MAP2,
 and FUN returns value V and found flag F,
 that correspond the lookup for K in the result."))
 
-(defgeneric pf:convert (interface2 interface1 map1)
-  (:documentation "Convert a map from interface1 to interface2."))
+(defgeneric convert (<map>2 <map>1 map1)
+  (:documentation "Convert a map from one interface to another."))
 
 #|
 Instead of divide and divide/list and in the spirit of fold-left and fold-right,
 we could have a
-(defgeneric monoid-fold (i map m-null m-singleton m-append m-append/list))
+(defgeneric monoid-fold (i map m-null m-singleton m-join m-join/list))
 |#
 
 ;;; Simple cases for a lot of the above functions
-
-(defclass fmap-simple-empty () ())
-(defmethod pf:empty ((i fmap-simple-empty))
+(defclass map-simple-empty () ())
+(defmethod check-invariant ((i map-simple-empty) (m null))
+  m)
+(defmethod empty ((i map-simple-empty))
   '())
-(defmethod pf:empty-p ((i fmap-simple-empty) map)
+(defmethod empty-p ((i map-simple-empty) map)
   (null map))
 
-(defclass fmap-simple-decons () ())
-(defmethod pf:decons ((i fmap-simple-decons) map)
-  (multiple-value-bind (k v f) (pf:first-key-value i map)
+(defclass map-simple-decons () ())
+(defmethod decons ((i map-simple-decons) map)
+  (multiple-value-bind (k v f) (first-key-value i map)
     (if f
-        (values (pf:remove i map k) k v f)
+        (values (drop i map k) k v f)
         (values map nil nil nil))))
 
-(defclass fmap-simple-update () ())
-(defmethod pf:update ((i fmap-simple-update) map key fun)
-  (multiple-value-bind (value foundp) (pf:lookup i map key)
+(defclass map-simple-update-key () ())
+(defmethod update-key ((i map-simple-update-key) map key fun)
+  (multiple-value-bind (value foundp) (lookup i map key)
    (multiple-value-bind (new-value new-foundp) (funcall fun value foundp)
      (cond
        (new-foundp
-        (pf:insert i map key new-value))
+        (insert i map key new-value))
        (foundp
-        (pf:remove i map key))
+        (drop i map key))
        (t
         map)))))
 
-(defclass fmap-simple-append () ())
-(defmethod pf:append ((i fmap-simple-append) map1 map2)
-  (pf:fold-left i map1 (lambda (m k v) (pf:insert i m k v)) map2))
+(defclass map-simple-join () ())
+(defmethod join ((i map-simple-join) map1 map2)
+  (fold-left i map1 (lambda (m k v) (insert i m k v)) map2))
 
-(defclass fmap-simple-append/list () ())
-(defmethod pf:append/list ((i fmap-simple-append/list) maplist)
-  (reduce #'pf:append maplist :from-end t))
+(defclass map-simple-join/list () ())
+(defmethod join/list ((i map-simple-join/list) maplist)
+  (reduce #'join maplist :from-end t))
 
-(defclass fmap-simple-divide/list () ())
-(defmethod pf:divide/list ((i fmap-simple-divide/list) map)
+(defclass map-simple-divide/list () ())
+(defmethod divide/list ((i map-simple-divide/list) map)
   (cond
     ((null map) '())
     ((null (cdr map)) (list map))
-    (t (multiple-value-list (pf:divide map)))))
+    (t (multiple-value-list (divide map)))))
 
-(defclass fmap-simple-merge () ())
-(defmethod pf:merge ((i fmap-simple-merge) fun map1 map2)
-  (labels ((merge1 (a k v1)
+(defclass map-simple-map/2 () ())
+(defmethod map/2 ((i map-simple-join) fun map1 map2)
+  (labels ((join1 (a k v1)
              (let ((mm (car a))
                    (m2 (cdr a)))
-               (multiple-value-bind (v2 f2) (pf:lookup i m2 k)
+               (multiple-value-bind (v2 f2) (lookup i m2 k)
                  (multiple-value-bind (v f) (funcall fun k v1 t v2 f2)
-                   (let ((nmm (if f (pf:insert i mm k v) mm))
-                         (nm2 (if f2 (pf:remove i m2 k) m2)))
+                   (let ((nmm (if f (insert i mm k v) mm))
+                         (nm2 (if f2 (drop i m2 k) m2)))
                      (cons nmm nm2))))))
-           (merge2 (mm k v2)
+           (join2 (mm k v2)
              (multiple-value-bind (v f) (funcall fun k nil nil v2 t)
-               (if f (pf:insert i mm k v) mm))))
+               (if f (insert i mm k v) mm))))
     (destructuring-bind (mm . m2)
-        (pf:fold-left i map1 #'merge1 (cons (pf:empty i) map2))
-      (pf:fold-left i m2 #'merge2 mm))))
-
-(defclass fmap-simple-count () ())
-(defmethod pf:count ((i fmap-simple-count) map)
-  (pf:fold-left i map (lambda (x k v) (declare (ignore k v)) (1+ x)) 0))
+        (fold-left i map1 #'join1 (cons (empty i) map2))
+      (fold-left i m2 #'join2 mm))))
+
+(defclass map-simple-fold-right () ())
+(defmethod fold-right ((i map-simple-fold-right) map fun seed)
+  (funcall
+   (fold-left
+    i map
+    (lambda (f k v) (lambda (acc) (funcall f (funcall fun k v acc))))
+    #'identity
+   seed)))
+
+(defclass map-simple-size () ())
+(defmethod size ((i map-simple-size) map)
+  (fold-left i map (lambda (x k v) (declare (ignore k v)) (1+ x)) 0))
+
+(defmethod convert ((i2 <map>) (i1 <map>) map1)
+  (fold-right
+   i1 map1
+   (lambda (k v map2) (insert i2 map2 k v))
+   (empty i2)))
diff --git a/pure-trees.lisp b/pure-trees.lisp
index 70a7b51733a735e0253390f674c288530f56c1cc..df4b6a4e32709de34cfed9580f02093a5a1c204a 100644
--- a/pure-trees.lisp
+++ b/pure-trees.lisp
@@ -3,44 +3,48 @@
 
 #+xcvb (module (:depends-on ("pure-maps" "order")))
 
-(in-package :fare-utils)
+(in-package :pure)
 
-;;; Generic tree interface
-
-(defpackage :tree
-  (:use)
-  (:export
-   #:<tree> #:node #:find #:join #:leftmost #:rightmost))
+;;; Trees in general
 
+(defclass <tree> (<type>) ()
+  (:documentation "abstract interface for trees"))
 
-;;; Trees in general
+#|
+(defclass <node> (<type>) ()
+  (:documentation "abstract interface for nodes of trees"))
+(defgeneric node-interface (<tree>)
+  (:documentation "returns the interface for nodes of given tree interface"))
+(defgeneric key-interface (<interface>)
+  (:documentation "returns the interface for keys of given tree interface"))
+|#
 
-(defclass tree:<tree> () ())
-(defgeneric tree:node (i &key)
-  (:documentation "create a new node for a <tree> interface.
-Assumes that any ordering and balancing constraints are respected
+(defgeneric join-nodes (<tree> node1 node2)
+  (:documentation "join two nodes.
+Unlike join, which accepts arbitrary trees,
+join assumes that any ordering and balancing constraints are respected
 in the constituents, and that any ordering constraint is respected
 between them, re-balancing as needed."))
-(defgeneric tree:find (i tree key path)
+(defgeneric leftmost (<tree> tree)
+  (:documentation "key, value, foundp for leftmost node in TREE"))
+(defgeneric rightmost (<tree> tree)
+  (:documentation "key, value, foundp for rightmost node in TREE"))
+
+(defgeneric locate (<tree> tree key path)
   (:documentation "lookup a tree for a key, return a path to the proper node."))
-(defgeneric tree:join (i a b)
-  (:documentation "join two trees, assuming.
-Assumes that any ordering and balancing constraints are respected
-in the constituents, and that any ordering constraint is respected
-between them, re-balancing as needed."))
-(defgeneric tree:leftmost (i a)
-  (:documentation "key value and flag for leftmost node in a"))
-(defgeneric tree:rightmost (i a)
-  (:documentation "key value and flag for rightmost node in a"))
 
+(defgeneric node (<tree> &key)
+  (:documentation "make a node for a tree interface"))
 
 ;;; Vanilla Binary Tree
 
-(defclass pf:<binary-tree>
-    (tree:<tree> pf:<map> order:<order>
-     fmap-simple-empty fmap-simple-decons fmap-simple-update
-     fmap-simple-merge fmap-simple-append fmap-simple-append/list
-     fmap-simple-count)
+(defclass <binary-tree>
+    (<tree> <map>
+     order:<order> ;; TODO: delegate that to a key interface?
+     map-simple-empty ;; handles all the null cases so we don't have to.
+     map-simple-decons map-simple-update-key
+     map-simple-join map-simple-map/2 map-simple-join/list
+     map-simple-size)
   ()
   (:documentation "Keys in binary trees increase from left to right"))
 
@@ -64,139 +68,136 @@ between them, re-balancing as needed."))
     :initform nil
     :reader node-value)))
 
+(defclass box ()
+  ((datum :initarg :datum :reader datum)))
+
 (defclass binary-tree-node (binary-branch association-pair)
+  ;;; Or should we have a box instead of an association-pair ???
+  ;;; Or let the user just inherit from binary-branch,
+  ;;; and use a node-interface with make and update?
   ())
 
-(defmethod pf:check-invariant ((i pf:<binary-tree>) role node)
-  (etypecase node
-    (null
-     nil)
-    (binary-tree-node
-     (when (left node)
-       (pf:check-invariant i role (left node))
-       (assert (order:< i (tree:rightmost i (left node)) (node-key node))))
-     (when (right node)
-       (pf:check-invariant i role (right node))
-       (assert (order:< i (node-key node) (tree:leftmost i (right node)))))))
-  node)
-
-
-(defmethod tree:node ((i pf:<binary-tree>) &key left right key value)
+(defmethod check-invariant ((i <binary-tree>)
+                            (node binary-branch))
+  (when (left node)
+    (check-invariant i (left node))
+    (assert (order:< i (rightmost i (left node)) (node-key node))))
+  (when (right node)
+    (check-invariant i (right node))
+    (assert (order:< i (node-key node) (leftmost i (right node))))))
+
+;;(defmethod node ((i <tree>) &rest keys &key &allow-other-keys)
+;;  (apply #'make (node-interface i) keys))
+(defmethod node ((i <binary-tree>) &key left right key value)
   (make-instance 'binary-tree-node
                  :key key :value value :left left :right right))
 
-(defmethod tree:find ((i pf:<binary-tree>) node key path)
-  (if (null node) (values nil nil)
-      (ecase (order:compare i key (node-key node))
+;;(defmethod compare-key ((i <map>) key1 key2)
+;;  (compare (key-interface i) key1 key2))
+
+(defmethod locate ((i <binary-tree>) node key path)
+  (ecase (order:compare i key (node-key node)) ;; (compare-key i key (node-key node))
         (0 (values node path))
-        (-1 (tree:find i (left node) key (cons 'left path)))
-        (1 (tree:find i (right node) key (cons 'right path))))))
-(defmethod pf:lookup ((i pf:<binary-tree>) node key)
-  (if (null node) (values nil nil)
-      (ecase (order:compare i key (node-key node))
+        (-1 (locate i (left node) key (cons 'left path)))
+        (1 (locate i (right node) key (cons 'right path)))))
+(defmethod lookup ((i <binary-tree>) node key)
+  (if (null node)
+      (values nil nil)
+      (ecase (order:compare i key (node-key node)) ;; (compare-key i key (node-key node))
         (0 (values (node-value node) t))
-        (-1 (pf:lookup i (left node) key))
-        (1 (pf:lookup i (right node) key)))))
-(defmethod pf:insert ((i pf:<binary-tree>) node key value)
+        (-1 (lookup i (left node) key))
+        (1 (lookup i (right node) key)))))
+(defmethod insert ((i <binary-tree>) node key value)
   (if (null node)
-      (tree:node i :key key :value value)
+      (node i :key key :value value)
       (ecase (order:compare i key (node-key node))
-        (0 (tree:node i :key key :value value
-                      :left (left node) :right (right node)))
-        (-1 (tree:node i :key (node-key node) :value (node-value node)
-                       :left (pf:insert i (left node) key value) :right (right node)))
-        (1 (tree:node i :key (node-key node) :value (node-value node)
-                      :left (left node) :right (pf:insert i (right node) key value))))))
-(defmethod pf:remove ((i pf:<binary-tree>) node key)
+        (0 (node i :key key :value value ;; (update-node i node :key key :value value)
+                 :left (left node) :right (right node)))
+        (-1 (node i :key (node-key node) :value (node-value node)
+                  :left (insert i (left node) key value) :right (right node)))
+        (1 (node i :key (node-key node) :value (node-value node)
+                 :left (left node) :right (insert i (right node) key value))))))
+(defmethod drop ((i <binary-tree>) (node binary-branch) key)
   (if (null node)
       (values nil nil nil)
       (let ((k (node-key node))
             (v (node-value node)))
         (ecase (order:compare i key k)
           (0 (values
-              (tree:join i (left node) (right node))
+              (join-nodes i (left node) (right node))
               v t))
-          (-1 (multiple-value-bind (left value foundp) (pf:remove i (left node) key)
-                (values (tree:node i :key k :value v
-                                   :left left :right (right node))
-                        value foundp)))
-          (1 (multiple-value-bind (right value foundp) (pf:remove i (right node) k)
-               (values (tree:node i :key k :value v
-                                  :left (left node) :right right)
+          (-1 (multiple-value-bind (left value foundp) (drop i (left node) key)
+                (values (node i :key k :value v
+                              :left left :right (right node))
+                    value foundp)))
+          (1 (multiple-value-bind (right value foundp) (drop i (right node) k)
+               (values (node i :key k :value v
+                             :left (left node) :right right)
                        value foundp)))))))
-(defmethod pf:first-key-value ((i pf:<binary-tree>) map)
-  (if map
-      (values (node-key map) (node-value map) t)
-      (values nil nil nil)))
-(defmethod pf:fold-left ((i pf:<binary-tree>) node f seed)
+(defmethod first-key-value ((i <binary-tree>) map)
+  (if (null map)
+      (values nil nil nil)
+      (values (node-key map) (node-value map) t)))
+(defmethod fold-left ((i <binary-tree>) node f seed)
   (if (null node)
       seed
-      (pf:fold-left i (right node) f
+      (fold-left i (right node) f
                       (funcall f
-                               (pf:fold-left i (left node) f seed)
+                               (fold-left i (left node) f seed)
                                (node-key node) (node-value node)))))
-(defmethod pf:fold-right ((i pf:<binary-tree>) node f seed)
+(defmethod fold-right ((i <binary-tree>) node f seed)
   (if (null node)
       seed
-      (pf:fold-right i (left node) f
+      (fold-right i (left node) f
                        (funcall f
                                 (node-key node) (node-value node)
-                                (pf:fold-right i (right node) f seed)))))
-(defmethod pf:for-each ((i pf:<binary-tree>) node f)
+                                (fold-right i (right node) f seed)))))
+(defmethod for-each ((i <binary-tree>) node f)
   (when node
-    (pf:for-each i (left node) f)
+    (for-each i (left node) f)
     (funcall f (node-key node) (node-value node))
-    (pf:for-each i (right node) f))
+    (for-each i (right node) f))
   (values))
-(defmethod pf:divide ((i pf:<binary-tree>) node)
+(defmethod divide ((i <binary-tree>) node)
   (cond
     ((null node)
      (values nil nil))
     ((null (left node))
-     (values (tree:node i :key (node-key node) :value (node-value node))
+     (values (node i :key (node-key node) :value (node-value node))
              (right node)))
     (t
-     (values (left node) (pf:insert i (right node) (node-key node) (node-value node))))))
-(defmethod pf:divide/list ((i pf:<binary-tree>) node)
+     (values (left node) (insert i (right node) (node-key node) (node-value node))))))
+(defmethod divide/list ((i <binary-tree>) node)
   (if (null node) '()
-      (let* ((rlist (cons (tree:node i :key (node-key node) :value (node-value node))
+      (let* ((rlist (cons (node i :key (node-key node) :value (node-value node))
                           (if (null (right node)) '() (list (right node))))))
         (if (null (left node)) rlist (cons (left node) rlist)))))
 
 
-(defmethod tree:leftmost ((i pf:<binary-tree>) node)
-  (cond
-    ((null node)
-     (values nil nil nil))
-    ((null (left node))
-     (values (node-key node) (node-value node) t))
-    (t
-     (tree:leftmost i (left node)))))
-(defmethod tree:rightmost ((i pf:<binary-tree>) node)
+(defmethod leftmost ((i <binary-tree>) node)
   (cond
-    ((null node)
-     (values nil nil nil))
-    ((null (right node))
-     (values (node-key node) (node-value node) t))
-    (t
-     (tree:rightmost i (right node)))))
-
-(defmethod tree:join ((i pf:<binary-tree>) a b)
+    ((null node) nil)
+    ((null (left node)) (values (node-key node) (node-value node) t))
+    (t (leftmost i (left node)))))
+(defmethod rightmost ((i <binary-tree>) node)
   (cond
-    ((null a) b)
-    ((null b) a)
-    (t
-     (assert (order:< i (tree:rightmost a) (tree:leftmost b)))
-     (tree:node i :key (node-key a) :value (node-value a)
-                :left (left a)
-                :right (tree:node i :key (node-key b) :value (node-value b)
-                                  :left (tree:join i (right a) (left b))
-                                  :right (right b))))))
+    ((null node) nil)
+    ((null (right node)) (values (node-key node) (node-value node) t))
+    (t (rightmost i (right node)))))
 
+(defmethod join-nodes ((i map-simple-empty) (a null) b) b)
+(defmethod join-nodes ((i map-simple-empty) a (b null)) a)
+(defmethod join-nodes ((i <binary-tree>) a b)
+  (assert (order:< i (rightmost a) (leftmost b)))
+  (node i :key (node-key a) :value (node-value a)
+        :left (left a)
+        :right (node i :key (node-key b) :value (node-value b)
+                     :left (join i (right a) (left b))
+                     :right (right b))))
 
 ;;; pure AVL-tree
 
-(defclass pf:<avl-tree> (pf:<binary-tree>) ())
+(defclass <avl-tree> (<binary-tree>) ())
 
 (defclass avl-tree-node (binary-tree-node)
   ((height
@@ -215,14 +216,13 @@ between them, re-balancing as needed."))
   (- (node-height (right node))
      (node-height (left node))))
 
-(defmethod pf:check-invariant :before ((i pf:<avl-tree>) role node)
-  (when node
-    (assert (typep (node-height node)
-                   `(integer 1 ,most-positive-fixnum)))
-    (assert (= (node-height node)
-               (1+ (max (node-height (left node))
-                        (node-height (right node))))))
-    (assert (member (node-balance node) '(-1 0 1)))))
+(defmethod check-invariant :before ((i <avl-tree>) (node avl-tree-node))
+  (assert (typep (node-height node)
+                 `(integer 1 ,most-positive-fixnum)))
+  (assert (= (node-height node)
+             (1+ (max (node-height (left node))
+                      (node-height (right node))))))
+  (assert (member (node-balance node) '(-1 0 1))))
 
 #| Minimum number of nodes in a tree of height n (maximum is 2^n-1)
 (memo:define-memo-function f (n)
@@ -235,10 +235,10 @@ This ensures that even in the worst-case scenario,
 a balanced tree is logarithmically shallow.
 
 Exercise: prove that the in the above algorithms,
-tree:node is always called with branches that are of comparable height...
+node is always called with branches that are of comparable height...
 |#
 
-(defmethod tree:node ((i pf:<avl-tree>) &key left right key value)
+(defmethod node ((i <avl-tree>) &key left right key value)
   (flet ((mk (&key left right key value)
            (let ((lh (node-height left))
                  (rh (node-height right)))
@@ -288,7 +288,9 @@ tree:node is always called with branches that are of comparable height...
               :key (node-key right) :value (node-value right)
               :right (right right))))))))
 
-(defclass pf:<integer-map> (pf:<avl-tree> order:<numeric>) ())
-(defparameter pf:<integer-map>
-  (memo:memoized 'make-instance 'pf:<integer-map>))
-(defparameter pf:<im> pf:<integer-map>)
+
+;;; Common special case: when keys are numbers
+(defclass <integer-map> (<avl-tree> order:<numeric>) ())
+(defparameter <integer-map>
+  (memo:memoized 'make-instance '<integer-map>))
+(defparameter <im> <integer-map>)
diff --git a/pure.lisp b/pure.lisp
index 34300c534c97c8e64efad01d754d58469770c4e9..9d16c34018fc91ac2eb95a9fff5506a8f8f9ecc6 100644
--- a/pure.lisp
+++ b/pure.lisp
@@ -5,44 +5,70 @@
 
 (in-package :cl)
 
-(defpackage :pf
+(defpackage :pure
   (:nicknames #:pure-functional)
-  (:use)
+  (:use :cl :fare-utils)
   (:export
 
    ;;; General purpose gfs
    #:check-invariant
 
+   ;;; Trees
+   #:<tree>
+   #:node #:locate #:join
+   #:left #:right #:leftmost #:rightmost
+
    ;;; Functional Maps and Containers: classes
    #:<map> #:<alist>
    #:<binary-tree> #:<avl-tree>
    #:<integer-map> #:<im>
    #:<hash-table> #:<equal-hash-table> #:<ht> #:<equal-ht>
-   #:<fast-append-integer-map> #:<faim>
+   #:<fmim>
 
    ;;; Functional Maps and Containers: Generic Functions
    #:empty
    #:empty-p
    #:lookup
    #:insert
-   #:remove
+   #:drop
    #:first-key-value
    #:decons
    #:fold-left
    #:fold-right
    #:for-each
-   #:append
+   #:join
    #:divide
-   #:count
-   #:append/list
+   #:size
+   #:join/list
    #:divide/list
    #:update
-   #:merge
+   #:map/2
    #:convert))
 
-(defgeneric pf:check-invariant (interface role object)
+(in-package :pure)
+
+(defclass <interface> ()
+  ()
+  (:documentation "An interface, encapsulating an algorithm"))
+
+(defclass <type> (<interface>) ()
+  (:documentation "An interface encapsulating a particular type of objects"))
+
+(defgeneric make (<type> &key)
+  (:documentation "Given a <type>, create an object conforming to the interface
+based on provided initarg keywords, returning the object."))
+
+(defgeneric update (<type> object &key)
+  (:documentation "Update OBJECT by overriding some of its slots
+with those specified as initarg keywords, returning a new object."))
+
+(defgeneric check-invariant (<type> object)
   (:documentation "Check whether an OBJECT fulfills the invariant(s) required
 to play a given ROLE with respect to the given INTERFACE.
 Interface is an interface, role is a class or keyword,
 object is whatever makes sense.
 On success the OBJECT itself is returned. On failure an error is signalled."))
+
+(defmethod check-invariant :around (type object)
+  (call-next-method)
+  object)
diff --git a/test/functional-map.lisp b/test/functional-map.lisp
index e22dd58a504700e9f72eac2196e80263b4d7c893..115ee364d2736ad03305abe7d258926f6416e4b6 100644
--- a/test/functional-map.lisp
+++ b/test/functional-map.lisp
@@ -2,8 +2,8 @@
 
 (declaim (optimize (speed 1) (debug 3) (space 3)))
 
-(defparameter <im> pf:<im>)
-(defparameter <alist> pf:<alist>)
+(defparameter <im> <im>)
+(defparameter <alist> <alist>)
 
 (defun sort-alist (alist) (sort (copy-seq alist) #'< :key #'car))
 (defun shuffle-list (list)
@@ -27,25 +27,25 @@
 (defparameter *al-5* (remove-duplicates (append *al-2* *al-3*) :key #'car :from-end t))
 
 (defun alist-from (i map)
-  (pf:convert <alist> i map))
+  (convert <alist> i map))
 
 (defun from-alist (i map)
-  (check-invariant i :map (pf:convert i <alist> map)))
+  (check-invariant i (convert i <alist> map)))
 
 (defgeneric test-map (fmap-interface))
 
-(defmethod test-map ((i pf:<map>))
+(defmethod test-map ((i <map>))
   ;;; TODO: test each and every function in the API
-  (assert (null (alist-from i (pf:empty i))))
-  (assert (pf:empty-p i (from-alist i ())))
+  (assert (null (alist-from i (empty i))))
+  (assert (empty-p i (from-alist i ())))
   (assert (equal "12"
-                 (pf:lookup
+                 (lookup
                   i
                   (from-alist
                    i '((57 . "57") (10 . "10") (12 . "12")))
                   12)))
   (loop :for (k . v) :in *al-1* :with m = (from-alist i *al-1*) :do
-    (assert (eq v (pf:lookup i m k))))
+    (assert (eq v (lookup i m k))))
   (assert (equal-alist *alist-10-latin*
                        (alist-from i (from-alist i *alist-10-latin*))))
   (assert (equal-alist *alist-10-latin*
@@ -55,24 +55,23 @@
   (assert (equal-alist *al-5*
                        (alist-from
                         i (check-invariant
-                           i :map
-                           (pf:append i (from-alist i *al-2*)
-                                        (from-alist i *al-3*))))))
+                           i (join i (from-alist i *al-2*)
+                                   (from-alist i *al-3*))))))
   t)
 
-(defmethod test-map :after ((i pf:<integer-map>))
+(defmethod test-map :after ((i <integer-map>))
   (let* ((a1 (make-alist 1000 "~@R"))
          (a2 (shuffle-list a1))
-         (m1 (pf:convert i <alist> a1))
-         (m2 (pf:convert i <alist> a2)))
-    (check-invariant i :map m1)
-    (check-invariant i :map m2)
-    (assert (= 10 (fare-utils::node-height m1)))
-    (assert (<= 10 (fare-utils::node-height m2) 15))
-    (assert (= 1000 (pf:count i m1)))
-    (assert (= 1000 (pf:count i m2)))))
+         (m1 (convert i <alist> a1))
+         (m2 (convert i <alist> a2)))
+    (check-invariant i m1)
+    (check-invariant i m2)
+    (assert (= 10 (pure::node-height m1)))
+    (assert (<= 10 (pure::node-height m2) 15))
+    (assert (= 1000 (size i m1)))
+    (assert (= 1000 (size i m2)))))
 
-(test-map pf:<alist>)
-(test-map pf:<im>)
-(test-map pf:<ht>)
-(test-map pf:<faim>)
+(test-map <alist>)
+(test-map <im>)
+(test-map <hash-table>)
+(test-map <fmim>)
diff --git a/test/package.lisp b/test/package.lisp
index cbf1d1de81098f0e6bf320ca0b51a100aadf21b0..741a638c70c0b0ce19b3b1e0c5005251d5fed88c 100644
--- a/test/package.lisp
+++ b/test/package.lisp
@@ -1,2 +1,2 @@
 (defpackage :fare-utils-test
-  (:use :fare-utils :cl :hu.dwim.stefil))
+  (:use :fare-utils :pure :cl :hu.dwim.stefil))