An example use of make-event
Here, we develop a reasonably self-contained example that
illustrates how to use
We begin by discussing prerequisites for this presentation. Next, we present the challenge problem, followed by code that solves the problem together with an example that illustrates its use. Finally, we start from the beginning and show how to develop the solution step-by-step.
We assume some general ACL2 and Common Lisp background, including
familiarity with macros and backquote. But we do some programming
below that goes beyond that general background in our use of the ACL2 state. See programming-with-state for relevant discussion, including
state global variables, f-get-global, f-put-global, error-triples and their construction using
Next, we present the challenge problem that we will solve below.
Define a utility that evaluates a given sequence of events, even continuing past errors, which stores the list of event forms that caused errors.
Let us call this utility
(progn+ (defun f1 (x) x) (defthm good-thm (equal 1 1) :rule-classes nil) (value-triple (cw "@@HI~%")) (defthm bad-thm (equal x y) :rule-classes nil) ; error! (defun f2 (x) x) (defun bad-fn (x) y) ; error! (defun f3 (x) x) )
We next present a definition of
(defmacro save-progn+-error (x) `(make-event (pprogn (f-put-global 'progn+-errors (cons ,x (f-get-global 'progn+-errors state)) state) (value '(value-triple nil))))) (defun progn+-fn (lst) (declare (xargs :guard (true-listp lst) :mode :program)) (cond ((endp lst) nil) (t (cons `(make-event '(:or ,(car lst) (save-progn+-error ',(car lst)))) (progn+-fn (cdr lst)))))) (defmacro progn+ (&rest lst) (declare (xargs :guard (and (true-listp lst) lst))) `(progn (make-event (pprogn (f-put-global 'progn+-errors nil state) (value '(value-triple nil)))) ,@(progn+-fn lst))) ; Example: (progn+ (defun f1 (x) x) (defthm good-thm (equal 1 1) :rule-classes nil) (value-triple (cw "@@HI~%")) (defthm bad-thm (equal x y) :rule-classes nil) (defun f2 (x) x) (defun bad-fn (x) y) (defun f3 (x) x) )
After running the example (which is the final form above), we expect the
resulting logical world to contain definitions of function symbols
ACL2 !>:pe f1 4:x(PROGN+ (DEFUN F1 # ...) (DEFTHM GOOD-THM # ...) ...) >L (DEFUN F1 (X) X) ACL2 !>:pe f2 4:x(PROGN+ (DEFUN F1 # ...) (DEFTHM GOOD-THM # ...) ...) >L (DEFUN F2 (X) X) ACL2 !>:pe f3 4:x(PROGN+ (DEFUN F1 # ...) (DEFTHM GOOD-THM # ...) ...) >L (DEFUN F3 (X) X) ACL2 !>(@ progn+-errors) ; same as (f-get-global 'progn+-errors state) ((DEFUN BAD-FN (X) Y) (DEFTHM BAD-THM (EQUAL X Y) :RULE-CLASSES NIL)) ACL2 !>
We now start from the beginning. Recall that progn does almost
what we ask
Thus, we begin with a simple piece of the task, by showing how to create an
event that will push a specific form,
(make-event (pprogn (f-put-global 'progn+-errors (cons '(defthm bad-thm (equal x y) :rule-classes nil) (f-get-global 'progn+-errors state)) state) (value '(value-triple nil))))
It might seem more natural to write
We follow good programming practice by wrapping the functionality displayed above into a concise utility, as follows.
(defmacro save-progn+-error (x) ; Push x (which is evaluated) onto the value of state global 'progn+-errors. `(make-event (pprogn (f-put-global 'progn+-errors (cons ,x (f-get-global 'progn+-errors state)) state) (value '(value-triple nil)))))
Before we write
(f-put-global 'progn+-errors nil state) (progn (defun f1 (x) x) (defthm good-thm (equal 1 1) :rule-classes nil) (value-triple (cw "@@HI~%")) (save-progn+-error '(defthm bad-thm (equal x y) :rule-classes nil)) (defun f2 (x) x) (save-progn+-error '(defun bad-fn (x) y)) (defun f3 (x) x) )
Our next task is to find a way to tell ACL2 that it should run a given
event, and if that event fails it should save it using
(make-event '(:or (defun f2 (x) x) (save-progn+-error '(defun f2 (x) x)))) (make-event '(:or (defun bad-fn (x) y) (save-progn+-error '(defun bad-fn (x) y))))
In the first example,
We can now define
(defun progn+-fn (lst) (declare (xargs :guard (true-listp lst) :mode :program)) (cond ((endp lst) nil) (t (cons `(make-event '(:or ,(car lst) (save-progn+-error ',(car lst)))) (progn+-fn (cdr lst))))))
We complete our definition of
(defmacro progn+ (&rest lst) (declare (xargs :guard (and (true-listp lst) lst))) `(progn (make-event (pprogn (f-put-global 'progn+-errors nil state) (value '(value-triple nil)))) ,@(progn+-fn lst)))
Exercise: Modify this tool so that instead of merely updating a state global, it prints the failed events at the end of execution; and moreover, it prints them in their original order. See make-event-example-2-exercise for a solution.