(with-fast-alist name form) causes name to be a fast alist for the execution of form.

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)
   (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)

 (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.