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
就像 struct
和 union
的组合,而 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
,用于构建分类的类型数据构造函数生成的值,此处为ThisGoo
和ThatGoo
。
newtype 声明,例如,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 type
和 type
是同义词。但是,我承认可能会出现混淆,因为 Haskell 有两个关键字 data
和 type
,它们执行两个非常不同的功能。为了保持区分清晰,重要的是要注意上下文。每当您谈论签名中的类型或一般的类型时,术语“数据类型”和“类型”几乎总是指同一个东西。每当您谈到在代码中声明类型时,都会有所不同。
使用data
声明的类型是一种新的用户定义类型,因此您可以执行以下操作
data Status = Ready | NotReady | Exploded
Ready
、NotReady
和 Exploded
是 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 时就不会再对它们感到困惑了。
【讨论】:
恕我直言type
是data/type/newtype
中唯一一个有意义的。由于 =
的无意义使用以及类型级别和术语级别标识符的混合,其他语法上令人困惑。 type
是一个简单的类型级自然函数(自然变换)【参考方案3】:
type
和 data type
指的是同一个概念,polymorphic type
和 polymorphic data type
也是如此。
为了说明两个短语可以一起使用的情况(在含义上没有任何区别),请考虑这个表达式
data Maybe a = Just a | Nothing
我可以说我刚刚定义了一个多态数据类型Maybe
,带有多态类型参数a
。
【讨论】:
以上是关于Haskell 术语:类型与数据类型的含义,它们是同义词吗?的主要内容,如果未能解决你的问题,请参考以下文章