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

时间:2016-10-18 21:01:35

标签: types lisp common-lisp sbcl

我们有以下内容:

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,以防这是依赖于实现的。谢谢!

2 个答案:

答案 0 :(得分:6)

(array foo)是否为(array bar)的子类型取决于实现在内存中是否具有类型为foobar的值数组的压缩表示。如果实现对其中一个元素类型具有更紧凑的表示(例如,为了避免内存表示中的间接级别),则数组类型不兼容,因此subtypep返回false。如果实现使用相同的压缩表示或通用表示,则subtypep将返回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

中指定

答案 1 :(得分:4)

来自SUBTYPEP

  

因此,

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

当且仅当

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

返回两个不同的类型说明符,它们总是引用相同的对象集。

以下是UPGRADED-ARRAY-ELEMENT-TYPE返回的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间接相关:

  

作为源和接收器的可变数据类型应该是不变的。   [...] Cat []不能被视为动物[]。应该总是可以将狗放入动物[]。