我喜欢的一个实际示例来自编程语言领域:OO系统中的类型集是有界和离散的,但不可枚举,并且是部分有序但不是全部有序。
有问题的部分排序是子类型关系<:
。然后,上限将是顶部类型(C#object
和Scala调用Any
),而下限将是底部类型(Scala的Nothing
; C#/ Java没有等效的说法)。
但是,无法枚举类型系统中的所有类型,因此无法编写instance Enum Type
。这应该很清楚:用户可以编写自己的类型,因此无法提前知道自己的类型。您可以枚举任何给定程序中的所有类型,但不能枚举整个系统中的所有类型。
同样,(根据子类型的某种合理定义)<:
是自反的,传递的和反对称的,但不是总的。存在成对的类型对<:
。(Cat
和Dog
都是的子类型Animal
,但都不是另一个的子类型。)
假设我们正在为一种简单的OO语言编写一个编译器。这是我们系统中类型的表示:
data Type = Bottom | Class { name :: String, parent :: Type } | Top
以及子类型关系的定义:
(<:) :: Type -> Type -> Bool
Bottom <: _ = True
Class _ _ <: Bottom = False
Class n t <: s@(Class m _)
| n == m = True -- you can't have different classes with the same name in this hypothetical language
| otherwise = t <: s -- try to find s in the parents of this class
Class _ _ <: Top = True
Top <: Top = True
Top <: _ = False
这也给我们带来了超类型化的关系。
(>:) :: Type -> Type -> Bool
t >: s = s <: t
您还可以找到两种类型的最小上限,
lub :: Type -> Type -> Type
lub Bottom s = s
lub t Bottom = t
lub t@(Class _ p) s@(Class _ q) =
| t >: s = t
| t <: s = s
| p >: s = p
| t <: q = q
| otherwise = lub p q
lub Top _ = Top
lub _ Top = Top
练习:通过下面和下面两种方法,显示Type
形成一个有边界的完整姿势。<:
>: