在common-lisp中,如何定义类型之间的关系?

时间:2011-10-20 14:56:51

标签: types lisp common-lisp

在Lisp中玩时我发现了以下内容:

(subtypep 'string '(array character)) ==> NIL, T
(subtypep '(array character) 'string) ==> NIL, T

(typep (make-string x) '(array character)) ==> T
(typep (make-array x :element-type :character) 'string) ==>T

表示x的任何值。

这意味着“subtypep”表示'string和'(数组字符)是两种不同的类型,而“typep”表示一种类型的任何实例也是另一种的实例( 1)

除非(1)不正确 - 请举例 - 为什么会发生这种情况?我发现很难掌握,因为我假设一个类型在没有它的实例的情况下不能在概念上存在,也就是说,它是由它的实例定义的:它是具有一组特定属性的对象的类(在数学意义上)。它是否正确?

编辑:正确指出(array character)不一定是string的子类型,原因很简单,因为存在多维字符数组。但是我仍然无法想象string的实例没有(array character)的类型。

4 个答案:

答案 0 :(得分:3)

http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science

Common Lisp中的数组是可变的。 CL中的数组是不变的,而不是试图假装它们是协变的或逆变的并且添加复杂的动态检查。因此,除非它们相同,否则(array character 1)(array base-char 1)之间不存在子类型关系。程序不应该在后者中存储非基本字符,程序可以从前者读取非基本字符。

阵列升级会导致新手进一步混淆。有助于记住,虽然一些编译器使用类型声明来确保安全,但它们的主要目标是性能。类型化数组被映射(升级)为一组特殊处理的数组元素类型。这些专门的数组类型必须形成一个格子(确保我们能够巧妙地找到最具体的特殊类型),但仍然没有子类型关系。

答案 1 :(得分:1)

实际上,这在您的实施中是一些古怪的事情。 (可能与某些优化相关)。

例如在SBCL中,如果您(describe 'string),则会获得STRING names a primitive type-specifier: (undocumented)。有趣的是,对于base-string,它是相同的,但是:

(subtypep 'base-string 'array) => T
(subtypep 'base-string '(array base-char)) => T
(subtypep 'string 'array) => T
(subtypep 'string '(array character)) => NIL
(subtypep 'string '(array base-char)) => NIL
(subtypep 'string '(array standard-char)) => NIL
(subtypep 'string '(array extended-char)) => NIL

答案 2 :(得分:1)

这是一个实施问题:

ccl e$ rlwrap ./dx86cl64
Loading ~/ccl-init.lisp
Welcome to Clozure Common Lisp Version 1.7-dev-r14614M-trunk  (DarwinX8664)!
? (subtypep 'string '(array character))
T
T
? 

答案 3 :(得分:1)

尝试:

(subtypep '(vector nil) 'string)

在SBCL和其他实现中了解。 (vector nil)作为字符串子类型的要求遵循标准,即使base-char和character在实现中是等效的。