MAKE-EVENT.html -- ACL2 Version 6.3

## MAKE-EVENT

evaluate (expand) a given form and then evaluate the result

    Major Section:  EVENTS

`Make-event` is a utility for generating events. It provides a capability not offered by Lisp macros (see defmacro), as it allows access to the ACL2 `state` and logical world. In essence, the expression `(make-event form)` replaces itself with the result of evaluating `form`, say, `ev`, as though one had submitted `ev` instead of the `make-event` call. For example, `(make-event (quote (defun f (x) x)))` is equivalent to the event `(defun f (x) x)`.

We break this documentation into the following sections.

Introduction
Detailed Documentation
Error Reporting
Restriction to Event Contexts
Examples Illustrating How to Access State
Advanced Expansion Control

We begin with an informal introduction, which focuses on examples and introduces the key notion of ``expansion phase''.

Introduction

`Make-event` is particularly useful for those who program using the ACL2 `state`; see programming-with-state. That is because the evaluation of `form` may read and even modify the ACL2 `state`.

Suppose for example that we want to define a constant `*world-length*`, that is the length of the current ACL2 world. A `make-event` form can accomplish this task, as follows.

      ACL2 !>(length (w state))
      98883
      ACL2 !>(make-event
              (list 'defconst '*world-length* (length (w state))))

      Summary
      Form:  ( DEFCONST *WORLD-LENGTH* ...)
      Rules: NIL
      Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)

      Summary
      Form:  ( MAKE-EVENT (LIST ...))
      Rules: NIL
      Time:  0.01 seconds (prove: 0.00, print: 0.00, other: 0.01)
       *WORLD-LENGTH*
      ACL2 !>*world-length*
      98883
      ACL2 !>(length (w state))
      98890
      ACL2 !>

How did this work? First, evaluation of the form `(list 'defconst '*world-length* (length (w state)))` returned the event form `(defconst *world-length* 98883)`. Then that event form was automatically submitted to ACL2. Of course, that changed the ACL2 logical world, which is why the final value of `(length (w state))` is greater than its initial value.

The example above illustrates how the evaluation of a `make-event` call takes place in two phases. The first phase evaluates the argument of the call, in this case `(list 'defconst '*world-length* (length (w state)))`, to compute an event form, in this case `(defconst *world-length* 98883)`. We call this evaluation the ``expansion'' phase. Then the resulting event form is evaluated, which in this case defines the constant `*world-length*`.

