首先,您缺少部分定义:data family
声明本身。
data family HList (l :: [*])
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
这被称为data family
(下TypeFamilies
扩展可用)。
pattern HCons x xs = HCons1 (x, xs)
这是一个双向模式(可在PatternSynonyms
扩展名下获得)。
什么是我看到的'[]
和(x ': xs)
语法?
当您在构造函数前面看到'
标记时,表示它们的标记为promoted type-level counterparts。作为一个语法上的方便,promoted lists and tuples也只需要额外的蜱(我们仍然可以编写'[]
为类型级别利弊空类型级列表和':
。所有这一切都可以通过DataKinds
扩展。
是否有除了避免HCons1
拳击?
是的,这是确保HList
有代表性role,在使用了元组(而不是有两个字段的数据声明)一newtype
声明的任何点,这意味着你可以控制ce HList
s 。这是一个有点太参与只是一个答案来解释,但在这里是那里的东西不要去,因为我们希望,当我们有
data instance HList (x ': xs) = HCons x (HList xs)
代替newtype instance
(无图案)的例子。考虑以下newtype
S的都是表象等同于Int
,Bool
和()
分别
newtype MyInt = MyInt Int
newtype MyBool = MyBool Bool
newtype MyUnit = MyUnit()
回想一下,我们可以使用coerce
包或自动解开这些类型。好了,我们希望能够做同样的事情,但对于整个HList
:
ghci> l = (HCons 3 (HCons True (HCons() HNil))) :: HList '[Int, Bool, ()]
ghci> l' = coerce l :: HList '[MyInt, MyBool, MyUnit]
这工作与newtype instance
变种,但不是因为角色的data instance
之一。 (更多关于该here)
技术上,有一个data family
作为一个整体没有任何作用:角色可以为每个instance
/newtype
不同 - 这里我们只真正需要的HCons
情况具有代表性,因为那是被强制执行的。 Check out this Trac ticket。
'(l :: [*])'是否意味着一个类型参数'l'被约束成类型'[*]'? – Textfield
@Textfield正好!一个类型参数是一个提升的类型列表。想想看,编译出来可能需要打开'KindSignatures',并且可能还需要导入'Data.Kind' ...只要做一下GHC的建议即可。 :) – Alec