Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 基于用户定义元组的数据构造函数_Haskell_Types_Tuples_Sml_Cons - Fatal编程技术网

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

Haskell 基于用户定义元组的数据构造函数,haskell,types,tuples,sml,cons,Haskell,Types,Tuples,Sml,Cons,我又在试着摸那个小家伙了。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 也许还有一个更接近特姆勒的替代方案 data Pizz

我又在试着摸那个小家伙了。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
也许还有一个更接近特姆勒的替代方案

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 FishPSh
PizzaSh2 FishPSh
类型


但第二个版本(可以说是更接近原始ML版本)似乎“另类”,就好像我在创建一个2元组,当我“cons”topping在一起时,第二个成员递归地展开。我可以假设
PizzaSh2
的参数化数据构造函数“function”并没有真正构建元组,它只是借用元组作为一种策略,对吗?在Haskell,
PizzaSh
PizzaSh2
中,哪一个更可取?据我所知,元组(笛卡尔积)数据类型将具有单个构造函数,例如,
数据点ab=Pt a b
,而不是不相交的或合(|)构造函数的并集。在SML中,“*”表示产品,即元组,但这是否只是一种“类似元组的东西”,即它只是一种将比萨饼组合在一起的元组形式?

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

data PizzaSh a = CrustSh | ToppingSh a (PizzaSh a)
在Haskell中不需要使用元组,因为像
ToppingSh
这样的数据构造函数可以接受多个参数

使用另一对,如中所示

data PizzaSh2 a = CrustSh2 | ToppingSh2 (a, PizzaSh2 a)
创建一个几乎与前一个类型同构的类型,但由于需要使用更多的括号,因此处理起来更麻烦。例如

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

bar :: PizzaSh a -> ...
bar (ToppingSh x y) = ....
-- vs
bar (ToppingSh2 (x, y)) = ...
此外,该类型实际上只是几乎同构的。当使用一个额外的对时,由于惰性,我们还有一个值可以在类型中表示:我们有一个correlpondence

ToppingSh x y     <->    ToppingSh2 (x, y)
ToppingSh x y ToppingSh2(x,y)
在这种情况下会发生故障

???               <->    ToppingSh2 undefined
???Topingsh2未定义
也就是说,
ToppinggSh2
可以应用于非终止(或其他例外)对值表达式,并且它构造了一个不能用
ToppingSh
表示的值


在操作上,GHC使用双间接寻址(大致为指针到指针,或thunk返回thunk对),这进一步降低了代码的速度。因此,从性能角度来看,如果一个人关心这样的微观优化,那么这也是一个糟糕的选择。

至于Haskell方面,它绝对是在
ToppingSh
构造函数中嵌套
(,)
构造函数。如果不进行所请求的嵌套,将违反Haskell的非严格语义。如果嵌套被删除,您将无法区分
undefined::PizzaSh2()
ToppingSh undefined::PizzaSh2()
。是的,大多数时候,这不是你想要的
PizzaSh
是Haskell中更自然的公式,除非您特别需要能够在评估过程中引入另一个底部


在任何特定的ML实现中,我都无法解决幕后发生的事情。虽然我可以说,使用严格的求值语义,没有行为上的差异可以观察,这意味着编译器可以自由使用更广泛的方法。

是的,
PizzaSh2
构造函数确实包含一个元组。谢谢。仍在尝试整理数据构造函数函数和普通函数之间的差异。也许您应该使用
UNPACK
pragmas提及严格字段,以便在您确实希望这样做的情况下,获得具有相同表示形式的精确同构。@dfeuer在这种情况下这样做有什么好处吗?写入
数据T=T{-#解包-#}!(X,Y)
看起来比备选方案糟糕得多,我不知道为什么我会推荐它。我认为它有时会有帮助。例如,想象
data Pt=Pt!智力!Int;数据段=段{-#解包#-}!打开包装!Pt
。这非常清楚地表明,一个段由两个点组成,并且
Int
与之配对,同时保持紧凑的段表示。如果需要,它还可以非常容易地(尽管不是免费的)分离点,或者从点构建线段。