我有一些基本上像这样结构的记录类型:
type Body x = { x | pos: (Int,Int) }
type Bubble = Body { radius: Int }
type Box = Body { width: Int, height: Int }
现在我希望有一个混合列表中的任何一个,并在Body
部分执行一些操作,但其他时间仍然处理Box
和Bubble
特殊情况。例如,有(实现省略):
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。
有没有更优雅的方式处理这种情况?
答案 0 :(得分:7)
使用合成而不是继承时,这个问题就消失了。
不是将整个结构包装在ADT中,而是使记录中的一个字段保持带有特定于对象的属性的ADT:
type Body = { pos: (Int,Int), shape: Shape }
data shape = Bubble Int | Box (Int,Int)
这允许在Body
中使用共享结构,同时仅在必要时匹配shape
。