haskell - 为什么我们需要 Sum 类型?

标签 haskell type-theory

想象一种不允许数据类型使用多个值构造函数的语言。而不是写

data Color = White | Black | Blue

我们会有
data White = White
data Black = Black
data Blue = Black
type Color = White :|: Black :|: Blue

在哪里 :|: (这里不是 | 以避免与 sum 类型混淆)是一个内置类型联合运算符。模式匹配将以相同的方式工作
show :: Color -> String
show White = "white"
show Black = "black"
show Blue = "blue"

如您所见,与副产品相比,它产生了扁平结构,因此您不必处理注入(inject)。而且,与 sum 类型不同,它允许随机组合类型,从而获得更大的灵 active 和粒度:
type ColorsStartingWithB = Black :|: Blue

我相信构造递归数据类型也不是问题
data Nil = Nil
data Cons a = Cons a (List a)
type List a = Cons a :|: Nil

我知道联合类型存在于 TypeScript 和其他语言中,但为什么 Haskell 委员会选择 ADT 而不是它们?

最佳答案

Haskell 的 sum 类型与您的 :|: 非常相似。 .

两者的区别在于 Haskell 求和类型 |是一个标记的联合,而你的“总和类型”:|:未标记。

标记意味着每个实例都是唯一的 - 你可以区分 Int | Int来自 Int (实际上,这适用于任何 a ):

data EitherIntInt = Left Int | Right Int

在这种情况下:Either Int Int包含比 Int 更多的信息因为可以有 LeftRight Int .

在您的 :|: ,您无法区分这两个:
type EitherIntInt = Int :|: Int

你怎么知道是左还是右Int ?

有关以下部分的扩展讨论,请参阅评论。

标记联合还有另一个优点:编译器可以验证您作为程序员是否处理了所有情况,这对于一般的未标记联合来说是依赖于实现的。您处理了Int :|: Int 中的所有案件吗? ?这要么与 Int 同构根据定义或编译器必须决定哪个 Int (左或右)选择,如果它们无法区分,这是不可能的。

考虑另一个例子:
type (Integral a, Num b) => IntegralOrNum a b = a :|: b    -- untagged
data (Integral a, Num b) => IntegralOrNum a b = Either a b -- tagged

什么是5 :: IntegralOrNum Int Double在未标记的联盟中?它都是 Integral 的一个实例和 Num ,所以我们不能确定,必须依赖实现细节。另一方面,标记的联合确切地知道5应该是因为它被标记为 LeftRight .

至于命名:Haskell 中的不相交联合是联合类型。 ADT 只是实现这些的一种手段。

关于haskell - 为什么我们需要 Sum 类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40620913/

相关文章:

haskell - 如何避免整个程序在 IO monad 中操作?

coq - 如何在 Coq 中证明 "Type <> Set"(即 Type 不等于 Set)?

algorithm - 如何系统地计算给定类型的居民数量?

haskell - 我这里的类型签名有什么问题?

haskell - 为什么不是 (20 >) 。长度 。取 10 === const True

haskell - 如何使 Vect n Int 成为 Monoid 的实例

functional-programming - 具有不同类型索引的互感描述?

types - 类型系统理论入门书籍

logic - 在 Agda 中制定依赖类型系统

haskell - Haskell 中的并发 HTTP 请求