Yeah the more I look at it this specific example the more I dislike it. It
is basically doing the model and command updates in the filters callback,
but instead of 'just doing it' it instead dispatches messages that do it,
gaining really nothing in readability or code size.
On Thursday, August 11, 2016 at 12:53:15 PM UTC-6, OvermindDL1 wrote:
>
> Yeah I was playing with the idea for more message types though still not
> convinced yet. Let's go hog-wild for a second to see how it would look
> with a fairly major overhaul and multiple message types though:
> ```elm
>
> {-| Msg is used for global message dispatching, handled only by the `filters`
> callback -}type Msg
> = ConnectTo Int
> | RoomConnected Int
> | ReceivedMessage String
> | MsgOnInput String
> | SendMsgDo
> type CmdMsg
> = FocusInputBox
> | ScrollInputBox
> | ConnectToRoom Int
> | SendMsgToRoom String
> type UpdMsg
> = JoinedRoom
> | MsgTyped String
> | MsgSent
> type alias Model =
> { uid : Int
> , msg : String
> , msgs : List String
> }
> init : ( Model, Cmd Msg )init = ( Model 0 "" [], connectToServer )
> filters : Msg -> Model -> States Model Msgfilters msg model =
> case msg of
> ConnectTo rid -> States.enableAll |> States.sendCommand (ConnectToRoom
> rid)
> RoomConnected uid ->
> States.enableAll
> |> States.sendCommand FocusInputBox
> |> States.sendCommand ScrollInputBox
> |> States.sendUpdate JoinedRoom
> ReceivedMessage msg -> States.enableAll
> MsgOnInput msg -> States.enableAll |> States.sendUpdate (MsgTyped msg)
> SendMsgDo -> States.enableAll |> States.sendCommand (SendMsgToRoom
> model.msg)
> update : UpdMsg -> Model -> Modelupdate msg model =
> case msg of
> JoinedRoom -> { model | msg="", msgs=[] }
> MsgTyped msg -> { model | msg=msg }
> MsgSent ->{ model | msg="" }
> command : Msg -> Model -> Cmd Msgcommand msg model =
> case msg of
> FocusInputBox -> focusMessageInput
> ScrollInputBox -> scrollScrollable Helpers Scrollable_Bottom
> ".messenger-mesglist"
> ConnectToRoom rid -> connectToRoom rid
> SendMsgToRoom msg -> sendMsgToConnectedRoom msg
>
> ```
>
> Eh I am not sure I like it, at all actually. It basically converts the
> usual helper functions into in-line in the case branches. It separates the
> commands and update messages out, however all the original logic is now in
> filter, which is basically just redistributing things (maybe it should be
> called `router` at this point) and is growing larger then its purpose was
> meant. Not sure of a good API yet...
>
>
> On Thursday, August 11, 2016 at 12:32:44 PM UTC-6, Kasey Speakman wrote:
>>
>> I do like the signatures you mentioned:
>>
>> `update : Msg -> Model -> Model`
>> `command: Msg -> Model -> Cmd Msg`
>>
>> However at that point, it no longer makes sense to use the same messages
>> for effects and model updates. For example:
>>
>> `update: Evt -> Model -> Model`
>> `command: Act -> Model -> Cmd Evt`
>>
>> Here, using Act for commands since Cmd is already taken. Evt for events
>> (facts which have occurred).
>>
>> The question then becomes how `view` would be affected. Html Msg doesn't
>> work there. If you did Html Act, then there is some boilerplate for actions
>> that don't have effects:
>>
>> ```
>> -- FUTURE READER: THIS IS AN EXAMPLE, NOT ACTUAL SYNTAX
>> command : Act -> Model -> Cmd Evt
>> command act model =
>> case act of
>> ChangeName name ->
>> Cmd.fromEvt <| NameChanged name
>>
>> SubmitCustomerChanges customer ->
>> Cmd.batch
>> [ Cmd.fromEvt <| CustomerChangesSubmitted
>> , callServerWithCustomer customer -- or model.Customer?
>> ]
>> ```
>>
>> An alternative is to allow Html to produce either Act or Evt. But that
>> feels wrong. It would be too easy to try to use only one or the other for
>> all the work.
>>
>> On Thursday, August 11, 2016 at 1:03:47 PM UTC-5, Kasey Speakman wrote:
>>>
>>> It was just something that bugged me when I first saw it in the
>>> examples, and I just came to the realization of why. And I am wondering out
>>> loud what it look like if they were separate things.
>>>
>>> In your example case, you could make a 3rd command that did the issued a
>>> new message InfoConnectIdAssigned to separate the model bit out. The
>>> tradeoff is isolation of model changes vs increased boilerplate (issuing a
>>> no-effect command). I think a shortcut method could be in order like
>>> Cmd.none, but something like Cmd.fromMsg.
>>>
>>> On Thursday, August 11, 2016 at 12:53:16 PM UTC-5, OvermindDL1 wrote:
>>>>
>>>> I guess what you are proposing is separating a Message into a
>>>> 'commands' and 'update' callbacks? That could work well too... I could
>>>> add that as an option to my ProgramEx testing library (where I test with
>>>> extra callbacks) if you want to play around with it? Do you propose that
>>>> `update` would be `Msg -> Model -> Model` and `command` would be `Msg ->
>>>> Model -> Cmd Msg, running in sequence of command before update? I can see
>>>> a lot of them having a lot of duplicate code though, but I guess that
>>>> could
>>>> be removed from my currently testing `filters` callback to clean up the
>>>> message into more pure stateful messages. Though if I did that I really
>>>> think I would want to make two different message types, one for filters
>>>> and
>>>> one for consuming, however that may make larger API changes than would be
>>>> easy... What precisely would you want it to look like?
>>>>
>>>>
>>>> On Thursday, August 11, 2016 at 11:48:21 AM UTC-6, OvermindDL1 wrote:
>>>>>
>>>>> Just as an aside, but I quite often return a mutated model *and*
>>>>> commands, such as this for the shortest example I am finding:
>>>>> ```elm
>>>>>
>>>>> InfoConnect uid ->
>>>>> ( { model | uid = uid }
>>>>> , Cmd.batch
>>>>> [ connect_roomlist 0
>>>>> , connect_roomlist uid
>>>>> ]
>>>>> )
>>>>>
>>>>> ```
>>>>> So when we connected to the server, got an InfoConnect message back
>>>>> with the unique ID of the user, they then are allowed to connect to both
>>>>> the public and their personal room lists, so I submit those connection
>>>>> requests.
>>>>>
>>>>>
>>>>> On Thursday, August 11, 2016 at 11:37:48 AM UTC-6, Kasey Speakman
>>>>> wrote:
>>>>>>
>>>>>> Hi all,
>>>>>>
>>>>>> I'm getting to know Elm. I recently read this article
>>>>>> <http://marcosh.github.io/post/2016/07/09/elm-event-sourcing.html>
>>>>>> about event sourcing in Elm. Essentially, the time-traveling debugger is
>>>>>> event sourcing. But it's a pattern that could be used in an app for
>>>>>> other
>>>>>> great things. (Lots of literature on that in the internet. One
>>>>>> particular
>>>>>> interest of mine is producing a complete failing use case from live
>>>>>> running
>>>>>> app -- it's just all the events. Obviously wouldn't work for real-time
>>>>>> apps... too many events... but for most of mine it would.)
>>>>>>
>>>>>> However, one thing that is a hindrance (to the TTD as well) and that
>>>>>> has always bothered me about the Elm examples is this signature.
>>>>>>
>>>>>> update : Msg -> Model -> (Model, Cmd Msg)
>>>>>>
>>>>>>
>>>>>> Because an update returns both a Model and Cmd, for instance, the
>>>>>> time-traveling debugger "...needs to tell the runtime not to perform any
>>>>>> side-effects during replay to avoid these issues"[1]. An event-sourcing
>>>>>> implementation would have to figure a way to do the same without runtime
>>>>>> hooks.
>>>>>>
>>>>>> This part of the architecture mixes concerns by returning a model and
>>>>>> effects. And usually (not always) you see each message returning one or
>>>>>> the
>>>>>> other, not both. From the docs:
>>>>>>
>>>>>> update : Msg -> Model -> (Model, Cmd Msg)
>>>>>> update msg model =
>>>>>> case msg of
>>>>>> Roll ->
>>>>>> (model, Random.generate NewFace (Random.int 1 6))
>>>>>>
>>>>>> NewFace newFace ->
>>>>>> (Model newFace, Cmd.none)
>>>>>>
>>>>>>
>>>>>> Here, Roll does an effect, but nothing with the model. NewFace
>>>>>> returns a new model but no effects. You do have cases where you want to
>>>>>> update a UI element when an outside effect happens, like activating a
>>>>>> spinner when sending off an HTTP request. Those could still be modeled
>>>>>> as
>>>>>> two "Cmd"s. One that immediately returns a separate message affecting
>>>>>> the
>>>>>> model's spinner. And another to do the HTTP request.
>>>>>>
>>>>>> So it seems to me that there are really two concepts at work here.
>>>>>> There are "events" which have happened and can be used completely
>>>>>> deterministically, and there are commands which interface with the
>>>>>> outside
>>>>>> and may produce events.
>>>>>>
>>>>>> I think it's something worth pointing out and considering for the
>>>>>> future. What do y'all think?
>>>>>>
>>>>>> Kasey
>>>>>>
>>>>>> [1] source <http://debug.elm-lang.org/>, section "How Elm makes this
>>>>>> possible", subsection "Purity", last paragraph
>>>>>>
>>>>>
--
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.