What is the easiest way to promise a Common Lisp compiler that the result of an arithmetic expression is a fixnum?

common-lisp

Solution

You can declare types for functions using FTYPE.

Example:

(defun foo (a b)
  (declare (ftype (function (&rest fixnum) fixnum) + * 1-)
           (type fixnum a b)
           (inline + * 1-)
           (optimize (speed 3) (safety 0) (debug 0) (space 0)))
  (+ a (* a (1- b))))

Does that make a difference?

Problem

I wanted to tell sbcl that the following function will only be called with fixnum values for which the result fits in a fixnum: ``` (defun layer (x y z n) (+ (* 2 (+ (* x y) (* y z) (* x z))) (* 4 (+ x y z n -2) (1- n)))) ``` My first attempt was to do ``` (defun layer (x y z n) (declare (fixnum x y z n)) (the fixnum (+ (* 2 (+ (* x y) (* y z) (* x z))) (* 4 (+ x y z n -2) (1- n)))) ``` But that return type declaration doesn't promise that all intermediate results will also be fixnums, as I found out by looking at the wonderfully useful compilation notes sbcl produced. So then I did this: ``` (defmacro fixnum+ (&rest args) (reduce (lambda (x y) `(the fixnum (+ ,x ,y))) args)) (defmacro fixnum* (&rest args) (reduce (lambda (x y) `(the fixnum (* ,x ,y))) args)) (defun layer (x y z n) (declare (fixnum x y z n)) (fixnum+ (fixnum* 2 (fixnum+ (fixnum* x y) (fixnum* y z) (fixnum* x z))) (fixnum* 4 (fixnum+ x y z n -2) (the fixnum (1- n))))) ``` And that worked just fine. My question is: is there an easier, more idiomatic way to do this? For example, maybe I can redeclare the types of +, -, *, 1- to promise fixnum results? (I know that's a bad idea in general, but I might want to do it in certain programs.) CHICKEN scheme has `(declare (fixnum-arithmetic))` that does what I want: it (unsafely) assumes that the results of all arithmetic operations on fixnums are fixnums.

Original source