理解 HList 的这个定义
Understanding this definition of HList
我对 Haskell 比较陌生,我正在尝试理解 HList 的定义之一。
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
pattern HCons x xs = HCons1 (x, xs)
我有几个具体问题:
我看到的 '[]
和 (x ': xs)
语法是什么?它几乎看起来像是可变类型参数的模式匹配,但我以前从未见过这种语法,我也不熟悉 Haskell 中的可变类型参数。我猜这是 GHC's Type Families 的一部分,但我在链接页面上看不到任何相关信息,而且很难在 Google.
[=29= 中搜索语法]
除了避免装箱 HCons1
之外,使用带有元组的 newtype
声明(而不是带有两个字段的 data
声明)还有什么意义吗?
'[]
和 (x ': xs)
在 DataKinds
language extension allows promoting types to kinds and constructors to types 的意义上是类型级列表的语法;即如果 k
是某种类型,那么 '[k]
也是一种类型,并且 '[]
是一种类型 '[k]
,如果 t :: k
和 ts :: '[k]
,然后 t ': ts :: '[k]
。一切都移动了一位。
所以在HList (x ': xs)
中,x
和xs
匹配两种类型:x
匹配"normal"类型的*
(例如Int
) 和 xs
匹配另一个种类 '[*]
的类型级列表。右侧定义了一个 (newtype
) 数据类型,它有一个构造函数 HCons1
,其参数类型为 (x, HList xs)
。
举个例子,我们可以
HCons1 (1, HCons1 (True, HNil)) :: HList '[Int, Bool]
或者,使用模式同义词:
1 `HCons` True `HCons` HNil :: HList '[Int, Bool]
对于你的第二个问题,关于为什么它被表示为带有元组的新类型,我没有很好的答案。
首先,您缺少定义的一部分: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
扩展名下可用)。
What is the '[]
and (x ': xs)
syntax I'm seeing?
当你在构造函数前面看到 '
标记时,表示它们的 promoted type-level counterparts. As a syntactic convenience, promoted lists and tuples 也只需要额外的勾号(我们仍然要为空写 '[]
类型级列表和 ':
用于类型级缺点。所有这些都可以通过 DataKinds
扩展名获得。
Is there any point in using a newtype
declaration with a tuple (instead of a data declaration with two fields) besides avoiding boxing of HCons1
?
对,就是保证HList
有一个表象role,也就是说可以在HList
s1之间进行强制.这有点过于复杂,无法仅在答案中进行解释,但这里有一个示例,说明当我们有
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。)
1 从技术上讲,data family
没有作为一个整体的角色:每个 instance
/[=25= 的角色可以不同] - 这里我们只需要 HCons
案例具有代表性,因为这是被强制执行的案例。 Check out this Trac ticket.
我对 Haskell 比较陌生,我正在尝试理解 HList 的定义之一。
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
pattern HCons x xs = HCons1 (x, xs)
我有几个具体问题:
我看到的
[=29= 中搜索语法]'[]
和(x ': xs)
语法是什么?它几乎看起来像是可变类型参数的模式匹配,但我以前从未见过这种语法,我也不熟悉 Haskell 中的可变类型参数。我猜这是 GHC's Type Families 的一部分,但我在链接页面上看不到任何相关信息,而且很难在 Google.除了避免装箱
HCons1
之外,使用带有元组的newtype
声明(而不是带有两个字段的data
声明)还有什么意义吗?
'[]
和 (x ': xs)
在 DataKinds
language extension allows promoting types to kinds and constructors to types 的意义上是类型级列表的语法;即如果 k
是某种类型,那么 '[k]
也是一种类型,并且 '[]
是一种类型 '[k]
,如果 t :: k
和 ts :: '[k]
,然后 t ': ts :: '[k]
。一切都移动了一位。
所以在HList (x ': xs)
中,x
和xs
匹配两种类型:x
匹配"normal"类型的*
(例如Int
) 和 xs
匹配另一个种类 '[*]
的类型级列表。右侧定义了一个 (newtype
) 数据类型,它有一个构造函数 HCons1
,其参数类型为 (x, HList xs)
。
举个例子,我们可以
HCons1 (1, HCons1 (True, HNil)) :: HList '[Int, Bool]
或者,使用模式同义词:
1 `HCons` True `HCons` HNil :: HList '[Int, Bool]
对于你的第二个问题,关于为什么它被表示为带有元组的新类型,我没有很好的答案。
首先,您缺少定义的一部分: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
扩展名下可用)。
What is the
'[]
and(x ': xs)
syntax I'm seeing?
当你在构造函数前面看到 '
标记时,表示它们的 promoted type-level counterparts. As a syntactic convenience, promoted lists and tuples 也只需要额外的勾号(我们仍然要为空写 '[]
类型级列表和 ':
用于类型级缺点。所有这些都可以通过 DataKinds
扩展名获得。
Is there any point in using a
newtype
declaration with a tuple (instead of a data declaration with two fields) besides avoiding boxing ofHCons1
?
对,就是保证HList
有一个表象role,也就是说可以在HList
s1之间进行强制.这有点过于复杂,无法仅在答案中进行解释,但这里有一个示例,说明当我们有
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。)
1 从技术上讲,data family
没有作为一个整体的角色:每个 instance
/[=25= 的角色可以不同] - 这里我们只需要 HCons
案例具有代表性,因为这是被强制执行的案例。 Check out this Trac ticket.