(with-fast-alist name form) causes name to be a fast alist for the
   execution of form.
Major Section: HONS-AND-MEMOIZATION
Logically, with-fast-alist just returns form.
Under the hood, we cause alist to become a fast alist before executing
form.  If doing so caused us to introduce a new hash table, the hash table
is automatically freed after form completes.
More accurately, under the hood (with-fast-alist name form) essentially
expands to something like:
 (if (already-fast-alist-p name)
     form
   (let ((<temp> (make-fast-alist name)))
     (prog1 form
            (fast-alist-free <temp>))))
Practically speaking, with-fast-alist is frequently a better choice then
just using make-fast-alist, and is particularly useful for writing
functions that can take either fast or slow alists as arguments.  That is,
consider the difference between:
 (defun bad (alist ...)
   (let* ((fast-alist (make-fast-alist alist))
          (answer     (expensive-computation fast-alist ...)))
    (prog2$ (fast-alist-free fast-alist)
            answer)))
 (defun good (alist ...)
    (with-fast-alist alist
      (expensive-computation alist ...)))
Either approach is fine if the caller provides a slow alist.  But if the
input alist is already fast, bad will (perhaps unexpectedly) free it!
On the other hand, good is able to take advantage of an already-fast
argument and will not cause it to be inadvertently freed.
See also the macro with-fast-alists defined in the community book
"books/centaur/misc/hons-extra.lisp", which allows you to call
with-fast-alist on several alists simultaneously.
The community book "books/centaur/misc/hons-extra.lisp" extends the
b* macro (defined in the community book "books/tools/bstar.lisp")
with the with-fast pattern binder.  That is, after executing
(include-book "centaur/misc/hons-extra.lisp" :dir :system) you may write
something like this:
 (b* (...
      ((with-fast a b c ...))
      ...)
   ...)
which causes a, b, and c to become fast alists until the completion
of the b* form.
Note that with-fast-alist will cause logically tail-recursive functions not
to execute tail-recursively if its cleanup phase happens after the
tail-recursive call returns.
 
 