34
34
; Kookamara LLC, which is also available under an MIT/X11 style license.
37
(include-book "xdoc/top" :dir :system)
38
(include-book "tools/bstar" :dir :system)
39
(include-book "std/osets/top" :dir :system)
37
(include-book "deflist-base")
38
(include-book "std/osets/element-list" :dir :system)
40
39
(include-book "defsort/duplicated-members" :dir :system)
41
40
(include-book "std/lists/sets" :dir :system)
42
41
(include-book "std/lists/list-fix" :dir :system)
43
42
(include-book "std/lists/take" :dir :system)
44
43
(include-book "std/lists/repeat" :dir :system)
45
44
(include-book "std/lists/rev" :dir :system)
46
(include-book "maybe-defthm")
47
(include-book "support")
52
:short "Introduce a recognizer for a typed list."
54
:long "<p>Deflist lets you to quickly introduce recognizers for typed lists
55
like @(see nat-listp). It defines the new recognizer function, sets up a basic
56
theory with rules about @(see len), @(see append), @(see member), etc., and
57
generates basic, automatic @(see xdoc) documentation.</p>
71
:elementp-of-nil :unknown
76
:mode current defun-mode
83
<h4>Basic Examples</h4>
85
<p>The following introduces a new function, @('my-integer-listp'), which
86
recognizes lists whose every element satisfies @('integerp'), and also
87
introduces many theorems about this new function.</p>
90
(deflist my-integer-listp (x)
94
<p><b><color rgb='#ff0000'>Note</color></b>: @('x') is treated in a special
95
way. It refers to the whole list in formals and guards, but refers to
96
individual elements of the list in the @('element') portion. This is similar
97
to how other macros like @(see defalist), @(see defprojection), and @(see
98
defmapappend) handle @('x').</p>
100
<p>Here is a recognizer for lists with no natural numbers:</p>
103
(deflist nat-free-listp (x)
108
<p>Here is a recognizer for lists whose elements must exceed some minimum:</p>
111
(deflist all-greaterp (min x)
113
:guard (and (natp min)
117
<h3>Usage and Optional Arguments</h3>
119
<p>Let @('pkg') be the package of @('name'). All functions, theorems, and
120
variables are created in this package. One of the formals must be @('pkg::x'),
121
and this argument represents the list to check. Otherwise, the only
122
restriction on the formals is that you may not use the names @('pkg::a'),
123
@('pkg::n'), or @('pkg::y'), because we use these variables in the theorems we
126
<p>The optional @(':negatedp') keyword can be used to recognize a list whose
127
every element does not satisfy elementp.</p>
129
<p>The optional @(':true-listp') keyword can be used to require that the new
130
recognizer is \"strict\" and will only accept lists that are
131
@('nil')-terminated; by default the recognizer will be \"loose\" and will not
132
pay attention to the final @('cdr'). There are various reasons to prefer one
133
behavior or another; see @(see strict-list-recognizers) for details.</p>
135
<p>The optional @(':elementp-of-nil') keyword can be used when @('(elementp nil
136
...)') is always known to be @('t') or @('nil'). When it is provided,
137
@('deflist') can generate slightly better theorems.</p>
139
<p>The optional @(':guard'), @(':verify-guards'), @(':guard-debug'), and
140
@(':guard-hints') are options for the @(see defun) we introduce. These are for
141
the guards of the new list recognizer, not the element recognizer.</p>
143
<p>The optional @(':mode') keyword can be set to @(':logic') or @(':program')
144
to introduce the recognizer in logic or program mode. The default is whatever
145
the current default defun-mode is for ACL2, i.e., if you are already in program
146
mode, it will default to program mode, etc.</p>
148
<p>The optional @(':verbosep') flag can be set to @('t') if you want deflist to
149
print everything it's doing. This may be useful if you run into any failures,
150
or if you are simply curious about what is being introduced.</p>
152
<p>The optional @(':parents'), @(':short'), and @(':long') keywords are as in
153
@(see defxdoc). Typically you only need to specify @(':parents'), perhaps
154
implicitly with @(see xdoc::set-default-parents), and suitable documentation
155
will be automatically generated for @(':short') and @(':long'). If you don't
156
like this documentation, you can supply your own @(':short') and/or @(':long')
159
<h3>Support for Other Events</h3>
161
<p>Deflist implements the same @('///') syntax as other macros like @(see
162
define). This allows you to put related events near the definition and have
163
them included in the automatic documentation. As with define, the new
164
recognizer is enabled during the @('///') section. Here is an example:</p>
167
(deflist even-integer-list-p (x)
171
(defthm integer-listp-when-even-integer-list-p
172
(implies (even-integer-list-p x)
176
<p>Deprecated. The optional @(':rest') keyword was a precursor to @('///').
177
It is still implemented, but its use is now discouraged. If both @(':rest')
178
and @('///') events are used, we arbitrarily put the @(':rest') events
181
<p>Deprecated. The optional @(':already-definedp') keyword can be set if you
182
have already defined the function. This was previously useful when you wanted
183
to generate the ordinary @('deflist') theorems without generating a @('defund')
184
event, e.g., because you are dealing with mutually recursive recognizers. We
185
still accept this option for backwards compatibility but it is useless, because
186
@('deflist') is now smart enough to notice that the function is already
189
(defxdoc strict-list-recognizers
191
:short "Should your list recognizers require @('nil')-terminated lists?"
193
:long "<p>Here are two ways that you could write a list recognizer:</p>
195
<p>The \"strict\" way:</p>
202
(foo-listp (cdr x)))))
205
<p>The \"loose\" way:</p>
212
(foo-listp (cdr x)))))
215
<p>The only difference is that in the base case, the strict recognizer requires
216
X to be NIL, whereas the loose recognizer allows X to be any atom.</p>
218
<p>By default, the recognizers introduced by @(see deflist) follow the loose
219
approach. You can use the @(':true-listp') option to change this behavior, and
220
instead introduce a strict recognizer.</p>
222
<p>Why in the world would we use a loose recognizer? Well, there are
223
advantages to either approach.</p>
225
<p>The strict approach is certainly more clear and less weird. It is nice that
226
a strict recognizer always implies @(see true-listp). And it makes EQUAL more
227
meaningful when applied to FOO-LISTP objects.</p>
229
<p>That is, when FOO-LISTP is strict, there is only one FOO-LISTP that has
230
length 3 and whose first three elements are (A B C). However, when FOO-LISTP
231
is loose, there are infinitely many lists like this, and the only difference
232
between them is their final cdr.</p>
234
<p>This nicer equality behavior makes the strict approach especially appealing
235
when you are building new data types that include FOO-LISTP components, and
236
you'd like to just reuse EQUAL instead of having new equivalence relations for
239
<p>But the loose approach more nicely follows the @(see list-fix) convention:
240
\"a function that takes a list as an argument should coerce the final-cdr to
241
NIL, and produce the same result regardless of the final cdr.\" More formally,
242
you might say that F respects the list-fix convention when you can prove</p>
245
(defcong list-equiv equal (f ... x ...) n)
248
<p>Where list-equiv is equality up to the final cdr, e.g.,</p>
251
(list-equiv x y) = (equal (list-fix x) (list-fix y))
254
<p>Many functions follow this convention or something similar to it, and
255
because of this there are sometimes nicer theorems about loose list recognizers
256
than about strict list recognizers. For instance, consider @(see append). In
257
the loose style, we can prove:</p>
260
(equal (foo-listp (append x y))
265
<p>In the strict style, we have to prove something uglier, e.g.,</p>
268
(equal (foo-listp (append x y))
269
(and (foo-listp (list-fix x))
273
<p>There are many other nice theorems, but just as a few examples, each of
274
these theorems are very nice in the loose style, and are uglier in the strict
278
(equal (foo-listp (list-fix x))
281
(equal (foo-listp (rev x))
284
(equal (foo-listp (mergesort x))
287
(implies (and (subsetp-equal x y)
292
<p>@(see deflist) originally came out of <a
293
href='http://www.cs.utexas.edu/users/jared/milawa/Web/'>Milawa</a>, where I
294
universally applied the loose approach, and in that context I think it is very
295
nice. It's not entirely clear that loose recognizers are a good fit for ACL2.
296
Really one of the main objections to the loose style is: ACL2's built-in list
297
recognizers use the strict approach, and it can become irritating to keep track
298
of which recognizers require true-listp and which don't.</p>")
47
(include-book "std/lists/nth" :dir :system)
48
(include-book "std/lists/update-nth" :dir :system)
49
(include-book "std/lists/butlast" :dir :system)
50
(include-book "std/lists/nthcdr" :dir :system)
51
(include-book "std/lists/append" :dir :system)
52
(include-book "std/lists/last" :dir :system)
53
(include-book "std/lists/rcons" :dir :system)
54
(include-book "std/lists/remove" :dir :system)
55
(include-book "std/lists/revappend" :dir :system)
56
(include-book "defredundant")))
59
;; Harvest the listp rules from the above books by non-locally setting the
60
;; listp-rules table to its (local) value. Redundantly define the theorems
61
;; referenced by the table.
63
(let ((tab (table-alist 'acl2::listp-rules (w state))))
64
`(table acl2::listp-rules nil ',tab :clear)))
67
(defredundant-fn (strip-cars (table-alist 'acl2::listp-rules (w state))) nil state))
300
70
(defsection deflist-lemmas
487
258
acl2::list-fix-under-list-equiv
488
259
set::mergesort-under-set-equiv
489
260
acl2::binary-append-without-guard))
492
(defconst *deflist-valid-keywords*
507
;; Undocumented option for customizing the theory, mainly meant for
508
;; problematic cases, e.g., built-in functions where ACL2 "knows too much"
511
(defun deflist-fn (name formals element kwd-alist other-events state)
512
(declare (xargs :mode :program))
513
(b* ((__function__ 'deflist)
514
(mksym-package-symbol name)
516
;; Special variables that are reserved by deflist.
517
(x (intern-in-package-of-symbol "X" name))
518
(a (intern-in-package-of-symbol "A" name))
519
(n (intern-in-package-of-symbol "N" name))
520
(y (intern-in-package-of-symbol "Y" name))
522
((unless (and (symbol-listp formals)
523
(no-duplicatesp formals)))
524
(raise "The formals must be a list of unique symbols, but are ~x0."
526
((unless (member x formals))
527
(raise "The formals must contain ~x0, but are ~x1.~%" x formals))
528
((unless (and (not (member a formals))
529
(not (member n formals))
530
(not (member y formals))))
531
(raise "As a special restriction, formals may not mention ~x0, ~x1, ~
532
or ~x2, but the formals are ~x3." a n y formals))
533
((unless (and (consp element)
534
(symbolp (car element))))
535
(raise "The element recognizer must be a function applied to the ~
536
formals, but is ~x0." element))
538
(elementp (car element))
539
(elem-formals (cdr element))
541
;; We previously required the user to tell us if the function was
542
;; already defined. Now we---you know---actually look to see. Duh.
543
(looks-already-defined-p
544
(or (not (eq (getprop name 'acl2::formals :none 'acl2::current-acl2-world
547
(not (eq (getprop name 'acl2::macro-args :none 'acl2::current-acl2-world
550
(already-definedp (getarg :already-definedp :unknown kwd-alist))
551
((unless (or (eq already-definedp :unknown)
552
(eq already-definedp looks-already-defined-p)))
553
(raise "Found :already-definedp ~x0, but ~x1 is ~s2."
554
already-definedp name
555
(if looks-already-defined-p
558
(already-definedp looks-already-defined-p)
560
(negatedp (getarg :negatedp nil kwd-alist))
561
(true-listp (getarg :true-listp nil kwd-alist))
562
(verify-guards (getarg :verify-guards t kwd-alist))
563
(guard (getarg :guard t kwd-alist))
564
(guard-debug (getarg :guard-debug nil kwd-alist))
565
(guard-hints (getarg :guard-hints nil kwd-alist))
567
(elementp-of-nil (getarg :elementp-of-nil :unknown kwd-alist))
568
(short (getarg :short nil kwd-alist))
569
(long (getarg :long nil kwd-alist))
570
(theory-hack (getarg :theory-hack nil kwd-alist))
575
(getarg :rest nil kwd-alist)
579
(default-defun-mode (w state))
582
(parents-p (assoc :parents kwd-alist))
583
(parents (cdr parents-p))
584
(parents (if parents-p
586
(or (xdoc::get-default-parents (w state))
587
'(acl2::undocumented))))
589
((unless (booleanp negatedp))
590
(raise ":negatedp must be a boolean, but is ~x0." negatedp))
591
((unless (booleanp true-listp))
592
(raise ":true-listp must be a boolean, but is ~x0." true-listp))
593
((unless (booleanp verify-guards))
594
(raise ":verify-guards must be a boolean, but is ~x0." verify-guards))
595
((unless (or (eq mode :logic)
597
(raise ":mode must be one of :logic or :program, but is ~x0." mode))
598
((unless (or (eq mode :logic)
599
(not already-definedp)))
600
(raise ":mode :program and already-definedp cannot be used together."))
601
((unless (member elementp-of-nil '(t nil :unknown)))
602
(raise ":elementp-of-nil must be t, nil, or :unknown"))
607
'string "@(call " (xdoc::full-escape-symbol name)
608
") recognizes lists where every element "
612
;; bozo it'd be better to put the formals in
613
;; here, for multi-arity functions.
614
"@(see? " (xdoc::full-escape-symbol elementp) ")."))))
619
"<p>This is an ordinary @(see std::deflist). It is
620
\"strict\" in that it requires @('x') to be a
621
\"properly\" nil-terminated list.</p>"
622
"<p>This is an ordinary @(see std::deflist). It is
623
\"loose\" in that it does not care whether @('x') is
624
nil-terminated.</p>"))))
626
(def (if already-definedp
628
`((defund ,name (,@formals)
629
(declare (xargs :guard ,guard
630
;; We tell ACL2 not to normalize because
631
;; otherwise type reasoning can rewrite the
632
;; definition, and ruin some of our theorems
633
;; below, e.g., when ELEMENTP is known to
636
,@(and (eq mode :logic)
637
`(:verify-guards ,verify-guards
638
:guard-debug ,guard-debug
639
:guard-hints ,guard-hints))))
642
`(not (,elementp ,@(subst `(car ,x) x elem-formals)))
643
`(,elementp ,@(subst `(car ,x) x elem-formals)))
644
(,name ,@(subst `(cdr ,x) x formals)))
649
((when (eq mode :program))
651
,@(and parents `(:parents ,parents))
652
,@(and short `(:short ,short))
653
,@(and long `(:long ,long))
660
(set-inhibit-warnings ;; implicitly local
661
"theory" "free" "non-rec" "double-rewrite" "subsume" "disable")
664
(cw "~|~%Deflist: attempting to show, using your current theory, ~
665
that ~x0 is always Boolean valued.~%" ',element))
669
:off (acl2::summary acl2::observation)
670
(local (defthm deflist-local-booleanp-element-thm
671
(or (equal ,element t)
672
(equal ,element nil))
673
:rule-classes :type-prescription)))
675
,@(and (not (eq elementp-of-nil :unknown))
677
(cw "~|~%Deflist: attempting to justify, using your ~
678
current theory, :ELEMENTP-OF-NIL ~x0.~%"
684
(local (maybe-defthm-as-rewrite
685
deflist-local-elementp-of-nil-thm
686
(equal (,elementp ,@(subst ''nil x elem-formals))
687
',elementp-of-nil))))))
690
(cw "~|~%Deflist: introducing ~x0 and proving deflist theorems.~%"
695
(local (in-theory (theory 'minimal-theory)))
696
(local (in-theory (enable deflist-support-lemmas
698
(:type-prescription ,name)
699
deflist-local-booleanp-element-thm
701
(local (enable-if-theorem deflist-local-elementp-of-nil-thm))
704
(defthm ,(mksym name '-when-not-consp)
705
(implies (not (consp ,x))
706
(equal (,name ,@formals)
710
:hints(("Goal" :in-theory (enable ,name))))
712
(defthm ,(mksym name '-of-cons)
713
(equal (,name ,@(subst `(cons ,a ,x) x formals))
715
`(not (,elementp ,@(subst a x elem-formals)))
716
`(,elementp ,@(subst a x elem-formals)))
718
:hints(("Goal" :in-theory (enable ,name))))
720
;; Occasionally the user might prove these theorems on his own, e.g.,
721
;; due to a mutual recursion. When this happens, they can end up
722
;; locally DISABLED!!!! because of the theory hint we gave above. So,
723
;; make sure they're explicitly enabled.
724
(local (in-theory (enable ,(mksym name '-when-not-consp)
725
,(mksym name '-of-cons))))
727
(local (in-theory (disable ,name)))
730
`((defthm ,(mksym 'true-listp-when- name)
731
(implies (,name ,@formals)
734
,(if (eql (len formals) 1)
736
;; Unfortunately we can't use a compound recognizer rule
737
;; in this case. I guess we'll try a rewrite rule, even
738
;; though it could get expensive.
740
:hints(("Goal" :induct (len ,x))))
742
(defthm ,(mksym name '-of-list-fix)
743
;; This is not very satisfying. Ideally, ACL2 would
744
;; deeply understand, from the compound-recognizer rule
745
;; showing true-listp when foo-listp, that whenever
746
;; (foo-listp x) holds then (true-listp x) holds.
747
;; Ideally, it could use this knowledge to rewrite
748
;; (list-fix x) to x whenever we can show (foo-listp x).
750
;; But compound recognizers aren't quite good enough for
751
;; this. For instance, ACL2 won't rewrite a term like
752
;; (list-fix (accessor x)) into (accessor x) even if we
753
;; have a rewrite rule that says (foo-listp (accessor x)).
755
;; Some alternatives we considered:
757
;; - A rewrite rule version of (foo-listp x) ==>
758
;; (true-listp x). But it seems like this would get
759
;; *really* expensive when you have 100 list
760
;; recognizers and you encounter a true-listp term.
762
;; - A rewrite rule that rewrites (list-fix x) ==> x when
763
;; (foo-listp x) is known. This might be the right
764
;; compromise. It's at least somewhat less common to
765
;; see list-fix than true-listp. But it still suffers
766
;; from the same kind of scaling problem.
768
;; David's rule, below, is not as powerful as either of
769
;; these approaches, but it at least manages to localize
770
;; the performance impact, and helps at least in some
771
;; cases. Perhaps TAU can somehow help with this in the
773
(implies (,name ,@formals)
774
(,name ,@(subst `(list-fix ,x) x formals))))))
776
(defthm ,(mksym elementp '-when-member-equal-of- name)
777
;; We previously used double-rewrite here, but it interferes with
778
;; free-variable matching
779
(implies (and (,name ,@formals)
780
(member-equal ,a ,x))
781
(equal (,elementp ,@(subst a x elem-formals))
783
:rule-classes ((:rewrite)
786
(implies (and (member-equal ,a ,x)
788
(equal (,elementp ,@(subst a x elem-formals))
792
:in-theory (enable member-equal))))
794
(defthm ,(mksym name '-when-subsetp-equal)
795
;; We previously used double-rewrite here, but it interferes with
796
;; free-variable matching
797
(implies (and (,name ,@(subst y x formals))
798
(subsetp-equal ,x ,y))
799
(equal (,name ,@formals)
803
:rule-classes ((:rewrite)
805
(implies (and (subsetp-equal ,x ,y)
806
(,name ,@(subst y x formals)))
807
(equal (,name ,@formals)
813
:in-theory (enable subsetp-equal ,name)
814
:expand (true-listp ,x)
815
:do-not '(eliminate-destructors))
817
;; Horrible, horrible hack. I found that I couldn't get
818
;; deflist to process ATOM-LISTP because ACL2 knows too much
819
;; about ATOM, so the member-equal rule above ends up being
820
;; no good because it tries to target ATOM instead of CONSP,
821
;; and we get nowhere. Solution: try to explicitly use the
822
;; member rule if we get stuck.
823
(and stable-under-simplificationp
824
'(:in-theory (disable
825
,(mksym elementp '-when-member-equal-of- name))
827
,(mksym elementp '-when-member-equal-of- name)
831
,@(and (not true-listp)
832
;; Awesome set congruence rule for loose recognizers, but not
833
;; a theorem for strict recognizers.
834
`((defthm ,(mksym name '-preserves-set-equiv)
835
(implies (set-equiv ,x ,y)
836
(equal (,name ,@formals)
837
(,name ,@(subst y x formals))))
838
:rule-classes :congruence
840
:in-theory (enable set-equiv)
841
:cases ((,name ,@formals))
842
:do-not-induct t)))))
844
(defthm ,(mksym name '-of-append)
845
(equal (,name ,@(subst `(append ,x ,y) x formals))
846
(and (,name ,@(if true-listp
847
(subst `(list-fix ,x) x formals)
849
(,name ,@(subst y x formals))))
852
:expand (list-fix ,x)
853
:in-theory (enable append))))
856
;; We don't bother proving these for loose recognizers because
857
;; the set-equiv congruence should handle them automatically
858
`((defthm ,(mksym name '-of-rev)
859
(equal (,name ,@(subst `(rev ,x) x formals))
860
(,name ,@(if true-listp
861
(subst `(list-fix ,x) x formals)
865
:expand (list-fix ,x)
866
:in-theory (enable rev))))
868
(defthm ,(mksym name '-of-revappend)
869
(equal (,name ,@(subst `(revappend ,x ,y) x formals))
870
(and (,name ,@(if true-listp
871
(subst `(list-fix ,x) x formals)
873
(,name ,@(subst y x formals))))
875
:induct (revappend ,x ,y)
876
:in-theory (enable revappend))))))
878
(defthm ,(mksym elementp '-of-car-when- name)
880
(,name ,@(subst `(double-rewrite ,x) x formals))
881
(equal (,elementp ,@(subst `(car ,x) x elem-formals))
883
((eq elementp-of-nil nil)
885
;; If x is a cons, then its car is not an element.
886
;; Else its car is nil, which is not an element.
888
;; If x is a cons, then its car is an element.
889
;; Else its car is nil, which is not an element.
891
((eq elementp-of-nil t)
893
;; If x is a cons, then its car is not an element.
894
;; Else its car is nil, which is an element.
896
;; If x is a cons, then its car is an element.
897
;; Else its car is nil, which is an element.
899
(t ;; elementp-of-nil is :unknown
902
(,elementp ,@(subst nil x elem-formals)))))))
904
:in-theory (enable default-car)
905
:expand ((,name . ,formals)))))
907
(defthm ,(mksym name '-of-cdr-when- name)
908
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
909
(equal (,name ,@(subst `(cdr ,x) x formals))
912
(defthm ,(mksym elementp '-of-nth-when- name)
914
(,name ,@(subst `(double-rewrite ,x) x formals))
915
(equal (,elementp ,@(subst `(nth ,n ,x) x formals))
917
((eq elementp-of-nil nil)
919
;; (elementp {e \in X}) = NIL, (elementp nil) = NIL
921
;; (elementp {(e \in X}) = T, (elementp nil) = NIL
922
`(< (nfix ,n) (len ,x))))
923
((eq elementp-of-nil t)
925
;; (elementp {e \in X}) = NIL, (elementp nil) = T
926
`(>= (nfix ,n) (len ,x))
927
;; (elementp {e \in X}) = T, (elementp nil) = T
931
;; (elementp {e \in X}) = NIL, (elementp nil) = ???
932
`(and (,elementp ,@(subst nil x elem-formals))
933
(>= (nfix ,n) (len ,x)))
934
;; (elementp {e \in X}) = T, (elementp nil) = ???
935
`(or (,elementp ,@(subst nil x elem-formals))
936
(< (nfix ,n) (len ,x))))))))
937
:hints(("Goal" :induct (nth ,n ,x))))
939
(defthm ,(mksym name '-of-update-nth-when- elementp)
940
;; 1. When (elementp nil) = NIL, there's a strong bound because if
941
;; you update something past the length of the list, you introduce
942
;; NILs into the list and then ruin foo-listp.
944
;; 2. When (elementp nil) = T, there's no bound because no matter
945
;; whether you add NILs, they're still valid.
947
;; 3. When (elementp nil) = Unknown, we restrict the rule to only
948
;; fire if N is in bounds
949
,(let ((val-okp (if negatedp
950
`(not (,elementp ,@(subst y x elem-formals)))
951
`(,elementp ,@(subst y x elem-formals)))))
952
(cond ((eq elementp-of-nil negatedp)
954
(,name ,@(subst `(double-rewrite ,x) x formals))
955
(equal (,name ,@(subst `(update-nth ,n ,y ,x) x formals))
956
(and (<= (nfix ,n) (len ,x))
958
((eq elementp-of-nil (not negatedp))
960
(,name ,@(subst `(double-rewrite ,x) x formals))
961
(equal (,name ,@(subst `(update-nth ,n ,y ,x) x formals))
965
(and (<= (nfix ,n) (len ,x))
966
(,name ,@(subst `(double-rewrite ,x) x formals)))
967
(equal (,name ,@(subst `(update-nth ,n ,y ,x) x formals))
970
(defthm ,(mksym name '-of-nthcdr)
971
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
972
(equal (,name ,@(subst `(nthcdr ,n ,x) x formals))
974
:hints(("Goal" :do-not-induct t)))
976
(defthm ,(mksym name '-of-take)
978
(,name ,@(subst `(double-rewrite ,x) x formals))
979
(equal (,name ,@(subst `(take ,n ,x) x formals))
981
((eq elementp-of-nil nil)
984
`(<= (nfix ,n) (len ,x))))
985
((eq elementp-of-nil t)
987
`(<= (nfix ,n) (len ,x))
991
`(or (not (,elementp ,@(subst nil x elem-formals)))
992
(<= (nfix ,n) (len ,x)))
993
`(or (,elementp ,@(subst nil x elem-formals))
994
(<= (nfix ,n) (len ,x))))))))
996
:in-theory (enable acl2::take-redefinition)
998
:expand ((,name ,@formals)
1000
(,name ,@(subst `(cons ,x ,y) x formals)))))))
1002
(defthm ,(mksym name '-of-replicate)
1003
(equal (,name ,@(subst `(replicate ,n ,x) x formals))
1004
(or ,(cond (negatedp
1005
`(not (,elementp ,@formals)))
1007
`(,elementp ,@formals)))
1010
:induct (replicate ,n ,x)
1011
:in-theory (enable replicate deflist-local-booleanp-element-thm)
1012
:expand ((,name ,@formals)
1014
(,name ,@(subst `(cons ,x ,y) x formals)))))))
1016
(defthm ,(mksym name '-of-last)
1017
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1018
(equal (,name ,@(subst `(last ,x) x formals))
1020
:hints(("Goal" :do-not-induct t)))
1022
(defthm ,(mksym name '-of-butlast)
1023
;; Historically this was much more complicated, but after Matt
1024
;; fixed up butlast to not be totally crazy in the -N case
1025
;; (introduce NILs, etc.) it simplifies down nicely.
1026
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1027
(equal (,name ,@(subst `(butlast ,x ,n) x formals))
1029
:hints(("Goal" :do-not-induct t)))
1031
(defthm ,(mksym name '-of-rcons)
1032
(equal (,name ,@(subst `(rcons ,a ,x) x formals))
1034
`(not (,elementp ,@(subst a x elem-formals)))
1035
`(,elementp ,@(subst a x elem-formals)))
1036
(,name ,@(if true-listp
1037
(subst `(list-fix ,x) x formals)
1039
:hints(("Goal" :in-theory (enable rcons))))
1041
(defthm ,(mksym name '-of-duplicated-members)
1042
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1043
(equal (,name ,@(subst `(duplicated-members ,x) x formals))
1045
:hints(("Goal" :do-not-induct t)))
1047
(defthm ,(mksym name '-of-set-difference-equal)
1048
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1049
(equal (,name ,@(subst `(set-difference-equal ,x ,y) x formals))
1051
:hints(("Goal" :do-not-induct t)))
1053
(defthm ,(mksym name '-of-intersection-equal-1)
1054
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1055
(equal (,name ,@(subst `(intersection-equal ,x ,y) x formals))
1057
:hints(("Goal" :do-not-induct t)))
1059
(defthm ,(mksym name '-of-intersection-equal-2)
1060
(implies (,name ,@(subst `(double-rewrite ,y) x formals))
1061
(equal (,name ,@(subst `(intersection-equal ,x ,y) x formals))
1063
:hints(("Goal" :do-not-induct t)))
1065
(defthm ,(mksym name '-of-sfix)
1066
;; This rule is important for set::under-set-equiv rules to work
1067
;; right in the context of a foo-listp.
1068
(implies (,name ,@(subst `(double-rewrite ,x) x formals))
1069
(equal (,name ,@(subst `(sfix ,x) x formals))
1073
:cases ((setp ,x)))))
1076
;; These aren't needed in the non true-listp case, because set
1077
;; reasoning will reduce them to, e.g., append,
1078
;; set-difference-equal, intersection-equal, etc.
1079
`((defthm ,(mksym name '-of-union-equal)
1080
(equal (,name ,@(subst `(union-equal ,x ,y) x formals))
1081
(and (,name ,@(subst `(list-fix ,x) x formals))
1082
(,name ,@(subst `(double-rewrite ,y) x formals))))
1085
:in-theory (enable union-equal))))
1087
(defthm ,(mksym name '-of-difference)
1088
(implies (,name ,@formals)
1089
(equal (,name ,@(subst `(difference ,x ,y) x formals))
1091
:hints(("Goal" :do-not-induct t)))
1093
(defthm ,(mksym name '-of-intersect-1)
1094
(implies (,name ,@formals)
1095
(equal (,name ,@(subst `(intersect ,x ,y) x formals))
1097
:hints(("Goal" :do-not-induct t)))
1099
(defthm ,(mksym name '-of-intersect-2)
1100
(implies (,name ,@(subst y x formals))
1101
(equal (,name ,@(subst `(intersect ,x ,y) x formals))
1103
:hints(("Goal" :do-not-induct t)))
1105
(defthm ,(mksym name '-of-mergesort)
1106
(equal (,name ,@(subst `(mergesort ,x) x formals))
1107
(,name ,@(subst `(list-fix ,x) x formals)))
1110
:in-theory (disable ,(mksym name '-when-subsetp-equal))
1111
:use ((:instance ,(mksym name '-when-subsetp-equal)
1114
(:instance ,(mksym name '-when-subsetp-equal)
1116
(,x (list-fix ,x)))))))
1119
(defthm ,(mksym name '-of-union-lemma-1)
1120
(implies (,name ,@(subst `(union ,x ,y) x formals))
1121
(and (,name ,@(subst `(sfix ,x) x formals))
1122
(,name ,@(subst `(sfix ,y) x formals))))
1123
:hints(("Goal" :do-not-induct t))))
1126
(defthm ,(mksym name '-of-union-lemma-2)
1127
(implies (and (,name ,@(subst `(sfix ,x) x formals))
1128
(,name ,@(subst `(sfix ,y) x formals)))
1129
(,name ,@(subst `(union ,x ,y) x formals)))
1132
:in-theory (disable set::union-under-set-equiv
1133
deflist-lemma-subsetp-of-union)
1134
:use ((:instance deflist-lemma-subsetp-of-union
1138
(defthm ,(mksym name '-of-union)
1139
(equal (,name ,@(subst `(union ,x ,y) x formals))
1140
(and (,name ,@(subst `(sfix ,x) x formals))
1141
(,name ,@(subst `(sfix ,y) x formals))))
1143
:cases ((,name ,@(subst `(union ,x ,y) x formals)))
1150
,@(and parents `(:parents ,parents))
1151
,@(and short `(:short ,short))
1152
,@(and long `(:long ,long))
1153
;; keep all our deflist theory stuff bottled up. BOZO encapsulate is
1154
;; slow, better to use a progn here
1157
;; now do the rest of the events with name enabled, so they get included
1160
`((value-triple (cw "Deflist: submitting /// events.~%"))
1164
(local (in-theory (enable ,name)))
1168
(defmacro deflist (name &rest args)
1169
(b* ((__function__ 'deflist)
1170
((unless (symbolp name))
1171
(raise "Name must be a symbol."))
1172
(ctx (list 'deflist name))
1173
((mv main-stuff other-events) (split-/// ctx args))
1174
((mv kwd-alist formals-elem)
1175
(extract-keywords ctx *deflist-valid-keywords* main-stuff nil))
1176
((unless (tuplep 2 formals-elem))
1177
(raise "Wrong number of arguments to deflist."))
1178
((list formals element) formals-elem)
1179
(verbosep (getarg :verbosep nil kwd-alist)))
1184
'(:gag-mode t :off (acl2::summary
1190
`(progn ,(deflist-fn ',name ',formals ',element ',kwd-alist
1191
',other-events state)
1192
(value-triple '(deflist ,',name)))))))