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