是否可以在 SBCL/Common Lisp 中在运行时检查/获取函数类型或其签名?

Jon*_*Yun 5 lisp types runtime function common-lisp

(deftype binary-number-func ()
  `(function (number number) number))

(declaim (ftype binary-number-func my-add))
(defun my-add (a b)
  (+ (the number a) (the number b)))

;; FAIL:
(assert (typep #'my-add 'binary-number-func))
;; Function types are not a legal argument to TYPEP:
;;  (FUNCTION (NUMBER NUMBER) (VALUES NUMBER &REST T))
;;   [Condition of type SIMPLE-ERROR]

;; FAIL:
(typep #'my-add '(function (number number) number))
;; Function types are not a legal argument to TYPEP:
;;   (FUNCTION (NUMBER NUMBER) (VALUES NUMBER &REST T))
;;    [Condition of type SIMPLE-ERROR]

Run Code Online (Sandbox Code Playgroud)

有没有办法检查函数值的复合类型?(在 Common Lisp 中,我使用 SBCL sbcl-1.5.0-x86-64-linux)

提前致谢。

Dan*_*son 4

由于 Common Lisp 允许您编写函数,即使编译器无法确定函数的最小函数类型,因此编译器并不总是能够检查函数是否具有特定类型。因此,唯一明智的行为是不检查类型。

\n\n

其次,这样的最小类型可能不存在。考虑这个函数:

\n\n
(defun foo (key)\n  (getf '(:red 1 :blue 2 :green 3 :yellow 4) key))\n
Run Code Online (Sandbox Code Playgroud)\n\n

它有类型(function (T) T)(function (T) (or null (integer 1 4)))(function ((member :red :blue :green :yellow)) (integer 1 4))。请注意,第二种和第三种类型都是正确的,但其中一种不是另一种的子类型。

\n\n

另请注意,要检查上面的第三种类型,需要准确地了解getf在这种情况下不太可能为真,并且在一般情况下根本不会为真。

\n\n

编译器检查函数类型是可以的,因为编译器可以抱怨或放弃。对于具有完全不同行为的运行时类型检查函数的不同实现来说,这是完全不可移植的。

\n

  • 我认为这可以用更好的措辞:仅仅因为并不总是可能知道某些东西的类型并不意味着检查类型永远是理智的:例如应该允许编译器按照您所说的那样这样做。最后一句是关键点:定义 *`typep`* 应该做什么基本上是不可能在不定义编译器可以做什么类型推断的情况下实现可移植的,这将是一件非常糟糕的事情。 (3认同)