使用数据和参数获取上下文,而不是存在性
我认为如果你想要
data Thing = Good [(Char,Int)] | Bad String | Indifferent Leg
但有时候也会
data Thing = Good [(Char,Float)] | Bad String | Indifferent Arm
您可以定义
data Thing num bodypart = Good [(Char,num)] | Bad String | Indifferent bodypart
或者,如果您想确保num
始终为数字,可以执行以下操作:
data Num num => Thing num bodypart = Good [(Char,num)] | Bad String | Indifferent bodypart
最后,您可以通过定义自己的类来限制bodypart
中允许的类型:
class Body a where
instance Body Leg where
instance Body Arm
data (Num num,Body bodypart) => Thing num bodypart =
Good [(Char,num)] | Bad String | Indifferent bodypart
我建议你不要使用forall构造函数或GADTs来使用存在类型,因为将num参数添加到数据类型中在实践中更加有用,尽管需要打字较多。
类型同义词的约束条件?
请注意,当您使用像
data (Num num) => Thing num = T [(Char,num)]
实际上只是改变了构造函数T
的类型
T :: (Num num) => [(Char,num)] -> Thing num
与其使用T :: [(Char,num)] -> Thing num
,不如使用T :: (Num num) => [(Char,num)] -> Thing num
。这意味着每次使用T
时,需要一个上下文(Num num)
,但这正是您想要的——防止将非数字数据放入数据类型中。
这一事实的结果是,您无法编写以下内容:
type Num num => [(Char,num)]
因为上下文 (Num num)
没有数据构造函数 T
,所以无法要求它;如果我有 [('4',False)],它会自动匹配类型 [(Char,num)]
,因为它是一个同义词。编译器不能在决定某个类型之前在您的代码中寻找实例。在 data
的情况下,它有一个构造函数 T
,告诉它类型,并且可以保证有一个 Num num
实例,因为它检查了您对函数 T
的使用。没有 T
,就没有上下文。
NumberList
类型的值能够包含任何数字列表,或者包含任何数字的列表,还是具有多态性并可用作任何数值类型的列表? - hzap