用户定义的基于元组的数据构造函数

我再次尝试理解 The Little MLer。TLMLer 有这个 SML 代码

datatype a pizza = Bottom | Topping of (a * (a pizza))
datatype fish = Anchovy | Lox | Tuna

我已经翻译为

data PizzaSh a = CrustSh | ToppingSh a (PizzaSh a)
data FishPSh = AnchovyPSh | LoxPSh | TunaPSh

然后可能是更接近 TLMLer 的替代方案

data PizzaSh2 a = CrustSh2 | ToppingSh2 (a, PizzaSh2 a)
data PizzaSh2 a = CrustSh2 | ToppingSh2 (a, PizzaSh2 a)

从每一个我创造一个比萨

fpizza1 = ToppingSh AnchovyPSh (ToppingSh TunaPSh (ToppingSh LoxPSh CrustSh))
fpizza2 = ToppingSh2 (AnchovyPSh, ToppingSh2 (LoxPSh, ToppingSh2 (TunaPSh, CrustSh2)))

分别是类型PizzaSh FishPShPizzaSh2 FishPSh

但是第二个版本(可以说更接近原始 ML 版本)似乎“另类”。就好像我正在创建一个 2 元组,当我在第二个成员递归扩展的地方“反对”浇头时。我可以假设参数化数据构造函数“函数”PizzaSh2并没有真正构建一个元组,它只是借用元组作为一个缺点策略,对吗?在 Haskell 中哪个更可取,PizzaSh还是PizzaSh2?据我了解,元组(笛卡尔积)数据类型将具有单个构造函数,例如,data Point a b = Pt a b,而不是 ored-together (|) 构造函数的不相交联合。在 SML 中,“*”表示产品,即元组,但同样,这只是一个“类似元组的东西”,即,它只是一种将比萨饼组合在一起的元组外观方式?

回答

在 Haskell 中,我们更喜欢这种风格:

data PizzaSh a = CrustSh | ToppingSh a (PizzaSh a)

在 Haskell 中不需要使用元组,因为像这样的数据构造函数ToppingSh可以接受多个参数。

使用额外的一对

创建一个几乎与前一个同构的类型,但处理起来更麻烦,因为它需要使用更多的括号。例如

foo (ToppingSh x y)
-- vs
foo (ToppingSh2 (x, y))

bar :: PizzaSh a -> ...
bar (ToppingSh x y) = ....
-- vs
bar (ToppingSh2 (x, y)) = ...

此外,该类型实际上只是几乎同构。当使用额外的一对时,由于懒惰,我们还有一个可以用类型表示的值:我们有一个对应关系

ToppingSh x y     <->    ToppingSh2 (x, y)

在这种情况下崩溃了

???               <->    ToppingSh2 undefined

也就是说,ToppinggSh2可以应用于非终止(或其他异常)、成对值表达式,并且构造一个不能使用 表示的值ToppingSh

在操作上,为了实现 GHC 使用双重间接(大致是指针到指针,或 thunk-returning-pair-of-thunk),这进一步减慢了代码的速度。因此,从性能的角度来看,这也是一个糟糕的选择,如果有人关心这样的微优化。


以上是用户定义的基于元组的数据构造函数的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>