Major Section: STOBJ
See stobj for an introduction to single-threaded objects.
Example Form:
(with-local-stobj
 st
 (mv-let (result st)
         (compute-with-st x st)
         result))
With-local-stobj can be thought of as a macro, where the example
form above expands as follows.
(mv-let (result st)
        (let ((st (create-st)))
          (compute-with-st x st))
        (declare (ignore st))
        result)
However, ACL2 expects you to use with-local-stobj, not its
expansion.  More precisely, stobj creator functions are not allowed
except (implicitly) via with-local-stobj and in logic-only
situations (like theorems and hints).  Moreover, neither
with-local-stobj nor its expansions are legal when typed directly at
the top-level loop.  See top-level for a way to use with-local-stobj
in the top-level loop.
General Forms: (with-local-stobj stobj-name mv-let-form) (with-local-stobj stobj-name mv-let-form creator-name)where
stobj-name is the name of a stobj, mv-let-form is a call
of mv-let, and if creator-name is supplied then it should be the
name of the creator function for stobj-name; see defstobj.  For the
example form above, its expansion would use creator-name, if supplied, in
place of create-st.  Note that stobj-name must not be state
(the ACL2 state), except in special situations probably of interest only to
system developers; see with-local-state.With-local-stobj can be useful when a stobj is used to memoize
intermediate results during a computation, yet it is desired not to
make the stobj a formal parameter for the function and its
callers.
ACL2 can reason about these ``local stobjs,'' and in particular
about stobj creator functions.  For technical reasons, ACL2 will not
allow you to enable the :EXECUTABLE-COUNTERPART rune of a stobj
creator function.
Finally, here is a small example concocted in order to illustrate that
with-local-stobj calls can be nested.
(defstobj st fld1)
(defun foo ()
  (with-local-stobj
   st ; Let us call this the ``outer binding of st''.
   (mv-let (val10 val20 st)
     (let ((st (update-fld1 10 st)))
       ;; At this point the outer binding of st has fld1 = 10.
       (let ((result (with-local-stobj
                      st ; Let us call this the ``inner binding of st''.
                      (mv-let (val st)
                        (let ((st (update-fld1 20 st)))
                          ;; Now fld1 = 20 for the inner binding of st.
                          (mv (fld1 st) st))
                        val))))
         ;; So result has been bound to 20 above, but here we are once again
         ;; looking at the outer binding of st, where fld1 is still 10.
         (mv (fld1 st) result st)))
     (mv val10 val20))))
(thm (equal (foo) (mv 10 20))) ; succeeds
 
 