Haskell 术语:类型与数据类型的含义,它们是同义词吗?

Posted

技术标签:

【中文标题】Haskell 术语:类型与数据类型的含义,它们是同义词吗?【英文标题】:Haskell terminology: meaning of type vs. data type, are they synonyms? 【发布时间】:2014-09-09 16:32:39 【问题描述】:

我正在阅读这本书:Haskell School of Expression,在第 56 页,在第 5 章的开头,我阅读了术语“多态数据类型”和“多态类型”。

这两个术语是指同一个概念吗?

它们是同义词吗?

或者两者之间有什么区别?如果是,是什么?

【问题讨论】:

与 C 的粗略比较——如果你知道那种语言的话——data 就像 structunion 的组合,而 type 就像 typedef。然而,haskell 数据类型比它们的 C 对应物更有效(data 允许更多的构造,考虑到所有可用的扩展)。 @didierc 粗略的比较确实是一个带标签的联合,但就像你说的那样,它们不止于此 @Wes,是的,我正在考虑这个问题,感谢您提及! 【参考方案1】:

type(在 Haskell 中)是一种语法,可以有意义地放在 :: 的右侧,以对 :: 左侧的表达式进行分类。类型的每个句法组件本身都由 kind 分类,其中类型的种类(对表达式进行分类)是*有些人乐于使用“类型”一词来指代类型语法的任何组件,无论它的种类是否允许它对表达式进行分类。

类型的语法可以通过各种声明形式进行扩展。

    类型同义词,例如type Foo x y z = [x] -> IO (y, z),添加完全应用形式Foo 的类型组件x y z ,它们按照它们的定义方程来扩展宏观时尚。 data 声明,例如data Goo x y z = ThisGoo x | ThatGoo (Goo y z x) 在类型语法中引入了一个新的类型构造函数 符号Goo,用于构建分类的类型数据构造函数生成的值,此处为ThisGooThatGoonewtype 声明,例如,newtype Noo x y z = MkNoo (x, [y], z) 会复制现有类型的副本,该副本在类型语法上与原始类型不同。

一个类型是多态,如果它包含类型变量可以被其他类型组件替换:按多态类型分类的值可以是特化 到类型变量的任何替换实例。例如。 append (++) :: [a] -> [a] -> [a] 适用于元素具有相同类型的列表,但任何类型都可以。具有多态类型的值通常被称为“多态值”。

有时,“数据类型”非常简单地表示由data 声明引入的类型。从这个意义上说,所有数据类型都是类型,但并非所有类型都是数据类型。不是数据类型的类型示例包括IO ()Int -> Int。此外,Int 不是 this 意义上的数据类型:它是硬连线的 primitive 类型。为免生疑问,有些人称这些类型为 algebraic 数据类型,因为构造函数给出了一个代数,意思是“通过组合其他值来构建值的一堆操作”。 “多态数据类型”是其中包含类型变量的数据类型,例如[(a, Bool)],与[Int] 形成对比。有时人们谈论“声明多态数据类型”或说“Maybe 是多态数据类型”之类的话,实际上只是意味着类型构造函数具有参数(因此可用于形成多态类型):迂腐,确实声明了一种多态数据类型,但不是任何旧的多态数据类型,而是应用于形式参数的类型构造函数。

当然,所有按类型分类的一等值在某种意义上都是“数据”,而在 Haskell 中,类型不用于分类任何不是一等值的东西,所以从广义上讲,每个“ type”是一种“数据类型”。在除了数据之外还有其他事物具有类型的语言(例如,Java 中的方法)中,这种区别变得更有意义。

非正式用法通常处于中间位置,并且没有很好的定义。人们经常在功能或流程与他们操作的东西(“数据”)之间存在某种区别。或者他们可能认为数据是“根据它们的制作方式来理解的”(并暴露它们的表示,例如通过模式匹配),而不是“根据它们的使用方式来理解”。 “数据”的最后一个用法与 abstract 数据类型的概念有些不协调,因为它是一种隐藏底层内容表示的类型。因此,隐藏表示的抽象数据类型与暴露表示的代数数据类型形成鲜明对比,这就是为什么“ADT”被随意用作两者的缩写是相当不幸的。

