Avoiding expensive guard checks using program-mode functions
Application programs can benefit from avoiding expensive guard checks. Imagine that
The following contrived example shows how to avoid that guard check by
using a program-mode wrapper: a function in program mode that
calls the intended function directly. The example below illustrates that idea
by defining
(defun fib (n) ; Fibonacci function, just for an example of slow computation (declare (xargs :guard (natp n))) (if (zp n) 0 (if (eql n 1) 1 (+ (fib (- n 1)) (fib (- n 2)))))) (defun expensive-guard-fn (n) (declare (xargs :guard t)) (and (natp n) (natp (fib n)))) (defun expensive-fn (n) (declare (xargs :guard (expensive-guard-fn n))) (* 2 n)) ; The following may take about a second, virtually all in the guard check. (time$ (expensive-fn 40)) (defun expensive-fn-wrapper (n) (declare (xargs :mode :program)) (expensive-fn n)) ; The following is virtually instantaneous. (time$ (expensive-fn-wrapper 40))
This trick isn't necessary if your function call is made on behalf of a superior call of a function that is guard-verified (or in program mode, since that essentially brings us back to the wrapper situation). Consider the following definition, building on the example above.
(defun f (n) (declare (xargs :guard (natp n))) (expensive-fn n)) ; The following is virtually instantaneous. (time$ (f 40))
Then evaluation of
; Define a logic-mode function that is not guard-verified: (defun g (n) (expensive-fn n)) ; The following may take about a second, virtually all in the guard check. (time$ (g 40))
Remark. This trick may be less effective if you see an