How to flatten a model

Refactoring types is a subject of interest to me; although your model does not look particularly flattenable.

Flattening

There is a purely mechanical process by which a model can be flattened, described here: Mapping Tagged Union types to other languages?.

Essentially you just expand out the products and sums to collapse a nested type down. If you only have products and sums you can always do this and get down to a model which is just a sum of products. If there are other non-sum-or-products in the model, usually List, Dict, Set, etc. then the math cannot be pulled through these, so they can prevent getting down to a flat model. As your model contains a few Lists, there is a limit to which this process can be applied, and even where it can be applied, does it result in a better model?

At any rate, I worked it through (note: you have 2 Cell definitions, I think I guessed right which is which):

type alias Player =
  { name: String
  , grid: Grid
  , words: List String }

type alias Grid = List Cell

type Cell
  = EmptyCell { coordinatesX: Int, coordinatesY: Int }
  | FullCell { coordinatesX: Int, coordinatesY: Int, val : String }

type Model =
  { players: List Player
  , dragging: Bool
  , dragStartX: Int
  , dragStartY: Int
  , dragEndX: Int
  , dragEndY: Int }

I can’t get it any flatter than that.

And did expanding out Point improve the model? I expect you are likely to have helper functions that work with Points doing stuff like calculating distance and so on, so I don’t think it was so helpful to do it.

Nested Updates

Having established that there can be limits to flattening, there is a great piece of advice on writing nested updates here: Updating nested records, again

For some record type Foo:

asBarIn : Foo -> Bar -> Foo
asBarIn foo bar =
    { foo | bar = bar }

Note also, it can often be applied to sum types too:

type Foo
  = First
  | Second { bar : Bar, whatever : Whatever }

asBarIn : Foo -> Bar -> Foo
asBarIn foo bar =
  case foo of
    First -> First
    Second second -> Second { second | bar = bar }
3 Likes