other
(in-package "ACL2S")
other
(include-book "defunc" :ttags :all)
map-predsfunction
(defun map-preds (types tbl atbl) (declare (xargs :guard (and (symbol-listp types) (sym-aalistp tbl) (sym-aalistp atbl)))) (if (endp types) nil (cons (pred-of-type (car types) tbl atbl) (map-preds (rest types) tbl atbl))))
map-intern-typefunction
(defun map-intern-type (type pkg) (declare (xargs :guard (and (symbolp type) (pkgp pkg)))) (if (keywordp type) (fix-intern$ (symbol-name type) pkg) type))
map-intern-typesfunction
(defun map-intern-types (types pkg) (declare (xargs :guard (and (symbol-listp types) (pkgp pkg)))) (if (endp types) nil (cons (map-intern-type (car types) pkg) (map-intern-types (rest types) pkg))))
make-input-contract-auxfunction
(defun make-input-contract-aux (args types) (declare (xargs :guard (and (symbol-listp args) (symbol-listp types)))) (cond ((endp args) nil) ((equal (car types) 'allp) (make-input-contract-aux (rest args) (rest types))) (t (cons `(,(CAR ACL2S::TYPES) ,(CAR ACL2S::ARGS)) (make-input-contract-aux (rest args) (rest types))))))
make-input-contractfunction
(defun make-input-contract (args types) (declare (xargs :guard (and (symbol-listp args) (symbol-listp types)))) (let ((res (make-input-contract-aux args types))) (cond ((endp res) t) ((equal (len res) 1) (first res)) (t (cons 'and res)))))
find-bad-d-arg-typesfunction
(defun find-bad-d-arg-types (d-arg-types d-arg-preds) (cond ((endp d-arg-preds) nil) ((null (car d-arg-preds)) (car d-arg-types)) (t (find-bad-d-arg-types (cdr d-arg-types) (cdr d-arg-preds)))))
find-next-typefunction
(defun find-next-type (var l acc) (cond ((endp l) acc) ((keywordp (car l)) (find-next-type var (cdr l) (cons (car l) (cons var acc)))) ((endp acc) (find-next-type var (cdr l) acc)) (t acc)))
process-typed-args-auxfunction
(defun process-typed-args-aux (l acc) (cond ((endp l) (rev acc)) ((keywordp (car l)) (process-typed-args-aux (cdr l) acc)) (t (process-typed-args-aux (cdr l) (append (find-next-type (car l) (cdr l) nil) acc)))))
process-typed-argsfunction
(defun process-typed-args (l) (process-typed-args-aux l nil))
skip-keywordsfunction
(defun skip-keywords (l) (cond ((endp l) l) ((keywordp (car l)) (skip-keywords (cdr l))) (t l)))
proper-argspfunction
(defun proper-argsp (l) (or (endp l) (and (consp (cdr l)) (legal-variablep (first l)) (if (keywordp (second l)) (proper-argsp (skip-keywords (cddr l))) (proper-argsp (cdr l))))))
definec-coremacro
(defmacro definec-core (name d? &rest args) `(with-output :stack :push :off :all :on (error comment) (make-event (b* ((tbl (table-alist 'type-metadata-table (w state))) (atbl (table-alist 'type-alias-table (w state))) (pkg (current-package state)) (name ',ACL2S::NAME) (d? ',ACL2S::D?) (args ',ACL2S::ARGS) (f-args (car args)) ((unless (proper-argsp f-args)) (er hard 'definec "~%The arguments to ~x0 are not well formed. See the documentation for example arguments: ~x1" name f-args)) (f-argsp (process-typed-args f-args)) (f-type (map-intern-type (second args) pkg)) (d-args (evens f-argsp)) (def-args (remove-duplicates d-args)) (d-arg-types (odds f-argsp)) (d-arg-types (map-intern-types d-arg-types pkg)) (d-arg-preds (map-preds d-arg-types tbl atbl)) (pred (pred-of-type f-type tbl atbl)) (ic (make-input-contract d-args d-arg-preds)) (oc (make-contract name def-args pred)) (defunc `(defunc-core ,ACL2S::NAME ,ACL2S::D? ,ACL2S::DEF-ARGS :input-contract ,ACL2S::IC :output-contract ,ACL2S::OC ,@(CDDR ACL2S::ARGS))) (bad-type (find-bad-d-arg-types d-arg-types d-arg-preds)) ((when bad-type) (er hard 'definec "~%One of the argument types, ~x0, is not a type." bad-type)) ((unless pred) (er hard 'definec "~%The given return type, ~x0, is not a known type." f-type))) `(with-output :stack :pop ,ACL2S::DEFUNC)))))
definecmacro
(defmacro definec (name &rest args) `(definec-core ,ACL2S::NAME nil ,@ACL2S::ARGS))
definedcmacro
(defmacro definedc (name &rest args) `(definec-core ,ACL2S::NAME t ,@ACL2S::ARGS))
other
(include-book "xdoc/top" :dir :system)
other
(defxdoc definec :parents (acl2-sedan macro-libraries defunc) :short "Function definitions with contracts extending @(see defunc)." :long " <h3>Examples</h3> @({ (definec my-len (a :all) :nat (if (atom a) 0 (+ 1 (my-len (rest a))))) ; An alternate, but equivalent, definition of my-len (definec my-len (a :all) :nat (match a (:atom 0) ((& . r) (1+ (my-len r))))) ; Notice that both x and y are nats (definec f (x y :nat) :nat (+ x y)) ; Both x and y are true-lists (definec my-app (x y :tl) :tl (match x (nil y) ((f . r) (cons f (my-app r y))))) ; All is the universal type (definec my-atom (x :all) :bool (atom x)) ; Factorial (definec my-fact (x :nat) :pos (match x ((:or 0 1) 1) (& (* x (my-fact (1- x)))))) ; list-sum (definec list-sum (l :rational-list) :rational (match l (nil 0) ((f . r) (+ f (list-sum r))))) ; Average: notice that l is a both a rational-list and a cons (definec average (l :rational-list :cons) :rational (/ (list-sum l) (len l))) ; Square a list, with some extra keyword arguments (definec square-list (l :nat-list) :nat-list (match l (nil nil) ((f . r) (app (list (* f f)) (square-list r)))) :verbose t :skip-tests t) }) <h3>Purpose</h3> <p> The macro @(see definec) is an extension of @(see defunc) that makes it more convient to specify simple contracts. For example, the expansion of </p> @({ (definec f (x y :nat) :nat (+ x y)) }) <p> includes the following events. </p> @({ (defunc f (x y) :input-contract (and (natp x) (natp y)) :output-contract (natp (f x y)) (+ x y)) (defthm f-definec-fc-rule (implies (force (and (natp x) (natp y))) (natp (f x y))) :rule-classes ((:forward-chaining :trigger-terms ((f x y))))) }) <p> Notice that nat was turned into natp. We convert type names into the corresponding predicates using @(see defdata) and we support :all (the type of the ACL2 universe), :tl (the type of true-lists), :int (the type of integers), :bool (the type of booleans) and all other types @(see defdata) knows. </p> <p> When specifying types one must use keywords, as shown above. It is important to put a space between the variable name and the type, e.g., x:nat will lead to errors. </p> <p> As the examples above show, the parameter types and the return type are used to generate @(see defunc) contracts and then the rest of the arguments are passed to @(see defunc), so you can use all the bells and whistles of @(see defunc). </p> ")
definecdmacro
(defmacro definecd (name &rest args) `(with-output :off :all :on (error) :stack :push (encapsulate nil (with-output :stack :pop (definec ,ACL2S::NAME ,@ACL2S::ARGS)) (make-event `(with-output :off :all :on (summary) :summary-off (:other-than form) (in-theory (disable ,(ACL2S::MAKE-SYMBL `(,',ACL2S::NAME ACL2S::-DEFINITION-RULE) (ACL2S::CURRENT-PACKAGE ACL2S::STATE)))))))))
definedcdmacro
(defmacro definedcd (name &rest args) `(with-output :off :all :on (error) :stack :push (encapsulate nil (with-output :stack :pop (definedc ,ACL2S::NAME ,@ACL2S::ARGS)) (make-event `(with-output :off :all :on (summary) :summary-off (:other-than form) (in-theory (disable ,(ACL2S::MAKE-SYMBL `(,',ACL2S::NAME ACL2S::-DEFINITION-RULE) (ACL2S::CURRENT-PACKAGE ACL2S::STATE)))))))))
definec-no-testmacro
(defmacro definec-no-test (name &rest args) `(gen-acl2s-local testing-enabled nil ((definec ,ACL2S::NAME ,@ACL2S::ARGS))))
definecd-no-testmacro
(defmacro definecd-no-test (name &rest args) `(gen-acl2s-local testing-enabled nil ((definecd ,ACL2S::NAME ,@ACL2S::ARGS))))
definedc-no-testmacro
(defmacro definedc-no-test (name &rest args) `(gen-acl2s-local testing-enabled nil ((definedc ,ACL2S::NAME ,@ACL2S::ARGS))))
definedcd-no-testmacro
(defmacro definedcd-no-test (name &rest args) `(gen-acl2s-local testing-enabled nil ((definedcd ,ACL2S::NAME ,@ACL2S::ARGS))))