More useful program combinators

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.

1 Like

Is it similar to what is in https://github.com/rtfeldman/elm-spa-example?

No, not really. elm-spa-example does make use of nested updates to bring together all the pages into the top-level update function, but it codes whatever it needs to fit its own situation. I also don’t think I saw any out messages in elm-spa-example.

I’m just trying to discover a pattern, by looking at how I tend to nest updates in my own code, then package up the re-usable bit of the pattern. That gives me a short hand for combing update functions into the top-level one.

1 Like