Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling records with shared substructure in Elm

I have some record types structured essentially like this:

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

Now I would like to have a mixed list of any of these and perform some operation on the Body part, but still special case handling Box and Bubble other times. For example, having (implementations elided):

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

I would like to

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

but this fails because Elm deems the types in the list incompatible.

Now I could wrap the Boxes and Bubbles in an ADT like so:

type BodyWrap = BoxWrap Box | BubbleWrap Bubble

but then I need to do an unwrapping and rewrapping in every case. If I want to fold on the mixed list it gets even messier. An example is in this gist.

Is there a more elegant way of handling this situation?

like image 341
Justin Kaeser Avatar asked Aug 04 '14 23:08

Justin Kaeser


1 Answers

This problem goes away when using composition rather than inheritance.

Instead of wrapping the whole structure in an ADT, make one field in the record hold an ADT with the object-specific properties:

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

This allows using the shared structure in Body while matching on shape only when necessary.

like image 173
Justin Kaeser Avatar answered Nov 03 '22 02:11

Justin Kaeser