承诺Common Lisp编译器的最简单方法是算术表达式的结果是fixnum?

Oma*_*ena 7 common-lisp

我想告诉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.

Rai*_*wig 9

您可以使用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)

这有什么区别吗?

  • 哇,我从未见过像这样使用内联!干杯 (2认同)

Ter*_* D. 6

在他的书"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年版权所有,但任何想要使用它的人都可以免费使用."