整数向量不是数字数组的子类型,为什么?

A vector of integers is not a subtype of arrays of numbers, why?

我们有以下内容:

CL-USER> (subtypep 'integer 'number)
T
T

CL-USER> (subtypep 'double-float 'number)
T
T

CL-USER> (subtypep 'vector 'array)
T
T

因此:

CL-USER> (subtypep '(vector integer) '(array number))
T
T

但我不明白:

CL-USER> (subtypep '(vector double-float) '(array number))
NIL
T

我正在使用 SBCL 1.3。1.debian x86_64,以防这取决于实现。谢谢!

(array foo) 是否是 (array bar) 的子类型取决于实现是否在内存中具有 foobar 类型值数组的打包表示。如果实现对其中一种元素类型有更紧凑的表示(例如,为了避免内存表示中的间接级别),则数组类型不兼容,因此 subtypep returns false。如果实现使用相同的打包表示或通用表示,则 subtypep returns true.

特别是,函数 (lambda (foo bar) (subtypep `(array ,foo) `(array ,bar)) 的行为取决于实现。

例如,(array integer) 在 SBCL 和 CLISP 中是 (array number) 的子类型,但在 GCL 中不是。 (array double-float) 在 CLISP 中是 (array number) 的子类型,但在 GCL 或 SBCL 中不是。

这是在Common Lisp definition中指定的。

来自SUBTYPEP

Therefore,

 (subtypep '(array T1) '(array T2)) =>  true 

if and only if

(upgraded-array-element-type 'T1)  and  
(upgraded-array-element-type 'T2)

return two different type specifiers that always refer to the same sets of objects.

这是 UPGRADED-ARRAY-ELEMENT-TYPE returns 与 SBCL 1.3.7 的内容:

CL-USER> (upgraded-array-element-type 'double-float)
DOUBLE-FLOAT
CL-USER> (upgraded-array-element-type 'number)
T

我猜如果我们尝试添加整数或复数,专门用于双浮点数的数组可能无法正常运行。规范不要求实现来保证子类型关系在这种情况下成立。


这与Covariance, Contravariance and Invariance间接相关:

Mutable data types which act as both sources and sinks should be invariant. [...] a Cat[] cannot be treated as an Animal[]. It should always be possible to put a Dog into an Animal[].