On Wednesday, February 22, 2017 at 8:41:41 PM UTC, Brian Marick wrote:
>
> I’m comfortable with sum and product types by themselves, but I flounder 
> when trying to combine them.  Should I model the problem as a sum type 
> inside a record? as records in a sum type? 


The way I am approaching it at the moment is as follows:

1. Go through all the fields needed to implement the module or application 
and pick out the ones that are always needed. Put those in the Model record 
(at the top level) - the main product.

2. Figure out a state diagram describing the behavior of your UI. I find 
this is tending to align very well with one state for each element of the 
UI that can change. For example, something shown or hidden, or something 
shown in one state or another. Turn the state diagram into a Type - the sum.

3. Group the remaining fields up depending on the situations where they are 
needed. These groupings will not necessary be 1:1 with the states, it is 
common for some groupings to be used in many states For example, I need the 
state for the menu toggle button to be available whether the menu itself is 
visible or not. Each group will be given a type alias as a record - these 
form a set of little products that are non-overlapping. They should 
definitely be non-overlapping.

Once this is in place, I start writing the view and update functions - in 
terms of the little products of fields that they need to work with to 
update some part of the model, or render some part of the view. Then I use 
some functions I wrote around the state machine to select when to apply 
those functions - in a particular state or not, when a particular little 
product is available.

I find this extra layer of flexibility that composing the states out of 
groupings of fields is very useful when it comes to changing the model. For 
example, one time I realized I needed to render something in the view, in a 
particular state that I had forgotten to include. The view function for it 
was written in terms of the little product needed to render that view - so 
when I added that product to the particular state, everything else just 
fell into place.

I've created a Gist with an example model in it, and the boiler-plate 
functions I am using with these state 
machines. https://gist.github.com/rupertlssmith/c948f304ce0a99cd7ba9d6b6a061251a

The model there is:

type alias Model =
    { mode : Mode
    , menu : Menu
    }

and I only listed out the 'Mode' state machine. 'Menu' is an independent 
state machine and it is implemented in another module. So it is an example 
of a thing that is always needs to be available in the Model along-side the 
state machine for this particular model.

I agree with what you are saying about how refactoring can be a pain when 
you did not get the model right the first time and require very extensive 
changes. I am finding that this pattern of making the Model a product of 
sums of little products, is working quite flexibly. Particularly when you 
tend to write functions in terms of the little products re-factoring is 
more painless. Choosing how you divide stuff up into the little products is 
very similar to data modelling in OO languages.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to