I'm not sure I like it either. Seems like a lot of UI commands would just 
be auto-converted to events by `command`.

However, in your example, I'm not sure what your filter code is about (my 
ignorance). If I am understanding it right, it's filling in for the case 
when you need to respond to an event and issue another command. This also 
seems like a separate concern from what I mentioned.

On Thursday, August 11, 2016 at 1:53:15 PM UTC-5, 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.

Reply via email to