【问题标题】:Haskell: Algebraic data vs TupleHaskell:代数数据与元组
【发布时间】: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) = …

【问题讨论】:

    标签: haskell types tuples


    【解决方案1】:

    首选data 版本,因为它更清楚地表明了程序员的意图——通过创建一个新类型,您向所有人指出这不仅仅是一个元组,而是一个有意义的语义实体,@987654323 @。

    这样就可以进一步依赖类型系统,为Ray 提供自定义实例,并且无法在元组中进行优化。

    【讨论】:

    • 对。关于类型的一个关键点:它们不仅仅是数据的表示;它们表征有用的结构。
    • 好的,有道理。 type 实际上只是一个同义词,而不是一种新的数据类型。但是必须在某个地方划清界限——type Colour = (Int, Int, Int) 是合适的,对吧?
    • 不,出于性能原因,为 Color 提供一个压缩向量类型更有意义,就像在 color 包中一样——像这样有意义的类型可以被优化和专门化。 hackage.haskell.org/packages/archive/colour/2.3.3/doc/html/src/…
    • 元组对于其他模块不可见的临时和中间数据类型很有用,或者对于逻辑相关但仅在模块中“支持参与者”的事物的集合很有用。
    • @Mk12 请记住,对于 3 维整数坐标空间中的位置,type Colour = (Int, Int, Int)type Position = (Int, Int, Int) 无法区分。但您可能不打算让对位置进行操作的函数也对颜色进行操作。
    【解决方案2】:

    您还可以考虑将两者结合的第三种选择:newtype

    newtype Ray = Ray (Vector, Vector)
    

    在我看来,代数数据类型用于有多种选择的情况,或者需要类型是递归的、包含自身的情况。但对于这样的事情,它可能有点矫枉过正。

    Don Stewart 指出,将类型同义为 tuple 与直接使用该 tuple 类型相同;类型同义词没有自己的身份。因此类型检查器将无法区分您的类型和元组,因此它无法检查您是否使用了所需的类型。此外,它的实例与元组完全相同。

    newtype 允许您使用与元组相同的底层类型;但它是类型检查器的单独类型,具有单独的实例。

    【讨论】:

    • 这似乎不如使用柯里化形式常见。也许只是因为它是更多的标点符号。
    【解决方案3】:

    我发现非常方便的第四个选择是记录:

    data Ray = Ray { from, to :: Vector } 
    

    它们基本上具有“普通”ADT 的所有功能,但还增加了一些语法糖。特别是它们使获取值的部分修改副本变得更容易。确实在某些情况下记录太有限,但是您可以使用“改进版本”更进一步,例如fclabels

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多