anchor.diff:           (setf (entries merge) (fset:map-union (entries keymap2) (entries keymap1)))
            (apply #'compose merge (rest (rest keymaps))))))))
   
  +(declaim (ftype (function (symbol keymap) (types:proper-list string)) symbol-keys*))
   (defun symbol-keys* (symbol keymap)
     "Return a the list of `keyspec's bound to SYMBOL in KEYMAP.
   The list is sorted alphabetically to ensure reproducible results."
  
positive.code:     (reduce #'fset:map-union
              (mapcar #'keymap->map* keymaps))))
  
  (defun keymap-with-parents->map (keymap)
    "List bindings in KEYMAP and all its parents.
  See `keymap->map'."
  
negative.code:   "Return a keyspecs"
    (coerce (str:join " " (mapcar #'key->keyspec keys)) 'keyspecs-type))
  
  (declaim (ftype (function (keymap &optional (types:proper-list keymap)) fset:map) keymap->map*))
  (defun keymap->map* (keymap &optional visited) ; TODO: Return a regular hash-table instead?
    "Return a `fset:map' of (KEYSPEC SYM) from KEYMAP."
    (coerce
     (fset:reduce
      (lambda (result key sym)
        (let ((keyspec (key->keyspec key)))
          (if (keymap-p sym)
              (cond
                ((find sym visited)
                 (warn "Cycle detected in keymap ~a" keymap)
                 result)
                (t
                 (fset:map-union result
                                 (fset:image (lambda (subkey subsym)
                                               (values (format nil "~a ~a" keyspec subkey)
                                                       subsym))
                                             (keymap->map* sym (cons sym visited))))))
              (fset:with result keyspec sym))))
      (entries keymap)
      :initial-value (fset:empty-map))
     'fset:map))
  
  (declaim (ftype (function (&rest keymap) fset:map) keymap->map))
  (defun keymap->map (&rest keymaps)
    "Return a `fset:map' of (KEYSPEC SYM) from KEYMAP.
  Parent bindings are not listed; see `keymap-with-parents->map' instead.
  