anchor.diff:  - (find-hook 'foo-hook 'bar-class)
   - (find-hook 'foo-hook (make-instance 'bar-class))"
     (gethash (list name object) %hook-table))
  +
  +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  +;; Compile-time type checking for add-hook is useful in case `add-hook' is not
  +;; run when the user config is loaded.  Sadly Common Lisp does not seem to allow
  +;; to extract the type of a function so that it can be checked against what a
  +;; hook would allow.  We work around this issue with a macro:
  +;;
  +;; - Generates hook and handler subclasses.
  +;; - Generate a handler maker with provided function type declaim.
  +;; - Generate a `add-hook' defmethod against those 2 classes.
  +
  +(defmacro define-hook-type (name type)
  +  "Type must be something like
  + (function (string) (values integer t)).
  +A function with name make-handler-NAME will be created.
  +A class with name handler-NAME will be created."
  +  (let* ((name (string name))
  +         (function-name (intern (str:concat "MAKE-HANDLER-" name)))
  +         (handler-class-name (intern (str:concat "HANDLER-" name)))
  +         (hook-class-name (intern (str:concat "HOOK-" name))))
  +    `(progn
  +       (defclass ,handler-class-name (handler) ())
  +       (declaim (ftype (function (,type &key (:name symbol) (:place t) (:value t)))
  +                       ,function-name))
  +       (defun ,function-name (fn &key name place value)
  +         (make-handler fn :class-name ',handler-class-name
  +                          :name name
  +                          :handler-type ',type
  +                          :place place
  +                          :value value))
  +       (defclass ,hook-class-name (hook)
  +         ((handler-class :initform (find-class ',handler-class-name))))
  +       (defmethod add-hook ((hook ,hook-class-name) (handler ,handler-class-name) &key append)
  +         ,(format nil "Add HANDLER to HOOK.
  +HOOK msut be of type ~a
  +FN must be of type ~a."
  +                  hook-class-name
  +                  handler-class-name)
  +         (add-hook-internal hook handler :append append)))))
  +
  +(define-hook-type void (function ()))
  +(define-hook-type string->string (function (string) string))
  +(define-hook-type number->number (function (number) number))
  +(define-hook-type any (function (&rest t)))
  
positive.code: 
  ;; TODO: Because our hooks are typed, having both `run-hook` and
  ;; `run-hook-with-args' makes little sense.  Remove `run-hook-with-args'?
  (defmethod run-hook-with-args ((hook hook) &rest args)
    (apply (combination hook) hook args))
  
  ;; TODO: Implement the following methods? Isn't the `combination' slot more general?
  ;; (defmethod run-hook-with-args-until-failure ((hook hook) &rest args)
  
negative.code:          :accessor name
           :type symbol
           :initform nil
           :documentation "
  Name of the handler.
  If defaults to the function name if `fn' is a named function.
  This is useful so that the user can build handlers out of anonymous functions.")
     (description :initarg :description
                  :accessor description
                  :type string
                  :initform ""
                  :documentation "
  Description of the handler.  This is purely informative.")
     (fn :initarg :fn
         :accessor fn
         :type function
         :initform nil
         :documentation "
  The handler function.  It can be an anonymous function.")
     (handler-type :initarg :handler-type
                   :accessor handler-type
                   :type list
                   :initform nil
                   :documentation "The function type of FN.
  This is purely informative.")
     (place :initarg :place
            :accessor place
            :type (or symbol list)
            :initform nil
            :documentation "
  If the handler is meant to be a setter, PLACE describes what is set.
  PLACE can be a symbol or a pair (CLASS SLOT).
  This can be left empty if the handler is not a setter.")
     (value :initarg :value
            :accessor value
            :type t
            :initform nil
            :documentation "
  If the handler is meant to be a setter, VALUE can be used to describe what FN is
  going to set to PLACE.
  In particular, PLACE and VALUE can be used to compare handlers.
  This can be left empty if the handler is not a setter.")))
  
  ;; TODO: Don't export make-handler, so that user is forced to use the typed versions.
  (defun make-handler (fn &key (class-name 'handler) name handler-type place value)
    "NAME is a symbol."
    (setf name (or name (let ((fname (nth-value 2 (function-lambda-expression fn))))
                          (when (typep fname 'symbol)
                            fname))))
    (unless name
      (error "Can't make a handler without a name"))
    (make-instance class-name
                   :name name
                   :fn fn
                   :handler-type handler-type
                   :place place
                   :value value))
  
  (defmethod equals ((fn1 handler) (fn2 handler))
    "Return non-nil if FN1 and FN2 are equal."
  