The part that is "more awkward" is in having to write the functions to
apply — or even just translate — the out messages from one layer to the
next. But, of course, the opportunity to do that work is where the pattern
gets its strength, so it's a tradeoff.

Other than that, it could probably benefit from a few more utility
functions and possibly a replacement for List as the way to return
sequences of out messages but I expect those to reveal themselves with
experience.

Mark

On Saturday, November 5, 2016, Eric G <[email protected]> wrote:

> Thanks for writing this up Mark, it seems very clear. It seems like it
> would be especially good for cases where results of effects need to be
> applied further up the state tree from where the effect is triggered. Or
> for cases where you want to examine (and possibly modify) requested effects
> further 'out' before they get converted to commands -- as in your example
> of needing to add credentials further 'out'.
>
> Personally I have only occasionally found a need for this kind of thing,
> but maybe that's for lack of a suitable hammer :)  Those helper functions
> certainly make it look more appealing... But I'm not sure I could evaluate
> it without actually trying it. Have you come across cases where it seems
> more awkward than standard TEA?
>
>
> On Friday, November 4, 2016 at 2:06:10 PM UTC-4, Mark Hamburg wrote:
>>
>> A note on where I'm moving with respect to structuring code (since many
>> have raised similar questions)...
>>
>> We don't have a particularly deep hierarchy but there are some fairly
>> distinct levels around things like app state management — are we logged in?
>> — and then view management while logged in. Even just having a few levels
>> made it worthwhile thinking about how to structure their relationships.
>>
>> I'd been moving toward the inter-module communication pattern supported
>> here:
>>
>> http://package.elm-lang.org/packages/folkertdev/outmessage/latest
>>
>>
>> in which update (and init) functions return not just a model and a
>> command but a model, a command, and out messages in some form. The outer
>> layer then applies the inner out messages to invoke further changes.
>>
>> One thing that didn't seem to be as well supported in this was having the
>> out messages generate out messages to go up to the next layer. Thinking
>> about adding that in and about any implied sequencing guarantees moved me
>> to a pattern in which the update functions have the following signatures:
>>
>> update : Msg -> Model -> ( Model, List OutMsg )
>>
>> (We should arguably change Msg to InMsg for symmetry but prevailing
>> convention uses Msg.)
>>
>> An update to an inner model looks something like the following:
>>
>> update : Msg -> Model -> ( Model, List OutMsg )
>> update msg model =
>>
>> case msg of
>>
>> ToInner innerMsg ->
>>
>> let
>>
>> (newInner, innerOutMsgs) =
>>
>> innerUpdate innerMsg model.inner
>>
>> in
>>
>> ( { model | inner = newInner }, [] )
>>
>> |> applyMessages
>>
>> applyInnerOutMsg
>> innerOutMsgs
>>
>>
>> Where we have support functions:
>>
>> applyInnerOutMsg : Inner.OutMsg -> Model -> ( Model, List OutMsg )
>>
>> applyMessages :
>>
>> ( msg -> model -> ( model, List outMsg ) )
>>
>> -> List msg
>>
>> -> ( model, List outMsg )
>>
>> -> ( model, List outMsg )
>>
>> applyMessages apply msgs state =
>>
>> List.foldl
>>
>> (\msg ( oldM, oldOut ) ->
>>
>> let
>>
>> ( newM, moreOut ) =
>>
>> apply msg m
>>
>> in
>>
>> ( newM, List.append oldOut moreOut )
>>
>> )
>>
>> state
>>
>> msgs
>>
>>
>> The benefits of this approach are that we can decide at each level how to
>> process the out messages from the next level down including both making
>> local changes and passing out messages up to the next level.
>>
>> This approach seems to embrace the "Effects as Data" pattern recommend
>> here:
>>
>> https://www.youtube.com/watch?v=6EdXaWfoslc.
>>
>>
>> In particular, it does so in a way that the standard use of commands
>> seems to thwart since commands aren't particularly designed to be inspected.
>>
>> But still, we have to fit commands in somewhere. At the top level, we
>> can't return a list of out messages and instead must build a command. One
>> way to do this is to make Cmd Msg the out message type for the top level
>> and then as a last step apply a Cmd.batch to the list of out messages.
>> Further down, while potentially less inspectable, we may still want to
>> generate commands without the intervening levels getting involved (though
>> this means that it's harder to put those lower levels in a test harness).
>> We can do that by including a Command (Cmd Msg) in the OutMsg type
>> union. The next layer out then uses Cmd.map to change the message type
>> and rewraps it in its own Command OutMsg. This pattern for handling
>> commands also makes it easy to move existing code over to this out message
>> centric model.
>>
>> I'm still in the process of converting code over, but I'm feeling pretty
>> happy with the results so far and conceptually it feels easy to explain: An
>> update function takes a message and a model and produces a new model and a
>> list of out messages to be handled at the next level up. If you need to do
>> something that doesn't fit within an update to your model, generate an out
>> message and let the next level up handle it. If you need information — e.g.
>> credentials — at a lower level to construct a request, don't do the final
>> command construction but rather return an out message describing the
>> request and let the level that has the credentials do the construction.
>>
>> Mark
>>
>> --
> 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]
> <javascript:_e(%7B%7D,'cvml','elm-discuss%[email protected]');>
> .
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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