恐怕结果很模糊。

【讨论】:

你能添加一个抽象数据类型 w.r.t Haskell 的例子吗? List 是按照这个定义的抽象数据类型吗? 列表不是 Haskell 中的抽象数据类型,因为它们的表示是公开的:您可以通过模式匹配来访问它们。库类型Set a 是抽象数据类型的一个示例:您获得了一个接口(带有空集、联合、交集、各种测试等),但您无法获得实际的表示形式(可以只使用列表,事实上,但据我所知,这确实是一些漂亮的二叉树)。 所以答案是,如果我理解正确的话,没有人真正知道其中的区别。不幸的是,Hudak 并没有在他的书中定义术语“数据类型”,但仍然使用它,我希望这位备受尊敬的作者更加精确。 我认为答案不是没有人知道其中的区别,而是“数据类型”并不总是一个技术术语。或者说是很多。通常它的确切含义不值得捕捉。这里的答案确实相当全面地涵盖了我能想到的所有精确含义。【参考方案2】:

在这种情况下,data typetype 是同义词。但是,我承认可能会出现混淆,因为 Haskell 有两个关键字 datatype,它们执行两个非常不同的功能。为了保持区分清晰,重要的是要注意上下文。每当您谈论签名中的类型一般的类型时,术语“数据类型”和“类型”几乎总是指同一个东西。每当您谈到在代码中声明类型时,都会有所不同。

使用data 声明的类型是一种新的用户定义类型,因此您可以执行以下操作

data Status = Ready | NotReady | Exploded

ReadyNotReadyExploded 是 Haskell 中未包含的新构造函数。

另一方面,type 关键字可以简单地为现有类型创建一个别名

type Status = String

ready, notReady, exploded :: Status
ready = "Ready"
notReady = "NotReady"
exploded = "Exploded"

在这里,Status 只是String 的别名,在任何使用String 的地方都可以使用Status,反之亦然。没有任何构造函数,只有要使用的预构建值。这种方法的安全性要低得多,如果您使用这样的方法,您在某些时候遇到错误。 type 声明通常用于使某些论点更清楚地说明它们的用途,例如

type FilePath = String

这是 GHC 中的内置别名,如果你看到一个函数

doSomething :: FilePath -> IO ()

那么你马上就知道要给它传递一个文件名,相比之下

doSomething :: String -> IO ()

你不知道这个函数做了什么,除了“某事”。它们也常用于减少打字,例如:

type Point = (Double, Double)

现在您可以在类型签名中使用Point 而不是(Double, Double),这样写起来更短,可读性更强。


总而言之,data 声明了一个全新的类型,完全为您定制,type 应该重命名为 alias,这样人们在第一次接触 Haskell 时就不会再对它们感到困惑了。

【讨论】:

恕我直言typedata/type/newtype 中唯一一个有意义的。由于 = 的无意义使用以及类型级别和术语级别标识符的混合,其他语法上令人困惑。 type 是一个简单的类型级自然函数(自然变换)【参考方案3】:

typedata type 指的是同一个概念,polymorphic typepolymorphic data type 也是如此。

为了说明两个短语可以一起使用的情况(在含义上没有任何区别),请考虑这个表达式

data Maybe a = Just a | Nothing

我可以说我刚刚定义了一个多态数据类型Maybe,带有多态类型参数a

【讨论】:

以上是关于Haskell 术语:类型与数据类型的含义,它们是同义词吗?的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 的类型系统是不是同构于一个不一致的逻辑系统?如果是这样,后果是啥?

在Haskell中扩展数据类型

Haskell分析中的星号含义?

Haskell 类型安全的空间使用

什么是打字纪律?

让Haskell区分类型同义词