在sbcl类型声明中使用异或

时间:2019-01-22 14:20:06

标签: common-lisp sbcl

对于像这样的功能

(defun test (x y)
   (declare (optimize (speed  3)))
   (< x y))

我看到一个包含以下内容的警告:

note: 
unable to
  open-code FLOAT to RATIONAL comparison
due to type uncertainty:
  The first argument is a REAL, not a FLOAT.
  The second argument is a REAL, not a RATIONAL.

如果我知道这两个参数都将是RATIONAL xor FLOAT,那么是否可以为此向sbcl提供声明提示?

2 个答案:

答案 0 :(得分:5)

您不能在类型之间声明这种类型的关系,但是您可以定义一些辅助函数,在这些辅助函数中声明类型但不检查类型:

(macrolet ((defexpansion (name type)
             `(progn
                (declaim (inline ,name))
                (defun ,name (x y)
                  (declare (type ,type x y)
                           (optimize (safety 1)
                                     (speed 3)))
                  (< x y)))))
  (defexpansion test-fixnum fixnum)
  (defexpansion test-float float)
  (defexpansion test-rational rational))

然后,您只需要对第一个参数进行类型检查,因为您知道,第二个参数必须具有相同的类型(这就是声明的内容,因此您要求编译器信任您)。

(defun test (x y)
  (etypecase x
    (float (test-float x y))
    (fixnum (test-fixnum x y))
    (rational (test-rational x y))))

答案 1 :(得分:4)

您可以为sbcl提供一些有关数据类型的信息:

(defun test (x y)
  (declare (optimize (speed  3))
           (type rational x y))
  (< x y))

您应该决定是否可以在所有情况下分辨xy的类型。

您可以在hyperspec和sbcl的manual中找到有关类型声明的更多信息。

编辑

我完全不知道这是否有意义,但可以考虑另一层来决定调用哪个函数:

(defun test% (x y)
  (declare (optimize (speed  3)))
  (if (and (typep x 'rational) (typep y 'rational))
      (test-rational x y)
      (test-float x y)))

(defun test-rational (x y)
  (declare (optimize (speed  3))
           (type rational x y))
  (< x y))

(defun test-float (x y)
  (declare (optimize (speed  3))
           (type float x y))
  (< x y))

我认为使用typecase或使用CLOS为每种类型定义方法还有进一步优化的空间。