我想告诉sbcl只能使用fixnum值调用以下函数,其结果适合fixnum:
(defun layer (x y z n)
(+ (* 2 (+ (* x y) (* y z) (* x z)))
(* 4 (+ x y z n -2) (1- n))))
Run Code Online (Sandbox Code Playgroud)
我的第一次尝试就是这样做
(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))))
Run Code Online (Sandbox Code Playgroud)
但是,返回类型声明并不保证所有中间结果也将是fixnums,正如我通过查看sbcl产生的非常有用的编译说明所发现的那样.那么我这样做了:
(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)))))
Run Code Online (Sandbox Code Playgroud)
这工作得很好.我的问题是:是否有更简单,更惯用的方式来做到这一点?
例如,也许我可以重新声明+, - ,*,1-的类型以承诺fixnum结果?(我知道这通常是一个坏主意,但我可能想在某些程序中这样做.)CHICKEN方案有(declare (fixnum-arithmetic))我想做的事情:它(不安全)假设fixnums上的所有算术运算的结果都是fixnums.
您可以使用FTYPE声明函数的类型.
例:
(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))))
Run Code Online (Sandbox Code Playgroud)
这有什么区别吗?
在他的书"ANSI Common Lisp"中,Paul Graham展示了宏with-type,它将表达式及其所有子表达式包装在the表单中,同时确保给出两个以上参数的运算符得到正确处理.
例如,(with-type fixnum (+ 1 2 3))将扩展到表单
(the fixnum (+ (the fixnum (+ (the fixnum 1) (the fixnum 2)))
(the fixnum 3))
Run Code Online (Sandbox Code Playgroud)
具有辅助函数的宏的代码是
(defmacro with-type (type expr)
`(the ,type ,(if (atom expr)
expr
(expand-call type (binarize expr)))))
(defun expand-call (type expr)
`(,(car expr) ,@(mapcar #'(lambda (a)
`(with-type ,type ,a))
(cdr expr))))
(defun binarize (expr)
(if (and (nthcdr 3 expr)
(member (car expr) '(+ - * /)))
(destructuring-bind (op a1 a2 . rest) expr
(binarize `(,op (,op ,a1 ,a2) ,@rest)))
expr))
Run Code Online (Sandbox Code Playgroud)
http://www.paulgraham.com/acl.html上的书籍代码链接
代码中的注释声明"此代码是Paul Graham 1995年版权所有,但任何想要使用它的人都可以免费使用."