ael*_*ndy 8 haskell coding-style
我知道之间的差别data,newtype并type很好.我正在编写一个小脚本,它将构建某种语法树.几乎所有类型都有一个构造函数.我避免type强制执行安全性(多个"不同"类型可能最终在Haskell中具有相同的类型).在这种情况下我不关心懒惰/严格,也不关心性能(这部分绝不是性能关键).我主要专注于风格.我有三个选择:
data.这感觉还可以,除了我有很多类型,只有一个带有一个参数的构造函数.代码看起来有些浪费...虽然我不关心性能提升,但它感觉不对.newtype.在多个参数的情况下,这导致了元组的大量丑陋.data和newtype其中有些看起来不均匀,有点恼人的统一方式.我宁愿所有类型的声明.我选择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在类型恰好由单个字段组成时使用,而不是一个包装.
当我构建真正的程序而不是懒惰时,我几乎总是使用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 _|_(因为所有值都无论如何完全定义).
还有另一件事要看:声明的一致性是值得警惕的.它表示您没有在程序中编码的抽象级别,您将隐式隐藏.看看是否可以编码该级别,直到没有可用的并行声明结构.这并非总是可行,但试着接近.