使用类型同义词系列的好处很明显 - 它是类型级函数。
但 data 系列并非如此 - 所以我的问题是,数据系列的用例是什么?我应该在哪里使用它?
答案 0 :(得分:23)
一个好处是数据系列是单射的,与类型系列不同。
如果你有
type family TF a
data family DF a
然后你知道DF a ~ DF b
暗示a ~ b
,而使用TF,你没有 - 对于任何a
你可以确定DF a
完全是[a]
新类型(就像[b]
是与a ~ b
不同的类型,当然除非data instance DF Int = DInt Int
data instance DF String = DString String
class C t where
foo :: t Int -> t String
instance C DF where -- notice we are using DF without an argument
-- notice also that you can write instances for data families at all,
-- unlike type families
foo (DInt i) = DString (show i)
),而类型系列可以将多种输入类型映射到同一现有类型。
第二个是数据系列可以像任何其他类型的构造函数一样部分应用,而类型系列则不能。
这不是一个特别真实的例子,但是例如,您可以这样做:
DF
基本上,DF a
和data
本身就是真正的,一流的合法类型,就像您使用TF a
声明的任何其他类型一样。 data
只是一个评估类型的中间形式。
但是,当我想知道数据系列并阅读类似内容时,我认为所有这些都不是很有启发性,或者至少不适合我。
这是我经历的经验法则。每当你发现自己重复你有一个类型族的模式,并且对于每种输入类型,你都要为要映射的类型族声明一个新的vector
类型,那么切断中间人并使用数据族就更好了代替。
来自vector库的真实示例。 Vector
有几种不同的向量:盒装向量,无盒装向量,基元向量,可存储向量。对于每个MVector
类型,存在相应的可变type family Mutable v :: * -> * -> * -- the result type has two type parameters
module Data.Vector{.Mutable} where
data Vector a = ...
data MVector s a = ...
type instance Mutable Vector = MVector
module Data.Vector.Storable{.Mutable} where
data Vector a = ...
data MVector s a = ...
type instance Mutable Vector = MVector
[etc.]
类型(法线向量是不可变的)。所以它看起来像这样:
data family Mutable v :: * -> * -> *
module Data.Vector{.Mutable} where
data Vector a = ...
data instance Mutable Vector s a = ...
type MVector = Mutable Vector
module Data.Vector.Storable{.Mutable} where
data Vector a = ...
data instance Mutable Vector s a = ...
type MVector = Mutable Vector
[etc.]
现在不是那样,我宁愿:
Vector
对不变量进行编码,对于每个Mutable Vector
类型,只有一个Vector
类型,并且它们之间存在一对一的对应关系。 Mutable Vector
的可变版本始终称为Mutable Vector
:这是它的名称,它没有其他名称。如果你有一个Vector
,你可以得到相应的不可变type family Mutable
的类型,因为它就像一个类型参数一样。使用MVector
,一旦将其应用于参数,它将评估为未指定的结果类型(可能称为{{1}},但您无法知道),并且您无法向后映射。