/usr/share/acl2-8.0dfsg/books/misc/defun-plus.lisp is in acl2-books-source 8.0dfsg-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 | (in-package "ACL2")
;; Copyright Nathan Wetzler and David Rager.
;; ============================================================================
;; Introductions
;;
;; This file defines defun+, which is a macro for defun that allows the user to
;; specify an "output signature" as part of a function's definition. It works
;; by defining the function as if the output signature did not exist, and then
;; defining a theorem that describes the value[s] returned by calling the
;; function. The user may optionally pass in an argument :disable, which
;; indicates whether the function should be disabled after the theorem stating
;; the output type is proved.
;;
;; See the end of the file for ideas on how to further extend defun+.
;; ============================================================================
;; ============================================================================
;; The following definitions related to gathering declarations are taken from
;; the ACL2 source code. The only changes (as of August 2012) is the removal
;; of the guards and defining these functions in program mode. These changes
;; are necessary, because :output is not one of the fields allowed in an xargs
;; declaration, as tested by ACL2 function plausible-dclsp.
;; ============================================================================
(defun strip-dcls-program-mode1 (fields lst)
(declare (xargs :mode :program))
(cond ((endp lst) nil)
((member-eq (caar lst) '(type ignore ignorable))
(cond ((member-eq (caar lst) fields)
(strip-dcls-program-mode1 fields (cdr lst)))
(t (cons (car lst) (strip-dcls-program-mode1 fields (cdr lst))))))
(t
(let ((temp (strip-keyword-list fields (cdar lst))))
(cond ((null temp) (strip-dcls-program-mode1 fields (cdr lst)))
(t (cons (cons 'xargs temp)
(strip-dcls-program-mode1 fields (cdr lst)))))))))
(defun strip-dcls-program-mode (fields lst)
(declare (xargs :mode :program))
(cond ((endp lst) nil)
((stringp (car lst))
(cond ((member-eq 'comment fields)
(strip-dcls-program-mode fields (cdr lst)))
(t (cons (car lst)
(strip-dcls-program-mode fields (cdr lst))))))
(t (let ((temp (strip-dcls-program-mode1 fields (cdar lst))))
(cond ((null temp) (strip-dcls-program-mode fields (cdr lst)))
(t (cons (cons 'declare temp)
(strip-dcls-program-mode fields (cdr lst)))))))))
(defun fetch-dcl-fields-program-mode2 (field-names kwd-list acc)
(declare (xargs :mode :program))
(cond ((endp kwd-list) acc)
(t (let ((acc (fetch-dcl-fields-program-mode2 field-names
(cddr kwd-list)
acc)))
(if (member-eq (car kwd-list) field-names)
(cons (cadr kwd-list) acc)
acc)))))
(defun fetch-dcl-fields-program-mode1 (field-names lst)
(declare (xargs :mode :program))
(cond ((endp lst) nil)
((member-eq (caar lst) '(type ignore ignorable))
(if (member-eq (caar lst) field-names)
(cons (cdar lst)
(fetch-dcl-fields-program-mode1 field-names (cdr lst)))
(fetch-dcl-fields-program-mode1 field-names (cdr lst))))
(t (fetch-dcl-fields-program-mode2 field-names
(cdar lst)
(fetch-dcl-fields-program-mode1
field-names
(cdr lst))))))
(defun fetch-dcl-fields-program-mode (field-names lst)
(declare (xargs :mode :program))
(cond ((endp lst) nil)
((stringp (car lst))
(if (member-eq 'comment field-names)
(cons (car lst)
(fetch-dcl-fields-program-mode field-names (cdr lst)))
(fetch-dcl-fields-program-mode field-names (cdr lst))))
(t (append (fetch-dcl-fields-program-mode1 field-names (cdar lst))
(fetch-dcl-fields-program-mode field-names (cdr lst))))))
(defun fetch-dcl-field-program-mode (field-name lst)
(declare (xargs :mode :program))
(fetch-dcl-fields-program-mode (list field-name) lst))
;; ============================================================================
;; Some (more) helper functions for defun+
;; ============================================================================
(defun generate-output-lemma-name (name number)
(if (not number)
(intern-in-package-of-symbol
(concatenate 'string (symbol-name name)
"-OUTPUT-LEMMA")
name)
(intern-in-package-of-symbol
(concatenate 'string (symbol-name name)
"-OUTPUT-LEMMA-"
(coerce (explode-atom number 10)
'string))
name)))
(defun generate-output-lemma-single (name guards output output-hints)
`((defthm ,(generate-output-lemma-name name nil)
(implies ,guards
,output)
:hints ,output-hints)))
(defun generate-output-lemma-multiple (name guards output number)
(if (atom output)
nil
(cons `(defthm ,(generate-output-lemma-name name number)
(implies ,guards
,(car output)))
(generate-output-lemma-multiple name
guards
(cdr output)
(1+ number)))))
(defun generate-output-lemmas (name guards output output-hints)
(if (not (equal (car output) 'and))
(generate-output-lemma-single name guards output output-hints)
(generate-output-lemma-multiple name guards (cdr output) 1)))
;; ============================================================================
;; Definition of defun+
;; ============================================================================
(defmacro defun+ (name formals dcl body &key disable)
(let* ((guards (car (fetch-dcl-field-program-mode :guard (list dcl))))
(output (car (fetch-dcl-field-program-mode :output (list dcl))))
(output-hints (car (fetch-dcl-field-program-mode :output-hints (list dcl))))
(new-dcls (car (strip-dcls-program-mode '(:output) (list dcl))))
(new-dcls (car (strip-dcls-program-mode '(:output-hints) (list new-dcls)))))
`(progn
(defun ,name ,formals ,new-dcls ,body)
,@(if output
(generate-output-lemmas name guards output output-hints)
`((value-triple nil)))
,(if disable
`(in-theory (disable ,name))
'(value-triple nil)))))
;; ============================================================================
;; Some examples
;; ============================================================================
(local
(defun+ baz (x y z)
(declare (xargs :guard (and (integerp x)
(integerp y)
(integerp z))
:output (integerp (baz x y z))))
(+ x y z)))
(local
(defun+ baz (x y z)
(declare (xargs :guard (and (integerp x)
(integerp y)
(integerp z))
:output (integerp (baz x y z))
:output-hints (("Goal" :do-not-induct t))))
(+ x y z)))
(local
(defun+ faz (x y z)
(declare (xargs :guard (and (integerp x)
(integerp y)
(integerp z))
:output (integerp (faz x y z))))
(+ x y z)
:disable t))
(local
(defun+ foo (x y)
(declare (xargs :guard (and (integerp x) (integerp y))
:output (and (equal (mv-nth 0 (foo x y)) 0)
(integerp (mv-nth 1 (foo x y))))))
(mv 0 (+ x y))
:disable t))
;; ============================================================================
;; It would be nice to automatically generate lemmas about the functions. For
;; example, it might be nice to define opener lemmas that hinge off the input
;; to a recursive function being a consp. However, we think we could have a
;; more general approach to automatically generating lemmas. As such, for now,
;; we leave the use of this code disabled.
;; ============================================================================
#||
(defmacro generate-lemma-names (fn1 fn2 &optional car-cdr)
`(intern-in-package-of-symbol
(concatenate 'string
(symbol-name ,fn1)
"-IMPLIES-"
(symbol-name ,fn2)
(if ,car-cdr
(concatenate 'string "-" (symbol-name ,car-cdr))
""))
,fn1))
(defun generate-lemmas (name formals guards body)
(declare (ignore formals guards))
(case-match body
(('if ('atom x)
tbr
(and (fbr-car ('car x))
(!name ('cdr x))))
(list `(defthm ,(generate-lemma-names name fbr-car 'car)
(implies (and (,name ,x)
(consp ,x))
(,fbr-car (car ,x))))
`(defthm ,(generate-lemma-names name name 'cdr)
(implies (and (,name ,x)
(consp ,x))
(,name (cdr ,x))))))
(& nil)))
(generate-lemmas 'foo
nil
nil
'(if (atom x)
(null x)
(and (bar (car x))
(foo (cdr x)))))
(defmacro defun+ (name formals dcl body &key disable generate-lemmas)
(let* ((guards (car (fetch-dcl-field-program-mode :guard (list dcl))))
(output (car (fetch-dcl-field-program-mode :output (list dcl))))
(new-dcls (car (strip-dcls-program-mode '(:output) (list dcl)))))
`(progn
(defun ,name ,formals ,new-dcls ,body)
,@(if output
(generate-output-lemmas name guards output)
`((value-triple nil)))
,@(if generate-lemmas
(generate-lemmas name formals guards body)
`((value-triple nil)))
,(if disable
`(in-theory (disable ,name))
'(value-triple nil)))))
(defun barp (x) (declare (xargs :guard t)) (integerp x))
(defun+ foop (x)
(declare (xargs :guard t))
(if (atom x)
(null x)
(and (barp (car x))
(foop (cdr x))))
:generate-lemmas t)
||#
;; ============================================================================
;; Here are a couple more ideas on how to improve defun+.
;; Add some output to defun+ (and also suppress some of the output) that tells
;; the user the definitions of the lemmas that were produced.
;; Potentially add symbols to output lemma names so that users can quickly
;; identify when the output lemmas are being used by viewing the summary of a
;; proof attempt. We are uncertain of the consequences of having the output
;; rules automatically generated, so having this extra mechanism for flagging
;; the automatic use of these lemmas, would help us figure out whether they can
;; cause problems.
;; Come up with a way of allowing hints for the output lemmas when there is
;; more than one output lemma.
;; ============================================================================
|