Now suppose we would like to introduce such a `defconst` form any time we like. It is common practice to define macros to automate such tasks. Now we might be tempted simply to make the following definition.

    ; WRONG!
    (defmacro define-world-length-constant (name state)
      (list 'defconst name (length (w state))))

But ACL2 rejects such a definition, because a macro cannot take the ACL2 state as a parameter; instead, the formal parameter to this macro named `"STATE"` merely represents an ordinary object. You can try to experiment with other such direct methods to define such a macro, but they won't work.

Instead, however, you can use the approach illustrated by the `make-event` example above to define the desired macro, as follows.

    (defmacro define-world-length-constant (name)
      `(make-event (list 'defconst ',name (length (w state)))))

Here are example uses of this macro.

      ACL2 !>(define-world-length-constant *foo*)

      Summary
      Form:  ( DEFCONST *FOO* ...)
      Rules: NIL
      Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)

      Summary
      Form:  ( MAKE-EVENT (LIST ...))
      Rules: NIL
      Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)
       *FOO*
      ACL2 !>*foo*
      98891
      ACL2 !>:pe *foo*
                2:x(DEFINE-WORLD-LENGTH-CONSTANT *FOO*)

      >             (DEFCONST *FOO* 98891)
      ACL2 !>(length (w state))
      98897
      ACL2 !>(define-world-length-constant *bar*)

      Summary
      Form:  ( DEFCONST *BAR* ...)
      Rules: NIL
      Time:  0.00 seconds (prove: 0.00, print: 0.00, other: 0.00)

      Summary
      Form:  ( MAKE-EVENT (LIST ...))
      Rules: NIL
      Time:  0.01 seconds (prove: 0.00, print: 0.00, other: 0.01)
       *BAR*
      ACL2 !>*bar*
      98897
      ACL2 !>:pe *bar*
                3:x(DEFINE-WORLD-LENGTH-CONSTANT *BAR*)

      >             (DEFCONST *BAR* 98897)
      ACL2 !>(length (w state))
      98903
      ACL2 !>

Finally, we note that the expansion phase can be used for computation that has side effects, generally by modifying state. Here is a modification of the above example that does not change the world at all, but instead saves the length of the world in a state global.

    (make-event
     (pprogn (f-put-global 'my-world-length (length (w state)) state)
             (value '(value-triple nil))))

Notice that this time, the value returned by the expansion phase is not an event form, but rather, is an error triple (see error-triples) whose value component is an event form, namely, the event form `(value-triple nil)`. Evaluation of that event form does not change the ACL2 world (see value-triple). Thus, the sole purpose of the `make-event` call above is to change the state by associating the length of the current logical world with the state global named `'my-world-length`. After evaluating this form, `(@ my-world-length)` provides the length of the ACL2 world, as illustrated by the following transcript.

      ACL2 !>:pbt 0
                0:x(EXIT-BOOT-STRAP-MODE)
      ACL2 !>(length (w state))
      98883
      ACL2 !>(make-event
              (pprogn (f-put-global 'my-world-length (length (w state)) state)
                      (value '(value-triple nil))))

      Summary
      Form:  ( MAKE-EVENT (PPROGN ...))
      Rules: NIL
      Time:  0.01 seconds (prove: 0.00, print: 0.00, other: 0.01)
       NIL
      ACL2 !>(length (w state))
      98883
      ACL2 !>:pbt 0
                0:x(EXIT-BOOT-STRAP-MODE)
      ACL2 !>

When `make-event` is invoked by a book, it is expanded during book certification but not, by default, when the book is included. So for the example `(define-world-length-constant *foo*)` given above, if that form is in a book, then the value of `*foo*` will be the length of the world at the time this form was invoked during book certification, regardless of world length at `include-book` time. (The expansion is recorded in the book's certificate, and re-used.) To overcome this default, you can specified keyword value `:CHECK-EXPANSION t`. This will cause an error if the expansion is different, but it can be useful for side effects. For example, if you insert the following form in a book, then the length of the world will be printed when the form is encountered, whether during `certify-book` or during `include-book`.

    (make-event
     (pprogn (fms "Length of current world: ~x0~|"
                  (list (cons #\0 (length (w state))))
                  *standard-co* state nil)
             (value '(value-triple nil)))
     :check-expansion t)

## Some Related Topics

- ### MAKE-EVENT-DETAILS -- details on `make-event` expansion

Detailed Documentation

    Examples:

    ; Trivial example: evaluate (quote (defun foo (x) x)) to obtain
    ; (defun foo (x) x), which is then evaluated.
    (make-event (quote (defun foo (x) x)))

    ; Evaluate (generate-form state) to obtain (mv nil val state), and
    ; then evaluate val.  (Generate-form is not specified here, but
    ; imagine for example that it explores the state and then generates
    ; some desired definition or theorem.)
    (make-event (generate-form state))

    ; As above, but make sure that if this form is in a book, then when
    ; we include the book, the evaluation of (generate-form state)
    ; should return the same value as it did when the book was
    ; certified.
    (make-event (generate-form state)
                :CHECK-EXPANSION t)

    ; As above (where the :CHECK-EXPANSION value can be included or
    ; not), where if there is an error during expansion, then the error
    ; message will explain that expansion was on behalf of the indicated
    ; object, typically specified as the first argument.
    (make-event (generate-form state)
                :ON-BEHALF-OF (generate-form state))

    General Form:
    (make-event form :CHECK-EXPANSION chk :ON-BEHALF-OF obj :EXPANSION? form)

where `chk` is `nil` (the default), `t`, or the intended ``expansion result'' from the evaluation of `form` (as explained below); and if supplied, `obj` is an arbitrary ACL2 object, used only in reporting errors in expansion, i.e., in the evaluation of form. The `:EXPANSION?` keyword is discussed in the final section, on Advanced Expansion Control.

We strongly recommend that you browse some `.lisp` files in the community books directory `books/make-event/`. You may even find it helpful, in order to understand `make-event`, to do so before continuing to read this documentation. You may also find it useful to browse community book `books/misc/eval.lisp`, which contains definitions of macros `must-succeed` and `must-fail` that are useful for testing and are used in many books in the `books/make-event/` directory, especially `eval-tests.lisp`. Another example, `books/make-event/defrule.lisp`, shows how to use macros whose calls expand to `make-event` forms, which in turn can generate events. For more examples, see file `books/make-event/Readme.lsp`. Other than the examples, the explanations here should suffice for most users. If you want explanations of subtler details, see make-event-details.

Note that `make-event` may only be used at the ``top level'' or where an event is expected. See the section ``Restriction to Event Contexts'', below.

`Make-event` is related to Lisp macroexpansion in the sense that its argument is evaluated to obtain an expansion result, which is evaluated again. Let us elaborate on each of these notions in turn: ``is evaluated,'' ``expansion result'', and ``evaluated again.'' The final section, on Advanced Expansion Control, will generalize these processes in a way that we ignore for now.

> ``is evaluated'' -- The argument can be any expression, which is evaluated as would be any expression submitted to ACL2's top level loop. Thus, `state` and user-defined `stobj`s may appear in the form supplied to `make-event`. Henceforth, we will refer to this evaluation as ``expansion.'' Expansion is actually done in a way that restores ACL2's built-in `state` global variables, including the logical world, to their pre-expansion values (with a few exceptions -- see make-event-details -- and where we note that changes to user-defined `state` global variables (see assign) are preserved). So, for example, events might be evaluated during expansion, but they will disappear from the logical world after expansion returns its result. Moreover, proofs are enabled by default at the start of expansion (see ld-skip-proofsp) if keyword `:CHECK-EXPANSION` is supplied and has a non-`nil` value.

> ``expansion result'' -- The above expansion may result in an ordinary (non-`state`, non-`stobj`) value, which we call the ``expansion result.'' Or, expansion may result in a multiple value of the form `(mv erp val state)`, or, more generally, `(mv erp val state stobj-1 ... stobj-k)` where each `stobj-i` is a stobj; then the expansion result is `val` unless `erp` is not `nil`, in which case there is no expansion result, and the original `make-event` evaluates to a soft error. In either case (single or multiple value), either `val` is an embedded event form (see embedded-event-form), or else the original `make-event` evaluates to a soft error, printed as described under ``Error Reporting'' below.

> ``evaluated again'' -- the expansion result is evaluated in place of the original `make-event`.

The expansion process can invoke subsidiary calls of `make-event`, and the expansion result can (perhaps after macroexpansion) be a call of `make-event`. It can be useful to track all these `make-event` calls. The state global variable `make-event-debug` may be set to a non-`nil` value, for example `(assign make-event-debug t)`, in order to see a trace of the expansion process, where a level is displayed (as in ```3>`'') to indicate the depth of subsidiary expansions.

Expansion of a `make-event` call will yield an event that replaces the original `make-event` call. In particular, if you put a `make-event` form in a book, then in essence it is replaced by its expansion result, created during the proof pass of the `certify-book` process. We now elaborate on this idea of keeping the original expansion.

A `make-event` call generates a ```make-event` replacement'' that may be stored by the system. In the simplest case, this replacement is the expansion result. When a book is certified, these replacements are stored in a book's certificate (technically, in the `:EXPANSION-ALIST` field). Thus, although the book is not textually altered during certification, one may imagine a ``book expansion'' corresponding to the original book, in which events are substituted by replacements that were generated during the proof phase of certification. A subsequent `include-book` will then include the book expansion corresponding to the indicated book. When a book is compiled during `certify-book`, it is actually the corresponding book expansion, stored as a temporary file, that is compiled instead. That temporary file is deleted after compilation unless one first evaluates the form `(assign keep-tmp-files t)`. Note however that all of the original forms must still be legal events; see embedded-event-form. So for example, if the first event in a book is `(local (defmacro my-id (x) x))`, and is followed by `(my-id (make-event ...))`, the final ```include-book`'' pass of `certify-book` will fail because `my-id` is not defined when the `my-id` call is encountered.

A `make-event` replacement might not be the expansion when either of the keyword arguments `:CHECK-EXPANSION` or `:EXPANSION?` is supplied. We deal with the latter in the final section, on Advanced Expansion Control. If `:CHECK-EXPANSION t` is supplied and the expansion is `exp`, then the replacement is obtained from the original `make-event` call, by substituting `exp` for `t` as the value of keyword `:CHECK-EXPANSION`. Such a `make-event` call -- during the second pass of an `encapsulate` or during event processing on behalf of `include-book` -- will do the expansion again and check that the expansion result is equal to the original expansion result, `exp`. In the unusual case that you know the expected expansion result, `res`, you can specify `:CHECK-EXPANSION res` in the first place, so that the check is also done during the initial evaluation of the `make-event` form. IMPORTANT BUT OBSCURE DETAIL: That expansion check is only done when processing events, not during a preliminary load of a book's compiled file. The following paragraph elaborates.

(Here are details on the point made just above, for those who use the `:CHECK-EXPANSION` argument to perform side-effects on the state. When you include a book, ACL2 generally loads a compiled file before processing the events in the book; see book-compiled-file. While it is true that a non-`nil` `:CHECK-EXPANSION` argument causes `include-book` to perform expansion of the `make-event` form during event processing it does not perform expansion when the compiled file (or expansion file; again, see book-compiled-file) is loaded.)

ACL2 performs the following space-saving optimization: when the expansion result is a `local` event, then the `make-event` replacement is `(local (value-triple :ELIDED))`.

The notion of ``expansion'' and ``replacement'' extend to the case that a call of `make-event` is found in the course of macroexpansion. The following example illustrates this point.

    (encapsulate
     ()
     (defmacro my-mac ()
       '(make-event '(defun foo (x) x)))
     (my-mac))
    :pe :here

The above call of `pe` shows that the form `(my-mac)` has a `make-event` expansion (and replacement) of `(DEFUN FOO (X) X)`:

    (ENCAPSULATE NIL
                 (DEFMACRO MY-MAC
                           NIL
                           '(MAKE-EVENT '(DEFUN FOO (X) X)))
                 (RECORD-EXPANSION (MY-MAC)
                                   (DEFUN FOO (X) X)))

Error Reporting

Suppose that expansion produces a soft error as described above. That is, suppose that the argument of a `make-event` call evaluates to a multiple value `(mv erp val state ...)` where `erp` is not `nil`. If `erp` is a string, then that string is printed in the error message. If `erp` is a `cons` pair whose `car` is a string, then the error prints `"~@0"` with `#\0` bound to that `cons` pair; see fmt. Any other non-`nil` value of `erp` causes a generic error message to be printed.

Restriction to Event Contexts

A `make-event` call must occur either at the top level, or during `make-event` expansion, or as an argument of an event constructor. We explain in more detail below. This restriction is imposed to enable ACL2 to track expansions produced by `make-event`.

The following examples illustrate this restriction.

    ; Legal:
    (progn (with-output
            :on summary
            (make-event '(defun foo (x) x))))

    ; Illegal:
    (mv-let (erp val state)
            (make-event '(defun foo (x) x))
            (mv erp val state))

More precisely: a `make-event` call that is not itself evaluated during `make-event` expansion is subject to the following requirement. After macroexpansion has taken place, such a `make-event` call must be in an ``event context'', defined recursively as follows. (All but the first two cases below correspond to similar cases for constructing events; see embedded-event-form.)

> o A form submitted at the top level, or more generally, supplied to a call of `ld`, is in an event context.

> o A form occurring at the top level of a book is in an event context.

> o If `(``LOCAL` `x1)` is in an event context, then so is `x1`.

> o If `(``SKIP-PROOFS` `x1)` is in an event context, then so is `x1`.

> o If `(``MAKE-EVENT` `x ...)` is in an event context and its expansion `x1` is an embedded event form, then `x1` is in an event context.

> o If `(``WITH-OUTPUT``... x1)`, `(``WITH-PROVER-STEP-LIMIT``... x1 ...)`, or `(``WITH-PROVER-TIME-LIMIT``... x1)` is in an event context, then so is `x1`.

> o For any call of `PROGN` or `PROGN!`, each of its arguments is in an event context.

> o For any call of `ENCAPSULATE`, each of its arguments except the first (the signature list) is in an event context.

> o If `(RECORD-EXPANSION x1 x2)` is in an event context, then `x1` and `x2` are in event contexts. Note: `record-expansion` is intended for use only by the implementation, which imposes the additional restriction that `x1` and its subsidiary `make-event` calls (if any) must specify a `:CHECK-EXPANSION` argument that is a consp.

Low-level remark, for system implementors. There is the one exception to the above restriction: a single `state-global-let*` form immediately under a `progn!` call. For example:

    (progn! (state-global-let* <bindings> (make-event ...)))

However, the following form may be preferable (see progn!):

    (progn! :STATE-GLOBAL-BINDINGS <bindings> (make-event ...))

Also see remove-untouchable for an interesting use of this exception.

Examples Illustrating How to Access State

You can modify the ACL2 state by doing your state-changing computation during the expansion phase, before expansion returns the event that is submitted. Here are some examples.

First consider the following. Notice that expansion modifies state global `my-global` during `make-event` expansion, and then expansion returns a `defun` event to be evaluated.

    (make-event
      (er-progn (assign my-global (length (w state)))
                (value '(defun foo (x) (cons x x)))))

Then we get:

      ACL2 !>(@ my-global)
      72271
      ACL2 !>:pe foo
       L        1:x(MAKE-EVENT (ER-PROGN # #))

      >L            (DEFUN FOO (X) (CONS X X))
      ACL2 !>

Here's a slightly fancier example, where the computation affects the `defun`. In a new session, execute:

    (make-event
      (er-progn (assign my-global (length (w state)))
                (value `(defun foo (x) (cons x ,(@ my-global))))))

Then:

      ACL2 !>(@ my-global)
      72271
      ACL2 !>:pe foo
       L        1:x(MAKE-EVENT (ER-PROGN # #))

      >L            (DEFUN FOO (X) (CONS X 72271))
      ACL2 !>

Note that ACL2 table events may avoid the need to use state globals. For example, instead of the example above, consider this example in a new session.

    (make-event
      (let ((world-len (length (w state))))
        `(progn (table my-table :STORED-WORLD-LENGTH ,world-len)
                (defun foo (x) (cons x ,world-len)))))

Then:

      ACL2 !>(table my-table)
       ((:STORED-WORLD-LENGTH . 72271))
      ACL2 !>:pe foo
                1:x(MAKE-EVENT (LET # #))

      >L            (DEFUN FOO (X) (CONS X 72271))
      ACL2 !>

By the way, most built-in state globals revert after expansion. But your own global (like `my-global` above) can be set during expansion, and the new value will persist.

Advanced Expansion Control

We conclude this documentation section by discussing three kinds of additional control over `make-event` expansion. These are all illustrated in community book `books/make-event/make-event-keywords-or-exp.lisp`. The discussion below is split into the following three parts.

(1) The value produced by expansion may have the form `(:DO-PROOFS exp)`, which specifies `exp` as the expansion result, to be evaluated without skipping proofs even when including a book.

(2) The value produced by expansion may have the form `(:OR exp-1 ... exp-k)`, which specifies that the first form `exp-i` to evaluate without error is the expansion result.

(3) The keyword argument `:EXPANSION?` can serve to eliminate the storing of `make-event` replacements, as described above for the ``book expansion'' of a book.

We now elaborate on each of these.

(1) `:DO-PROOFS` ``call'' produced by expansion.

We have discussed the expansion result produced by the expansion phase of evaluating a `make-event` call. However, if the expansion phase produces an expression of the form `(:DO-PROOFS exp)`, then the expansion result is actually `exp`. The `:DO-PROOFS` wrapper indicates that even if proofs are currently being skipped (see ld-skip-proofsp), then evaluation of `exp` should take place with proofs not skipped. For example, proofs will be performed when evaluating the `make-event` expansion, namely the indicated `defthm` event, in the following example.

    (set-ld-skip-proofsp t state)
    (make-event '(:DO-PROOFS
                  (defthm app-assoc (equal
                                     (append (append x y) z)
                                     (append x y z)))))

Note that such use of `:DO-PROOFS` causes proofs to be performed when evaluating the expansion while including an uncertified book. But when including a certified book, then unless `:CHECK-EXPANSION` is supplied a non-`nil` value, the `make-event` replacement will just be the expansion, which does not include the `:DO-PROOFS` wrapper and hence will be evaluated with proofs skipped.

(2) `:OR` ``call'' produced by expansion.

There may be times where you want to try different expansions. For example, the community book `books/make-event/proof-by-arith.lisp` attempts to admit a given event, which we'll denote `EV`, by trying events of the following form as `BOOK` varies over different community books.

    (encapsulate
     ()
     (local (include-book BOOK :DIR :SYSTEM))
     EV)

A naive implementation of this macro would evaluate all such `encapsulate` events until one succeeds, and then return that successful event as the expansion. Then that event would need to be evaluated again! With some hacking one could avoid that re-evaluation by using `skip-proofs`, but that won't work if you are trying to create a certified book without skipped proofs. Instead, the implementation creates an expansion of the form `(:OR ev-1 ev-2 ... ev-k)`, where the list `(ev-1 ev-2 ... ev-k)` enumerates the generated encapsulate events. In general, for this ``disjunctive case'' of a result from expansion, each `ev-i` is evaluated in sequence, and the first that succeeds without error is considered to be the expansion result -- and a repeat evaluation is avoided. If evaluation of each `ev-i` results in an error, then so does the `make-event` call.

This special use of `:OR` in a value produced by expansion is only supported at the top level. That is, the result can be `(:OR ev-1 ev-2 ... ev-k)` but then each `ev-i` must be a legal expansion result, without such further use of `:OR` -- except, `ev-i` may be `(:DO-PROOFS ev-i')`, where `ev-i'` then would serve as the expansion rather than `ev-i`.

(3) The `:EXPANSION?` keyword argument.

If keyword argument `:EXPANSION?` has a non`nil` value, then the `:CHECK-EXPANSION` keyword must be omitted or have value `nil` or `t`, hence not a cons pair.

The idea of the `:EXPANSION?` keyword is to give you a way to avoid storing expansion results in a book's certificate. Roughly speaking, when the expansion result matches the value of `:EXPANSION?`, then no expansion result is stored for the event by book certification; then when the book is later included, the value of `:EXPANSION?` is used as the expansion, thus bypassing the expansion phase. One could say that the event is its own make-event replacement, but it is more accurate to say that there is no make-event replacement at all, since nothing is stored in the certificate for this event. Below, we elaborate on make-event replacements when `:EXPANSION` is used and also discuss other properties of this keyword.

We modify the notion of ``expansion result'' for `make-event` forms to comprehend the use of the `:EXPANSION?` keyword. For that purpose, let's consider a call of `make-event` to be ``reducible'' if it has an `:EXPANSION?` keyword with non-`nil` value, `exp`, and its `:CHECK-EXPANSION` keyword is missing or has value `nil`, in which case the ``reduction'' of this `make-event` call is defined to be `exp`. The expansion result as originally defined is modified by the following ``recursive reduction'' process: recur through the original expansion, passing through calls of `local`, `skip-proofs`, `with-output`, `with-prover-step-limit`, and `with-prover-time-limit`, and replacing (recursively) any reducible call of `make-event` by its reduction. Furthermore, we refer to two forms as ``reduction equivalent'' if their recursive reductions are equal. Note that the recursive reduction process does not pass through `progn` or `encapsulate`, but that process is applied to the computation of expansions for their subsidiary `make-event` calls.

To explain further the effect of `:EXPANSION? exp`, we split into the following two cases.

o Case 1: Evaluation is not taking place when including a book or evaluating the second pass of an `encapsulate` event; more precisely, the value of `(ld-skip-proofsp state)` is not the symbol `INCLUDE-BOOK`. There are two subcases.

> - Case 1a: The expansion result is not reduction-equivalent to `exp`. Then the `make-event` call is processed as though the `:EXPANSION?` keyword had been omitted.

> - Case 2a: The expansion result is reduction-equivalent to `exp`. Then there is no `make-event` replacement for this call of `make-event`; no replacement will be put into the certificate file for a book containing this `make-event` call. When that book is subsequently included, the original form will be evaluated in the manner described in the next case.

o Case 2: Evaluation is taking place when including a book or evaluating the second pass of an `encapsulate` event; more precisely, the value of `(ld-skip-proofsp state)` is the symbol `INCLUDE-BOOK`. Then the expansion is `exp`. The expansion phase is skipped unless `:CHECK-EXPANSION` is `t`.

The `:EXPANSION?` keyword can be particularly useful in concert with the disjunctive (```:OR`'') case (2) discussed above. Suppose that expansion produces a value as discussed in (2) above, `(:OR exp-1 ... exp-k)`. If one of these expressions `exp-i` is more likely than the others to be the expansion, then you may wish to specify `:EXPANSION? exp-i`, as this will avoid storing a `make-event` replacement in that common case. This could be useful if the expressions are large, to avoid enlarging the certificate file for a book containing the `make-event` call.

It is legal to specify both `:EXPANSION? exp` and `:CHECK-EXPANSION t`. When either `(ld-skip-proofsp state)` is the symbol `INCLUDE-BOOK`, or evaluation is taking place in raw Lisp, then this combination is treated the same as if `:EXPANSION?` is omitted and the value of `:CHECK-EXPANSION` is `exp`. Otherwise, this combination is treated the same as `:CHECK-EXPANSION t`, modified to accommodate the effect of `:EXPANSION?` as discussed above: if the expansion is indeed the value of `:EXPANSION?`, then no `make-event` replacement is generated.