【发布时间】:2012-05-17 00:07:07
【问题描述】:
data Ray = Ray Vector Vector
或
type Ray = (Vector, Vector)
在惯用的 haskell 中哪个是首选?为什么我应该使用一个而不是另一个?
我不在乎性能。
似乎与功能没什么区别,例如:
trace :: Ray -> …
trace (Ray x d) = …
-- OR
trace (x, d) = …
【问题讨论】:
data Ray = Ray Vector Vector
或
type Ray = (Vector, Vector)
在惯用的 haskell 中哪个是首选?为什么我应该使用一个而不是另一个?
我不在乎性能。
似乎与功能没什么区别,例如:
trace :: Ray -> …
trace (Ray x d) = …
-- OR
trace (x, d) = …
【问题讨论】:
首选data 版本,因为它更清楚地表明了程序员的意图——通过创建一个新类型,您向所有人指出这不仅仅是一个元组,而是一个有意义的语义实体,@987654323 @。
这样就可以进一步依赖类型系统,为Ray 提供自定义实例,并且无法在元组中进行优化。
【讨论】:
type 实际上只是一个同义词,而不是一种新的数据类型。但是必须在某个地方划清界限——type Colour = (Int, Int, Int) 是合适的,对吧?
type Colour = (Int, Int, Int) 与 type Position = (Int, Int, Int) 无法区分。但您可能不打算让对位置进行操作的函数也对颜色进行操作。
您还可以考虑将两者结合的第三种选择:newtype
newtype Ray = Ray (Vector, Vector)
在我看来,代数数据类型用于有多种选择的情况,或者需要类型是递归的、包含自身的情况。但对于这样的事情,它可能有点矫枉过正。
Don Stewart 指出,将类型同义为 tuple 与直接使用该 tuple 类型相同;类型同义词没有自己的身份。因此类型检查器将无法区分您的类型和元组,因此它无法检查您是否使用了所需的类型。此外,它的实例与元组完全相同。
newtype 允许您使用与元组相同的底层类型;但它是类型检查器的单独类型,具有单独的实例。
【讨论】:
我发现非常方便的第四个选择是记录:
data Ray = Ray { from, to :: Vector }
它们基本上具有“普通”ADT 的所有功能,但还增加了一些语法糖。特别是它们使获取值的部分修改副本变得更容易。确实在某些情况下记录太有限,但是您可以使用“改进版本”更进一步,例如fclabels。
【讨论】: