I know you can declare function parameter types like
(defun add-integer (a b)
(declare (integer a b))
(the integer (+ a b)))
But what about DO variables? For example, I want to type passes
:
(defun bench ()
(do ((end (+ (get-internal-real-time) (* 5 internal-time-units-per-second)))
(passes 0 (+ 1 passes)))
((> (get-internal-real-time) end)
passes)
(sieve 1000000)))
When I try to compile with (declaim (optimize (speed 2) (safety 0)))
, I get
; in: DEFUN BENCH
; (1+ PASSES)
;
; note: forced to do full call
; unable to do inline fixnum arithmetic (cost 2) because:
; The first argument is a UNSIGNED-BYTE, not a FIXNUM.
; The result is a (VALUES (INTEGER 1) &OPTIONAL), not a (VALUES FIXNUM
; &REST T).
; unable to do inline (unsigned-byte 64) arithmetic (cost 5) because:
; The first argument is a UNSIGNED-BYTE, not a (UNSIGNED-BYTE 64).
; The result is a (VALUES (INTEGER 1) &OPTIONAL), not a (VALUES
; (UNSIGNED-BYTE 64)
; &REST T).
I tried
(defun bench ()
(declare (type (unsigned-byte 64) passes))
(do ((end (+ (get-internal-real-time) (* 5 internal-time-units-per-second)))
(passes 0 (+ 1 passes)))
((> (get-internal-real-time) end)
passes)
(sieve 1000000)))
But then I get
; Undefined variable:
; PASSES
I cannot find anything on this in the type chapters of the HyperSpec, e.g. (http://clhs.lisp.se/Body/04_bc.htm). A working example would be extremely helpful! Thanks!
You put the declaration at the beginning of the loop body.
(defun bench ()
(do ((end (+ (get-internal-real-time) (* 5 internal-time-units-per-second)))
(passes 0 (+ 1 passes)))
((> (get-internal-real-time) end)
passes)
(declare (type (unsigned-byte 64) passes))
(sieve 1000000)))
This is shown in the specification of DO
:
do ({var | (var [init-form [step-form]])}*) (end-test-form result-form*) declaration* {tag | statement}*
See declaration
after (end-test-form result-form*)