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

ael*_*ndy 8 haskell coding-style

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

  1. 仅限使用data.这感觉还可以,除了我有很多类型,只有一个带有一个参数的构造函数.代码看起来有些浪费...虽然我不关心性能提升,但它感觉不对.
  2. 仅限使用newtype.在多个参数的情况下,这导致了元组的大量丑陋.
  3. 混合datanewtype其中有些看起来不均匀,有点恼人的统一方式.我宁愿所有类型的声明.

我选择1到3之间的困境.

ehi*_*ird 11

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

其次,也是最重要的,newtype不同的语义data!除非你明确使用严格字段,否则a的构造函数newtype是严格的,而不是非严格的构造函数data.即使你不关心严格,或者你data的所有领域都是严格的,但仍然存在一些微妙的差异.

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

你说你不关心性能,但如果一个运行时开销拳data 真的不方便,那么你可以混合使用它们,只要你意识到的语义差异.但是,如果您使用-funbox-strict-fields,那么GHC可能能够为您优化单构造函数,单个参数data,如果它们作为其他数据类型中的严格字段出现.

通常,您应该newtype在包装现有类型时使用,出于编译时安全/抽象的目的,或者定义自己的实例,并data在类型恰好由单个字段组成时使用,而不是一个包装.


luq*_*qui 6

当我构建真正的程序而不是懒惰时,我几乎总是使用newtype具有单个构造函数和参数的数据类型以及data其他所有内容:

data Foo = FooA | FooB Int
data Bar = BarA Int Foo
newtype Baz = Baz Bar
Run Code Online (Sandbox Code Playgroud)

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

newtype Foo = Foo (X,Y)
Run Code Online (Sandbox Code Playgroud)

语义是相同

data Foo = Foo X Y
Run Code Online (Sandbox Code Playgroud)

所以你不妨使用这个data版本因为它更漂亮.确实

data Foo = Foo Int
newtype Bar = Bar Int
Run Code Online (Sandbox Code Playgroud)

就在语义上不同,但在最终成为了"真实"的节目,我们不希望有知道的区别重要的任何方式_|_Foo _|_(因为所有值都无论如何完全定义).

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