PROGN_bang_.html -- ACL2 Version 6.3

## PROGN!

evaluate some forms, not necessarily events

    Major Section:  EVENTS

WARNING! This event is intended for advanced users who, in essence, want to build extensions of ACL2. See see defttag, in particular, the ``WARNING'' there, and see the warning about stobjs at the end of this documentation topic.

`Progn!` can be used like `progn`, even in books. But unlike `progn`, `progn!` does not require its constituent forms to be events (see embedded-event-form), except that the first form cannot be a symbol unless it is `:state-global-bindings` (advanced feature, described below). However, see make-event for a ``Restriction to the Top Level'' that still applies under a call of `progn!`.

Because `progn!` allows non-events, it differs from `progn` in another important respect: `progn!` is illegal unless there is an active ttag; see defttag.

See community book `books/hacking/hacker.lisp` for two macros, `with-raw-mode` and `with-redef-allowed`, each defined in terms of `progn!`, that allow arbitrary forms in contexts that would normally require legal embedded event forms.

Given a form `(progn! form1 form2 ... formk)`, ACL2 will evaluate each `formi` in turn (for i from 1 to k). If a form returns more than one value (see mv) where the first value returned is not `nil`, then no later form will be evaluated and the result returned by the `progn!` call will be `(mv erp val state)` for some non-`nil` value `erp`, signifying an error (see ld-error-triples). Otherwise the evaluation is considered to have succeeded, and will continue with later forms. The value returned by a call of `progn!` with no such error is of the form `(mv nil v state)`, where `v` depends on the last form as follows. If the last form evaluates to a single value, then `v` is that value, except if the value is a stobj, say `ST`, then `v` is the symbol `REPLACED-ST`. Otherwise the last form evaluates to some `(mv nil x ...)`, and `v` is `x` unless after the final form's evaluation we are in raw-mode (see set-raw-mode), in which case the `progn!` call returns `nil` (so that ACL2 can at least print the result -- imagine Lisp returning a pathname object from a `load` call, for example).

The normal undoing mechanism does not generally apply to forms within a `progn!` that are not legal ACL2 events (see embedded-event-form). In particular, note that a non-`local` call of `progn!` in an `encapsulate` event will generally be evaluated twice: once on each pass. This fact is worth keeping in mind if you are using `progn!` to change the state of the system; ask yourself if it is acceptable to apply that state-changing operation more than once.

Please note that `progn!` may differ from `progn` in the following sense: definitions within a call of `progn!` might not be compiled. For example, consider the following book.

    (in-package "ACL2")
    (defttag :test)
    (progn  (defun f1 (x) x))
    (progn! (defun f2 (x) x))

If the underlying Lisp is GCL 2.6.7, then after including this certified book (where the default certification took place, creating a compiled file), then `f1` is a compiled function but `f2` is not. For other Lisps supported by ACL2, both `f1` and `f2` are compiled, though we are not sure that every function under every call of `progn!` would similarly be compiled.

We now describe, for system hackers only, a sophisticated extension of `progn!` not mentioned above: support for keyword argument `:state-global-bindings`. If the first argument of `progn!` is this keyword, then the second argument is treated as a list of bindings as expected by ACl2 system function `state-global-let*`. Thus, in the ACL2 loop,

    (progn! :state-global-bindings bindings form1 form2 ... formk)

is treated as follows:

    (progn! (state-global-let* bindings (progn! form1 form2 ... formk)))

However, in raw Lisp the former is just:

    (progn form1 form2 ... formk)

Thus, one should use the `:state-global-bindings` argument with care, since the behavior in the ACL2 loop can differ from that in Common Lisp. The intention is that one bind only state global variables that are relevant to evaluation of the forms within the ACL2 loop and are harmlessly ignored for evaluation of those forms in raw Lisp. Here is a typical sort of example, as state global `ld-redefinition-action` is not relevant to the evaluation of `defun` in raw Lisp.

    (progn! (remove-untouchable 'ld-redefinition-action nil)
            (progn! :state-global-bindings
                    ((ld-redefinition-action '(:doit . :overwrite)))
                    (defun foo (x)
                      (cons x x)))
            (push-untouchable 'ld-redefinition-action nil))

Finally, we point out a pitfall of `progn!` related to stobjs. The following book can cause a hard Lisp error, depending on the host Common Lisp, when certified with a non-`nil` value for `compile-flg` (see certify-book).

    (in-package "ACL2")
    (defstobj st fld)
    (defttag :my-ttag)
    (progn! (update-fld 3 st))

The problem is that the stobj variable `st` is not known to raw Lisp. The compilation problem disappears if the last form above is replaced with the following two forms.

    (include-book "hacking/hacker" :dir :system)
    (with-raw-mode (update-fld 3 *the-live-st*))