多参数newtype用元组伪造?

时间:2011-08-07 04:00:09

标签: haskell newtype

这是一个愚蠢的问题,一直困扰着我。为什么我不能写一个包含多个参数的newtype,

newtype A = A Int Int

虽然元组版本很好吗?

newtype A = A (Int, Int)

前者在模式匹配等方面更为出色。

2 个答案:

答案 0 :(得分:11)

newtype A = A Int创建一个与Int同构的类型。也就是说,它的行为与Int w.r.t完全相同。例如bottom,但名称不同。

这与data A = A Int形成对比,Int创建了一个与Int不同的提升类型。还有一个不在A undefined undefined::A中的增值(与newtype A = A (Int, Int)不同)。

现在,(Int, Int)创建了一个与data A = A Int Int同构的类型。顺便说一句,这恰恰是newtype A = A Int Int所做的。

因此,如果我们承认newtype A = A (Int, Int)等同于newtype A = A Int Int,我们有什么? newtype A = A (Int, Int)相当于data A = A Int Int,相当于newtype A = A Int Int

data A = A Int Int相当于newtype(因此newtype A = A Int在这种情况下是多余的),

data A = A Int 等同于newtype(这是首先拥有newtype A = A Int Int的重点。)

因此,我们必须得出结论:newtype A = A (Int, Int)等同于newtype A = A Int Int会造成冗余和不一致,我们最好不要允许它。

可能没有办法给{{1}}一些其他没有这些不一致的含义(否则我会发现并使用它;)

答案 1 :(得分:7)

因为粗略地说newtype在运行时与type类似,在编译时类似于data。每个data定义都会增加一个额外的间接层 - 在正常情况下,这意味着另一个不同的地方可以将某些东西留作thunk - 围绕它所拥有的值,而newtype则不会。 newtype上的“构造函数”基本上只是一种幻觉。

任何将多个值组合成一个或者在多个案例之间进行选择的东西,必然会引入一个间接层来表达,因此newtype A = A Int Int的逻辑解释将是两个断开的Int值什么都没有“把它们抱在一起”。 newtype A = A (Int, Int)的区别在于元组本身添加了额外的间接层。

将此与data A = A Int Intdata A = A (Int, Int)进行对比。前者在两个A周围添加了一个层(Int构造函数),而后者在元组周围添加了相同的层,它本身在Int周围添加了一个层。 / p>

每一层间接通常也会添加一个可以something的地方,所以考虑每种形式的可能情况,在哪里?代表非最低价值:

  • 对于newtype A = A (Int, Int)(⊥, ?)(?, ⊥)(?, ?)

  • 对于data A = A Int IntA ⊥ ?A ? ⊥A ? ?

  • 对于data A = A (Int, Int)A ⊥A (⊥, ?)A (?, ⊥)A (?, ?)

从上面可以看出,前两个是等价的。


最后一点,这里有一个有趣的演示,说明newtypedata的区别。考虑这些定义:

data D = D D deriving Show
newtype N = N N deriving Show

哪些可能的价值,包括所有可能的价值,都有?您认为以下两个值是什么?

d = let (D x) = undefined in show x
n = let (N x) = undefined in show x

将它们装入GHC并查找!