又一个新类型与数据(风格问题)

时间:2012-02-15 12:58:56

标签: haskell coding-style

我非常了解datanewtypetype之间的差异。我正在编写一个小脚本,它将构建某种语法树。 几乎所有类型都有一个构造函数。我正在避免type强制执行安全性(多个“不同”类型可能最终在Haskell中具有相同的类型)。在这种情况下我不关心懒惰/严格,也不关心性能(这部分绝不是性能关键)。我主要专注于风格。我有三个选择:

  1. 仅使用data。这感觉还可以,除了我有很多类型,只有一个带有一个参数的构造函数。代码看起来有些浪费...虽然我不关心性能提升,但它感觉不对。
  2. 仅使用newtype。在多个参数的情况下,这会导致元组的大量丑陋。
  3. 混合datanewtype看起来有点不均匀而且有点烦人。我宁愿以一致的方式宣布所有类型。
  4. 我处于选择1到3之间的两难境地。

2 个答案:

答案 0 :(得分:11)

在这种情况下,出于几个原因,我会普遍使用data。首先,为了与多参数案例保持一致(肯定 data,而不是newtype)。

其次,最重要的是,newtype具有不同的语义data!除了明确使用严格字段之外,newtype的构造函数是严格的,而不是data的构造函数,它们是非严格的。即使您不关心严格性,或者data的所有字段都是严格的,仍然有一些subtle differences

我不认为一个构造函数,一个参数data类型是浪费的 - 从语法上讲,它们和newtype一样轻,在语义上,对我来说似乎更重要。< / p>

你说你并不关心性能,但是如果data 的运行时装箱费用非常不方便,那么只要你知道就可以将它们混合起来语义差异。但是,如果您使用-funbox-strict-fields,那么GHC可能能够为您优化单构造函数,单参数data,如果它们作为其他数据类型中的严格字段出现。

通常,在包装现有类型时,为了编译时安全/抽象,或者要定义自己的实例,应使用newtype,并在类型时使用data恰好是由一个字段组成,而不是一个包装器。

答案 1 :(得分:6)

当我构建没有使用懒惰的微妙事物的真实程序时,我几乎总是将newtype用于具有单个构造函数和参数data的数据类型其他一切:

data Foo = FooA | FooB Int
data Bar = BarA Int Foo
newtype Baz = Baz Bar

至少,如果你发现自己写作

newtype Foo = Foo (X,Y)

语义与相同

data Foo = Foo X Y

因此您可以使用data版本,因为它更漂亮。确实

data Foo = Foo Int
newtype Bar = Bar Int

在语义方面有所不同,但最终对“真实”程序不重要,我们不希望知道_|_Foo _|_之间的区别(因为无论如何,所有的值都是完全定义的。)

还有另一件事要看:声明的一致性是警惕的。它表示您没有在程序中编码的抽象级别,您将隐式隐藏。看看是否可以编码该级别,直到没有可用的并行声明结构。这并非总是可行,但试着接近。