在Elm中处理具有共享子结构的记录

时间:2014-08-04 23:33:59

标签: polymorphism algebraic-data-types elm

我有一些基本上像这样结构的记录类型:

type Body x = { x | pos: (Int,Int) }
type Bubble = Body { radius: Int }
type Box = Body { width: Int, height: Int }

现在我希望有一个混合列表中的任何一个,并在Body部分执行一些操作,但其他时间仍然处理BoxBubble特殊情况。例如,有(实现省略):

mv: (Int,Int) -> Body a -> Body a
bubble: Bubble
box: Box

我想

map (mv (1,1)) [box,bubble]

但这失败了,因为Elm认为列表中的类型不兼容。

现在我可以将Box es和Bubble包装在ADT中,如下所示:

type BodyWrap = BoxWrap Box | BubbleWrap Bubble

然后我需要在每种情况下进行解包和重新打包。如果我想在混合列表上折叠,它会变得更加混乱。一个例子是this gist

有没有更优雅的方式处理这种情况?

1 个答案:

答案 0 :(得分:7)

使用合成而不是继承时,这个问题就消失了。

不是将整个结构包装在ADT中,而是使记录中的一个字段保持带有特定于对象的属性的ADT:

type Body = { pos: (Int,Int), shape: Shape }
data shape = Bubble Int | Box (Int,Int)

这允许在Body中使用共享结构,同时仅在必要时匹配shape