这取决于用例。对于您拥有的功能,预计枚举性能会更好。基本上,三个构造函数D
become Int
s resp. Int#
当严格性分析允许时,并且 GHC 知道它已静态检查参数只能具有三个值之一0#, 1#, 2#
,因此不需要插入错误处理代码f
. For E
,没有给出仅三个值之一可能的静态保证,因此需要添加错误处理代码g
,这会显着减慢速度。如果你改变定义g
这样最后一个案例就变成了
E _ -> 3535#
差异完全或几乎完全消失(我得到了 1% - 2% 更好的基准)f
尽管如此,但我还没有进行足够的测试来确定这是否是真正的差异或基准测试的产物)。
但这不是 wiki 页面讨论的用例。它所说的是当类型是其他数据的组件时,例如,将构造函数解包到其他构造函数中。
data FooD = FD !D !D !D
data FooE = FE !E !E !E
然后,如果编译为-funbox-strict-fields
, 他们三个Int#
s 可以被解压到构造函数中FooE
,所以你基本上会得到相当于
struct FooE {
long x, y, z;
};
while the fields of FooD
have the multi-constructor type D
and cannot be unpacked into the constructor FD
(1), so that would basically give you
struct FooD {
long *px, *py, *pz;
}
这显然会产生重大影响。
我不确定单构造函数参数的情况。对于包含数据的类型(例如元组)来说,这具有明显的优势,但我不知道这如何应用于普通枚举,在普通枚举中,您只有一个case
将工人和包装机分开(对我来说)是没有意义的。
无论如何,工作者/包装器转换并不是单一构造函数的事情,构造函数专门化可以为具有很少构造函数的类型提供相同的好处。 (创建多少个构造函数专业化取决于-fspec-constr-count
.)
(1) That might have changed, but I doubt it. I haven't checked it though, so it's possible the page is out of date.