5

我对 Haskell 比较陌生,我正在尝试理解HList的定义之一。

data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)
pattern HCons x xs = HCons1 (x, xs)

我有几个具体问题:

  • 我看到的'[]and语法是什么?(x ': xs)它几乎看起来像是对可变参数类型参数的模式匹配,但我以前从未见过这种语法,也不熟悉 Haskell 中的可变参数类型参数。我猜这是GHC 的 Type Families 的一部分,但我在链接页面上看不到任何关于此的内容,而且在 Google 中搜索语法相当困难。

  • 除了避免装箱之外,使用newtype带有元组的声明(而不是带有两个字段的声明)还有什么意义?dataHCons1

4

2 回答 2

8

首先,您缺少定义的一部分:data family声明本身。

data family HList (l :: [*])
data instance HList '[] = HNil
newtype instance HList (x ': xs) = HCons1 (x, HList xs)

这称为 a data family(在TypeFamilies扩展名下可用)。

pattern HCons x xs = HCons1 (x, xs)

这是一个双向模式(在PatternSynonyms扩展下可用)。

我看到的'[]and语法是什么?(x ': xs)

当你'在构造函数前面看到标记时,它表示它们提升的类型级对应物。为了语法上的方便,提升列表和元组也只需要额外的勾号(我们仍然可以'[]为空类型级列表和':类型级 cons 编写。所有这些都可以通过DataKinds扩展获得。

除了避免装箱之外,使用newtype带有元组的声明(而不是带有两个字段的数据声明)还有什么意义HCons1

是的,这是为了确保HList具有代表性的角色,这意味着您可以在HLists 1之间进行强制。这有点过于复杂,无法仅在一个答案中解释,但这是一个例子,说明当我们有

 data instance HList (x ': xs) = HCons x (HList xs)

而不是newtype instance(并且没有模式)。考虑以下在表示上分别newtype等同于IntBool和的 s()

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用于角色。(更多关于这里。)


1从技术上讲,a 没有作为一个整体的角色:每个/data family的角色可以不同- 这里我们只需要案例具有代表性,因为那是被强制的。看看这张 Trac 票instancenewtypeHCons

于 2016-12-14T05:48:40.693 回答
2

'[]并且(x ': xs)是类型级列表的语法,因为DataKinds语言扩展允许将类型提升为种类,将构造函数提升为类型;即如果k是某种类型,那么'[k]也是一种类型,并且'[]是一种类型'[k],如果t :: kts :: '[k],那么t ': ts :: '[k]。一切都被转移了一个。

所以在HList (x ': xs),xxs匹配两种类型:x匹配一种“正常”类型的 kind *(例如Int)并xs匹配另一个类型级别的 kind 列表'[*]。右侧定义了一个 ( newtype) 数据类型,该数据类型具有HCons1一个参数类型为 的构造函数(x, HList xs)

例如,我们可以有

HCons1 (1, HCons1 (True, HNil)) :: HList '[Int, Bool]

或者,使用模式同义词:

1 `HCons` True `HCons` HNil :: HList '[Int, Bool]

关于为什么将其表示为带有元组的新类型的第二个问题,我没有很好的答案。

于 2016-12-14T05:16:59.330 回答