It's written Haskell 元组只是代数数据类型的不同语法。类似地,也有如何用元组重新定义值构造函数的示例。
例如,Haskell 中的 Tree 数据类型可以写为
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
可以像这样转换为“元组形式”:
data Tree a = EmptyTree | Node (a, Tree a, Tree a)
Node
之间有什么区别?第一个示例中的 value 构造函数,以及实际的 tuple
在第二个例子中?即Node a (Tree a) (Tree a)
与 (a, Tree a, Tree a)
(除了语法)?在引擎盖下,是
Node a (Tree a) (Tree a)
只是每个位置的适当类型的 3 元组的不同语法?我知道您可以部分应用值构造函数,例如
Node 5
类型:(Node 5) :: Num a => Tree a -> Tree a -> Tree a
你也可以部分应用一个元组,使用
(,,)
作为一个函数......但这不知道未绑定(bind)条目的潜在类型,例如:Prelude> :t (,,) 5
(,,) 5 :: Num a => b -> c -> (a, b, c)
除非,我猜,你用
::
显式声明了一个类型。 .除了像这样的语法特性,加上最后一个类型作用域的例子,Haskell 中的“值构造函数”实际上是什么,与用于存储相同类型的位置值的元组是值构造函数之间是否存在实质性区别?论据?
最佳答案
好吧,从概念上讲确实没有区别,实际上其他语言(OCaml,Elm)正是以这种方式呈现标记的联合 - 即,在元组或第一类记录上的标记(Haskell 缺乏)。我个人认为这是 Haskell 的设计缺陷。
虽然有一些实际差异:
data Tree a = EmptyTree | Node !a !(Tree a) !(Tree a)
您还可以使用 the
UNPACK
pragma 标记严格字段进一步减少占地面积。或者,您可以使用 the -funbox-strict-fields
compiler option .关于最后一个,我只是更喜欢在我的所有项目中默认启用它。见 the Hasql's Cabal file例如。 考虑到上述情况,如果您要查找的是惰性类型,则以下代码段应编译为相同的内容:
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
data Tree a = EmptyTree | Node {-# UNPACK #-} !(a, Tree a, Tree a)
所以我想你可以说可以使用元组来存储构造函数的惰性字段而不会受到惩罚。尽管应该提到这种模式在 Haskell 社区中有点不合常规。
如果您追求的是严格的类型和占用空间减少,那么除了将元组直接非规范化为构造函数字段之外别无他法。
关于haskell - 值构造函数和元组有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27476446/