other
(in-package "STD")
other
(include-book "define")
other
(include-book "maybe-defthm")
other
(include-book "std/lists/abstract" :dir :system)
other
(set-state-ok t)
other
(defxdoc deflist :parents (std/util) :short "Introduce a recognizer for a typed list." :long "<p>Deflist lets you to quickly introduce recognizers for typed lists like @(see nat-listp). It defines the new recognizer function, sets up a basic theory with rules about @(see len), @(see append), @(see member), etc., and generates basic, automatic @(see xdoc) documentation.</p> <h4>General Form</h4> @({ (deflist name formals element [keyword options] [/// other events] ) Options Defaults :negatedp nil :true-listp nil :elementp-of-nil :unknown :guard t :verify-guards t :guard-hints nil :guard-debug nil :non-emptyp nil :mode current defun-mode :cheap nil :verbosep nil :parents nil :short nil :long nil :prepwork nil }) <h4>Basic Examples</h4> <p>The following introduces a new function, @('my-integer-listp'), which recognizes lists whose every element satisfies @('integerp'), and also introduces many theorems about this new function.</p> @({ (deflist my-integer-listp (x) (integerp x)) }) <p><b><color rgb='#ff0000'>Note</color></b>: @('x') is treated in a special way. It refers to the whole list in formals and guards, but refers to individual elements of the list in the @('element') portion. This is similar to how other macros like @(see defalist), @(see defprojection), and @(see defmapappend) handle @('x').</p> <p>Here is a recognizer for lists with no natural numbers:</p> @({ (deflist nat-free-listp (x) (natp x) :negatedp t) }) <p>Here is a recognizer for lists whose elements must exceed some minimum:</p> @({ (deflist all-greaterp (min x) (> x min) :guard (and (natp min) (nat-listp x))) }) <h3>Usage and Optional Arguments</h3> <p>Let @('pkg') be the package of @('name'). All functions, theorems, and variables are created in this package. One of the formals must be @('pkg::x'), and this argument represents the list to check. Otherwise, the only restriction on the formals is that you may not use the names @('pkg::a'), @('pkg::n'), or @('pkg::y'), because we use these variables in the theorems we generate.</p> <p>The optional @(':negatedp') keyword can be used to recognize a list whose every element does not satisfy elementp.</p> <p>The optional @(':true-listp') keyword can be used to require that the new recognizer is "strict" and will only accept lists that are @('nil')-terminated; by default the recognizer will be "loose" and will not pay attention to the final @('cdr'). There are various reasons to prefer one behavior or another; see @(see strict-list-recognizers) for details.</p> <p>The optional @(':elementp-of-nil') keyword can be used when @('(elementp nil ...)') is always known to be @('t') or @('nil'). When it is provided, @('deflist') can generate slightly better theorems.</p> <p>The optional @(':guard'), @(':verify-guards'), @(':guard-debug'), and @(':guard-hints') are options for the @(see defun) we introduce. These are for the guards of the new list recognizer, not the element recognizer.</p> <p>The optional @(':mode') keyword can be set to @(':logic') or @(':program') to introduce the recognizer in logic or program mode. The default is whatever the current default defun-mode is for ACL2, i.e., if you are already in program mode, it will default to program mode, etc.</p> <p>The optional @(':verbosep') flag can be set to @('t') if you want deflist to print everything it's doing. This may be useful if you run into any failures, or if you are simply curious about what is being introduced.</p> <p>The optional @(':cheap') flag can be set to @('t') to produce cheaper, less effective rule-classes for some rules; this may be convenient when the element type is a very common function such as @('consp'), in which case adding stronger rules might significantly slow down proofs.</p> <p>The optional @(':parents'), @(':short'), and @(':long') keywords are as in @(see defxdoc). Typically you only need to specify @(':parents'), perhaps implicitly with @(see xdoc::set-default-parents), and suitable documentation will be automatically generated for @(':short') and @(':long'). If you don't like this documentation, you can supply your own @(':short') and/or @(':long') to override it.</p> <p>The optional @(':prepwork') may provide a list of event forms that are submitted just before the generated events. These are preparatory events, e.g. local lemmas to help prove @(':elementp-of-nil').</p> <h3>Pluggable Architecture</h3> <p>Beginning in ACL2 6.5, deflist no longer hard-codes the set of theorems to be produced about every list recognizer. Instead, @('def-listp-rule') forms pertaining to a generic list recognizer called @('element-list-p') are used as templates and instantiated for each deflist invocation. These forms may be scattered throughout various libraries, so the set of books you have loaded determines the set of rules produced by a deflist invocation. See @(see acl2::std/lists/abstract) for more information about these rules and how to control what theorems are produced by deflist.</p> <p>"std/util/deflist.lisp" includes books that compose a set of rules to instantiate that should be more or less backward compatible with the theorems produced by deflist in ACL2 6.4 and previous. "std/util/deflist-base.lisp" includes a much more basic set of rules.</p> <h3>Support for Other Events</h3> <p>Deflist implements the same @('///') syntax as other macros like @(see define). This allows you to put related events near the definition and have them included in the automatic documentation. As with define, the new recognizer is enabled during the @('///') section. Here is an example:</p> @({ (deflist even-integer-list-p (x) (even-integer-p x) :true-listp t /// (defthm integer-listp-when-even-integer-list-p (implies (even-integer-list-p x) (integer-listp x)))) }) <p>Deprecated. The optional @(':rest') keyword was a precursor to @('///'). It is still implemented, but its use is now discouraged. If both @(':rest') and @('///') events are used, we arbitrarily put the @(':rest') events first.</p> <p>Deprecated. The optional @(':already-definedp') keyword can be set if you have already defined the function. This was previously useful when you wanted to generate the ordinary @('deflist') theorems without generating a @('defund') event, e.g., because you are dealing with mutually recursive recognizers. We still accept this option for backwards compatibility but it is useless, because @('deflist') is now smart enough to notice that the function is already defined.</p>")
other
(defxdoc strict-list-recognizers :parents (deflist) :short "Should your list recognizers require @('nil')-terminated lists?" :long "<p>Here are two ways that you could write a list recognizer:</p> <p>The "strict" way:</p> @({ (defun foo-listp (x) (if (atom x) (not x) (and (foop (car x)) (foo-listp (cdr x))))) }) <p>The "loose" way:</p> @({ (defun foo-listp (x) (if (atom x) t (and (foop (car x)) (foo-listp (cdr x))))) }) <p>The only difference is that in the base case, the strict recognizer requires X to be NIL, whereas the loose recognizer allows X to be any atom.</p> <p>By default, the recognizers introduced by @(see deflist) follow the loose approach. You can use the @(':true-listp') option to change this behavior, and instead introduce a strict recognizer.</p> <p>Why in the world would we use a loose recognizer? Well, there are advantages to either approach.</p> <p>The strict approach is certainly more clear and less weird. It is nice that a strict recognizer always implies @(see true-listp). And it makes EQUAL more meaningful when applied to FOO-LISTP objects.</p> <p>That is, when FOO-LISTP is strict, there is only one FOO-LISTP that has length 3 and whose first three elements are (A B C). However, when FOO-LISTP is loose, there are infinitely many lists like this, and the only difference between them is their final cdr.</p> <p>This nicer equality behavior makes the strict approach especially appealing when you are building new data types that include FOO-LISTP components, and you'd like to just reuse EQUAL instead of having new equivalence relations for each structure.</p> <p>But the loose approach more nicely follows the @(see list-fix) convention: "a function that takes a list as an argument should coerce the final-cdr to NIL, and produce the same result regardless of the final cdr." More formally, you might say that F respects the list-fix convention when you can prove</p> @({ (defcong list-equiv equal (f ... x ...) n) }) <p>Where list-equiv is equality up to the final cdr, e.g.,</p> @({ (list-equiv x y) = (equal (list-fix x) (list-fix y)) }) <p>Many functions follow this convention or something similar to it, and because of this there are sometimes nicer theorems about loose list recognizers than about strict list recognizers. For instance, consider @(see append). In the loose style, we can prove:</p> @({ (equal (foo-listp (append x y)) (and (foo-listp x) (foo-listp y))) }) <p>In the strict style, we have to prove something uglier, e.g.,</p> @({ (equal (foo-listp (append x y)) (and (foo-listp (list-fix x)) (foo-listp y))) }) <p>There are many other nice theorems, but just as a few examples, each of these theorems are very nice in the loose style, and are uglier in the strict style:</p> @({ (equal (foo-listp (list-fix x)) (foo-listp x)) (equal (foo-listp (rev x)) (foo-listp x)) (equal (foo-listp (mergesort x)) (foo-listp x)) (implies (and (subsetp-equal x y) (foo-listp y)) (foo-listp x)) }) <p>@(see deflist) originally came out of @(see acl2::milawa), where I universally applied the loose approach, and in that context I think it is very nice. It's not entirely clear that loose recognizers are a good fit for ACL2. Really one of the main objections to the loose style is: ACL2's built-in list recognizers use the strict approach, and it can become irritating to keep track of which recognizers require true-listp and which don't.</p>")
other
(defconst *deflist-valid-keywords* '(:negatedp :cheap :guard :verify-guards :guard-debug :guard-hints :already-definedp :elementp-of-nil :non-emptyp :mode :parents :short :long :true-listp :rest :verbosep :prepwork :theory-hack))
other
(program)
deflist-substitutionfunction
(defun deflist-substitution (name formals element kwd-alist x) (b* ((negatedp (getarg :negatedp nil kwd-alist)) (true-listp (getarg :true-listp nil kwd-alist)) (non-emptyp (getarg :non-emptyp nil kwd-alist))) `((element-p ,(IF STD::NEGATEDP `(LAMBDA (,STD::X) (NOT ,STD::ELEMENT)) `(LAMBDA (,STD::X) ,STD::ELEMENT))) (non-element-p ,(IF STD::NEGATEDP `(LAMBDA (,STD::X) ,STD::ELEMENT) `(LAMBDA (,STD::X) (NOT ,STD::ELEMENT)))) (,(IF STD::NON-EMPTYP 'ELEMENT-LIST-NONEMPTY-P 'ELEMENT-LIST-P) (lambda (,STD::X) (,STD::NAME . ,STD::FORMALS))) (element-list-final-cdr-p ,(IF STD::TRUE-LISTP 'NOT '(LAMBDA (STD::X) T))))))
atom/quote-listpfunction
(defun atom/quote-listp (x) (if (atom x) (eq x nil) (and (or (atom (car x)) (eq (caar x) 'quote)) (atom/quote-listp (cdr x)))))
simple-fncall-p-hackfunction
(defun simple-fncall-p-hack (x) (and (consp x) (symbolp (car x)) (atom/quote-listp (cdr x))))
deflist-requirement-alistfunction
(defun deflist-requirement-alist (kwd-alist formals element) (b* ((negatedp (getarg :negatedp nil kwd-alist)) (simple (simple-fncall-p-hack element)) (true-listp (getarg :true-listp nil kwd-alist)) (elementp-of-nil (getarg :elementp-of-nil :unknown kwd-alist)) (single-var (eql (len formals) 1)) (cheap (getarg :cheap nil kwd-alist))) `((element-p-of-nil . ,(EQ STD::ELEMENTP-OF-NIL (NOT STD::NEGATEDP))) (not-element-p-of-nil . ,(EQ STD::ELEMENTP-OF-NIL STD::NEGATEDP)) (negatedp . ,STD::NEGATEDP) (true-listp . ,STD::TRUE-LISTP) (single-var . ,STD::SINGLE-VAR) (cheap . ,STD::CHEAP) (simple . ,STD::SIMPLE))))
other
(mutual-recursion (defun deflist-thmbody-subst (body element name formals x negatedp) (if (atom body) body (case (car body) (element-p (let ((call (cons (car element) (subst (cadr body) x (cdr element))))) (if negatedp (list 'not call) call))) (non-element-p (let ((call (cons (car element) (subst (cadr body) x (cdr element))))) (if negatedp call (list 'not call)))) (element-list-p (cons name (subst (cadr body) x formals))) (element-list-nonempty-p (cons name (subst (cadr body) x formals))) (t (if (symbolp (car body)) (cons (car body) (deflist-thmbody-list-subst (cdr body) element name formals x negatedp)) (deflist-thmbody-list-subst body element name formals x negatedp)))))) (defun deflist-thmbody-list-subst (body element name formals x negatedp) (if (atom body) body (cons (deflist-thmbody-subst (car body) element name formals x negatedp) (deflist-thmbody-list-subst (cdr body) element name formals x negatedp)))))
deflist-thmname-substfunction
(defun deflist-thmname-subst (thmname listp-name elementp) (b* ((thmname (symbol-name thmname)) (subst-list `(("ELEMENT-LIST-NONEMPTY-P" . ,(SYMBOL-NAME STD::LISTP-NAME)) ("ELEMENT-LIST-NONEMPTY" . ,(SYMBOL-NAME STD::LISTP-NAME)) ("ELEMENT-LIST-P" . ,(SYMBOL-NAME STD::LISTP-NAME)) ("ELEMENT-LIST" . ,(SYMBOL-NAME STD::LISTP-NAME)) ("ELEMENT-P" . ,(SYMBOL-NAME STD::ELEMENTP)) ("ELEMENT" . ,(SYMBOL-NAME STD::ELEMENTP))))) (intern-in-package-of-symbol (dumb-str-sublis subst-list thmname) listp-name)))
deflist-ruleclasses-substfunction
(defun deflist-ruleclasses-subst (rule-classes element name formals x negatedp) (b* (((when (atom rule-classes)) rule-classes) (class (car rule-classes)) ((when (atom class)) (cons class (deflist-ruleclasses-subst (cdr rule-classes) element name formals x negatedp))) (corollary-look (assoc-keyword :corollary class)) ((unless corollary-look) (cons class (deflist-ruleclasses-subst (cdr rule-classes) element name formals x negatedp))) (prefix (take (- (len class) (len corollary-look)) class)) (corollary-term (deflist-thmbody-subst (cadr corollary-look) element name formals x negatedp))) (cons (append prefix `(:corollary ,STD::COROLLARY-TERM . ,(CDDR STD::COROLLARY-LOOK))) (deflist-ruleclasses-subst (cdr rule-classes) element name formals x negatedp))))
deflist-instantiatefunction
(defun deflist-instantiate (table-entry element name formals kwd-alist x req-alist fn-subst world) (b* (((cons inst-thm alist) table-entry) ((when (not alist)) nil) (alist (and (not (eq alist t)) alist)) (req-look (assoc :requirement alist)) (req-ok (or (not req-look) (generic-eval-requirement (cadr req-look) req-alist))) ((unless req-ok) nil) (thmname-base (let ((look (assoc :name alist))) (if look (cadr look) inst-thm))) (thmname (deflist-thmname-subst thmname-base name (car element))) (body (let ((look (assoc :body alist))) (if look (cadr look) (fgetprop inst-thm 'untranslated-theorem nil world)))) ((when (not body)) (er hard? 'deflist-instantiate "Bad deflist table entry: ~x0~%" inst-thm)) (rule-classes (b* ((cheap-look (and (getarg :cheap nil kwd-alist) (assoc :cheap-rule-classes alist))) ((when cheap-look) (cadr cheap-look)) (look (assoc :rule-classes alist))) (if look (cadr look) (fgetprop inst-thm 'classes nil world)))) (negatedp (getarg :negatedp nil kwd-alist)) (rule-classes (deflist-ruleclasses-subst rule-classes element name formals x negatedp))) `((defthm ,STD::THMNAME ,(STD::DEFLIST-THMBODY-SUBST STD::BODY STD::ELEMENT STD::NAME STD::FORMALS STD::X STD::NEGATEDP) :hints (("goal" :use ((:functional-instance ,STD::INST-THM . ,STD::FN-SUBST)))) :rule-classes ,STD::RULE-CLASSES))))
deflist-instantiate-table-thms-auxfunction
(defun deflist-instantiate-table-thms-aux (table element name formals kwd-alist x req-alist fn-subst world) (if (atom table) nil (append (deflist-instantiate (car table) element name formals kwd-alist x req-alist fn-subst world) (deflist-instantiate-table-thms-aux (cdr table) element name formals kwd-alist x req-alist fn-subst world))))
deflist-instantiate-table-thmsfunction
(defun deflist-instantiate-table-thms (name formals element kwd-alist x world) (b* ((non-emptyp (getarg :non-emptyp nil kwd-alist)) (table (reverse (table-alist (if non-emptyp 'nonempty-listp-rules 'listp-rules) world))) (fn-subst (deflist-substitution name formals element kwd-alist x)) (req-alist (deflist-requirement-alist kwd-alist formals element))) (deflist-instantiate-table-thms-aux table element name formals kwd-alist x req-alist fn-subst world)))
deflist-fnfunction
(defun deflist-fn (name formals element kwd-alist other-events state) (declare (xargs :mode :program)) (b* ((__function__ 'deflist) (x (intern-in-package-of-symbol "X" name)) (a (intern-in-package-of-symbol "A" name)) (n (intern-in-package-of-symbol "N" name)) (y (intern-in-package-of-symbol "Y" name)) ((unless (and (symbol-listp formals) (no-duplicatesp formals))) (raise "The formals must be a list of unique symbols, but are ~x0." formals)) ((unless (member x formals)) (raise "The formals must contain ~x0, but are ~x1.~%" x formals)) ((unless (and (not (member a formals)) (not (member n formals)) (not (member y formals)))) (raise "As a special restriction, formals may not mention ~x0, ~x1, ~ or ~x2, but the formals are ~x3." a n y formals)) ((unless (and (consp element) (symbolp (car element)))) (raise "The element recognizer must be a function applied to the ~ formals, but is ~x0." element)) (elementp (car element)) (elem-formals (cdr element)) (looks-already-defined-p (or (not (eq (getprop name 'formals :none 'current-acl2-world (w state)) :none)) (not (eq (getprop name 'macro-args :none 'current-acl2-world (w state)) :none)))) (already-definedp (getarg :already-definedp :unknown kwd-alist)) ((unless (or (eq already-definedp :unknown) (eq already-definedp looks-already-defined-p))) (raise "Found :already-definedp ~x0, but ~x1 is ~s2." already-definedp name (if looks-already-defined-p "already defined." "not defined."))) (already-definedp looks-already-defined-p) (negatedp (getarg :negatedp nil kwd-alist)) (true-listp (getarg :true-listp nil kwd-alist)) (verify-guards (getarg :verify-guards t kwd-alist)) (guard (getarg :guard t kwd-alist)) (guard-debug (getarg :guard-debug nil kwd-alist)) (guard-hints (getarg :guard-hints nil kwd-alist)) (elementp-of-nil (getarg :elementp-of-nil :unknown kwd-alist)) (short (getarg :short nil kwd-alist)) (long (getarg :long nil kwd-alist)) (theory-hack (getarg :theory-hack nil kwd-alist)) (non-emptyp (getarg :non-emptyp nil kwd-alist)) (prepwork (getarg :prepwork nil kwd-alist)) (rest (append (getarg :rest nil kwd-alist) other-events)) (mode (getarg :mode (default-defun-mode (w state)) kwd-alist)) (parents-p (assoc :parents kwd-alist)) (parents (cdr parents-p)) (parents (if parents-p parents (or (get-default-parents (w state)) '(undocumented)))) ((unless (booleanp negatedp)) (raise ":negatedp must be a boolean, but is ~x0." negatedp)) ((unless (booleanp true-listp)) (raise ":true-listp must be a boolean, but is ~x0." true-listp)) ((unless (booleanp verify-guards)) (raise ":verify-guards must be a boolean, but is ~x0." verify-guards)) ((unless (or (eq mode :logic) (eq mode :program))) (raise ":mode must be one of :logic or :program, but is ~x0." mode)) ((unless (or (eq mode :logic) (not already-definedp))) (raise ":mode :program and already-definedp cannot be used together.")) ((unless (member elementp-of-nil '(t nil :unknown))) (raise ":elementp-of-nil must be t, nil, or :unknown")) (short (or short (and parents (concatenate 'string "@(call " (full-escape-symbol name) ") recognizes lists where every element " (if negatedp "is rejected by " "satisfies ") "@(see? " (full-escape-symbol elementp) ").")))) (long (or long (and parents (if true-listp "<p>This is an ordinary @(see std::deflist). It is "strict" in that it requires @('x') to be a "properly" nil-terminated list.</p>" "<p>This is an ordinary @(see std::deflist). It is "loose" in that it does not care whether @('x') is nil-terminated.</p>")))) (car-test (if negatedp `(not (,STD::ELEMENTP ,@(SUBST `(CAR ,STD::X) STD::X STD::ELEM-FORMALS))) `(,STD::ELEMENTP ,@(SUBST `(CAR ,STD::X) STD::X STD::ELEM-FORMALS)))) (end-test (if true-listp `(null ,STD::X) t)) (def (if already-definedp (and (or (and parents-p parents) short long) `((defxdoc ,STD::NAME ,@(AND (OR STD::PARENTS-P STD::PARENTS) `(:PARENTS ,STD::PARENTS)) ,@(AND STD::SHORT `(:SHORT ,STD::SHORT)) ,@(AND STD::LONG `(:LONG ,STD::LONG)) :no-override t))) `((define ,STD::NAME (,@STD::FORMALS) ,@(AND (OR STD::PARENTS-P STD::PARENTS) `(:PARENTS ,STD::PARENTS)) ,@(AND STD::SHORT `(:SHORT ,STD::SHORT)) ,@(AND STD::LONG `(:LONG ,STD::LONG)) :returns bool :guard ,STD::GUARD :normalize nil ,@(AND (EQ STD::MODE :LOGIC) `(:VERIFY-GUARDS ,STD::VERIFY-GUARDS ,@(AND STD::GUARD-DEBUG `(:GUARD-DEBUG ,STD::GUARD-DEBUG)) :GUARD-HINTS ,STD::GUARD-HINTS)) ,(IF STD::NON-EMPTYP `(AND (CONSP ,STD::X) ,STD::CAR-TEST (LET ((,STD::X (CDR ,STD::X))) (IF (CONSP ,STD::X) (,STD::NAME ,@STD::FORMALS) ,STD::END-TEST))) `(IF (CONSP ,STD::X) (AND ,STD::CAR-TEST (,STD::NAME ,@(SUBST `(CDR ,STD::X) STD::X STD::FORMALS))) ,STD::END-TEST)))))) ((when (eq mode :program)) `(encapsulate nil (program) ,@STD::PREPWORK ,@STD::DEF ,@REST)) (want-doc-p (or short long parents)) (thms (deflist-instantiate-table-thms name formals element kwd-alist x (w state))) (name-basics (intern-in-package-of-symbol (concatenate 'string (symbol-name name) "-BASICS") name)) (thms-section (if (or (not want-doc-p) (and already-definedp (find-topic name-basics (get-xdoc-table (w state))))) `(progn . ,STD::THMS) `(defsection-progn ,STD::NAME-BASICS :parents (,STD::NAME) :short ,(CONCATENATE 'STRING "Basic theorems about @(see " (XDOC::FULL-ESCAPE-SYMBOL STD::NAME) "), generated by @(see std::deflist).") . ,STD::THMS))) (events `((logic) ,@STD::PREPWORK (set-inhibit-warnings "theory" "free" "non-rec" "double-rewrite" "subsume" "disable") (value-triple (cw "~|~%Deflist: attempting to show, using your current theory, ~ that ~x0 is always Boolean valued.~%" ',STD::ELEMENT)) (with-output :stack :pop :off (summary observation) (local (defthm deflist-local-booleanp-element-thm (or (equal ,STD::ELEMENT t) (equal ,STD::ELEMENT nil)) :rule-classes :type-prescription))) ,@(AND (NOT (EQ STD::ELEMENTP-OF-NIL :UNKNOWN)) `((STD::VALUE-TRIPLE (STD::CW "~|~%Deflist: attempting to justify, using your ~ current theory, :ELEMENTP-OF-NIL ~x0.~%" ',STD::ELEMENTP-OF-NIL)) (STD::WITH-OUTPUT :STACK :POP :OFF (SUMMARY) (STD::LOCAL (STD::MAYBE-DEFTHM-AS-REWRITE STD::DEFLIST-LOCAL-ELEMENTP-OF-NIL-THM (EQUAL (,STD::ELEMENTP ,@(SUBST ''NIL STD::X STD::ELEM-FORMALS)) ',STD::ELEMENTP-OF-NIL)))))) (value-triple (cw "~|~%Deflist: introducing ~x0 and proving deflist theorems.~%" ',STD::NAME)) ,@STD::DEF (local (in-theory (theory 'minimal-theory))) (local (in-theory (enable ,STD::NAME (:type-prescription ,STD::NAME) deflist-local-booleanp-element-thm))) (local (enable-if-theorem deflist-local-elementp-of-nil-thm)) ,@STD::THEORY-HACK ,STD::THMS-SECTION))) `(progn (encapsulate nil . ,STD::EVENTS) . ,(AND REST `((STD::VALUE-TRIPLE (STD::CW "Deflist: submitting /// events.~%")) (STD::WITH-OUTPUT :STACK :POP (STD::DEFSECTION STD::USER-EVENTS ,@(AND STD::WANT-DOC-P `(:EXTENSION ,STD::NAME)) (STD::LOCAL (STD::IN-THEORY (STD::ENABLE ,STD::NAME))) . ,REST)))))))
deflistmacro
(defmacro deflist (name &rest args) (b* ((__function__ 'deflist) ((unless (symbolp name)) (raise "Name must be a symbol.")) (ctx (list 'deflist name)) ((mv main-stuff other-events) (split-/// ctx args)) ((mv kwd-alist formals-elem) (extract-keywords ctx *deflist-valid-keywords* main-stuff nil)) ((unless (tuplep 2 formals-elem)) (raise "Wrong number of arguments to deflist.")) ((list formals element) formals-elem) (verbosep (getarg :verbosep nil kwd-alist))) `(with-output :stack :push ,@(IF STD::VERBOSEP NIL '(:GAG-MODE T :OFF (SUMMARY OBSERVATION PROVE PROOF-TREE EVENT))) (make-event `(progn ,(STD::DEFLIST-FN ',STD::NAME ',STD::FORMALS ',STD::ELEMENT ',STD::KWD-ALIST ',STD::OTHER-EVENTS STD::STATE) (value-triple '(deflist ,',STD::NAME)))))))