据说 Haskell 元组只是代数数据类型的不同语法。同样,有一些例子展示了如何使用元组重新定义值构造函数。
例如,在 Haskell 中,Tree 数据类型可以这样写:
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
这些内容可以转换为“元组形式”,如下所示:
data Tree a = EmptyTree | Node (a, Tree a, Tree a)
第一个例子中的
Node
值构造函数和第二个例子中的实际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
你也可以使用(,,)
作为函数来部分应用元组...但这并不知道未绑定条目的潜在类型,例如:Prelude> :t (,,) 5
(,,) 5 :: Num a => b -> c -> (a, b, c)
除非你使用::
明确声明类型,否则不会有区别。
除了这种语法上的特殊性以及类型范围的最后一个示例之外,在Haskell中,“值构造器”实际上与用于存储相同类型的位置值的元组在本质上有什么区别吗?
tuple
创建递归数据类型,而不使用data
或newtype
关键字,否则将涉及到内存方面的考虑,对吗? - elynewtype
是一个仅在编译时存在的概念,在编译期间会被擦除。与data
不同,它不会在包装的类型上引入任何内存开销。我的答案更新应该可以解释其余部分。 - Nikita Volkovdata CustomTuple a b c = CustomTuple a b c
在 GHC 中的表示与(a, b, c)
完全相同。尝试编译和运行main = print (unsafeCoerce (CustomTuple "hi" 32 True) :: (String, Integer, Bool))
来验证这个说法(虽然编译很重要——runhaskell 和 ghci 在这里不起作用)。 - Daniel WagnerFoo
的元组赋予一个简写类型同义词,比如Foo
。(或者也许可以通过某种相互递归的方式实现?) - ely