So these are not actually program combinators, as they leave out the other parts other than update
. But it mostly seems that when I combine packages of re-usable code together, its the update functions that present an opportunity to make use of some helper functions to trim the boilerplate.
I took this lift
function from elm-mdl/Material.Helpers (but switched around the set function to follow the convention of ‘model goes last’):
lift :
(model -> submodel)
-> (submodel -> model -> model)
-> (submsg -> msg)
-> (submsg -> submodel -> ( submodel, Cmd sub msg ))
-> submsg
-> model
-> ( model, Cmd msg )
lift get set tagger update subMsg model =
let
( updatedSubModel, subCmd ) =
update subMsg (get model)
in
( set updatedSubModel model, Cmd.map tagger subCmd )
And I based this eval
function on what I saw in folkertdev/OutMessage
eval :
(model -> ( model, Cmd msg ))
-> ( model, Cmd msg )
-> ( model, Cmd msg )
eval func ( model, cmds ) =
let
( newModel, moreCmds ) =
func model
in
( newModel, Cmd.batch [ cmds, moreCmds ] )
It only differs from Tuple.mapSecond
in that it appends the commands together using Cmd.batch
.
I also note that it is possible to write another lift function, for the case where update functions return 3 values, one of them being an out message, which is equivalent to code like this:
Auth.update msg model.auth
|> OutMessage.mapComponent (\auth -> { model | auth = auth })
|> OutMessage.mapCmd AuthMsg
I like how this reduces the language of combining update functions to lift and eval.