Re: [elm-discuss] Re: More thorough side-effect isolation

2016-08-18 Thread Kasey Speakman
You could be right. I'm thinking of back-end systems where a PM may need to
send a command to an "external" system (or even calls to its own system are
done as "external" calls), so I/O is involved. Maybe that scenario doesn't
apply on the front-end.

On Thu, Aug 18, 2016 at 9:32 AM, Marco Perone  wrote:

> Thanks Kasey for your observations!
>
> I agree with everything except for one thing. Regarding `process`, I don't
> think it should return a Cmd Command. Cmd generates asynchronous
> operations, and we receive a notification when they are completed, so I'd
> rather represent this message with an Event. I guess that `process` should
> return something like Command | Cmd Event, to allow both synchronous and
> asynchronous commands
>
>
> On Wednesday, August 17, 2016 at 9:31:02 PM UTC+2, Kasey Speakman wrote:
>>
>> So, reading through your implementation:
>>
>> Bug: In `projection`, you're doing a foldl on your history, but you're
>> putting new events at the head of your history using cons (::). So your
>> history be replayed in reverse order. I think there was a quite humorous
>> Red Dwarf episode about that.
>>
>> Possible typo: `process` should return a Cmd Command instead of Cmd Event
>> if we're talking about the Process Manager pattern. I would also do a List
>> instead of Maybe. (You can Cmd.batch them, and Cmd.none is actually
>> implemented as Cmd.batch on an empty list)
>>
>> Also, `process` is called incorrectly if it only uses Events to make
>> decisions. It should be called with all history, not just the events
>> generated from the one command. With only current events, it might be
>> missing the information needed to know if a Command is warranted. RPG
>> example: your game didn't have full history, so even though you got a
>> GoblinSlayer sword 5 minutes ago, it didn't on turn Glow on when
>> GoblinsEnteredTheArea.
>>
>> `commandHandler` - I believe the definition of commandHandler as `Command
>> -> Events -> Events` is too narrow. A command handler is often responsible
>> for wrangling external resources (e.g. API calls). The only way to make
>> this possible is to return `Cmd Events`. I also imagine it possible to
>> perform some IO through Cmd and subsequently need to issue another Command
>> to do something else with logic or IO. (Generally, I think multiple API
>> calls would be handled better by an API gateway, but I wouldn't want to
>> limit possibilities here.) I think Cmd Msg or Cmd (List Msg) would be more
>> expected here.
>>
>> As previously mentioned, I don't think it's a good idea to carry around
>> the increment value and actually calculate it in the `eventHandler`. The
>> relating of Incremented to the plus operator and Decremented to minus is
>> logic, and logic should be under the command handler. Updating a model with
>> event data should be as dumb as possible, because it should not have the
>> possibility to fail when simply responding to facts. Not sure if plus/minus
>> overflow in Elm (in JS, they flip sign on overflow), but other kinds of
>> operators could.
>>
>> On Wednesday, August 17, 2016 at 11:32:27 AM UTC-5, Marco Perone wrote:
>>>
>>> Hi!
>>>
>>> I was eventually able to read carefully the thread and give some
>>> thoughts about it.
>>>
>>> @kasey, I had a look to your Gist and it looks really interesting! Some
>>> notes about it:
>>>
>>> - I think it would be better to store in the parameter of the Fact's the
>>> increment, and not the state of the application. It looks to me that you
>>> are mixing two concerns, i.e. the state of the applications and the events
>>> that happens to it
>>>
>>> - if I'm not mistaken, from you implementation it seems that only Act's
>>> (and not Fact's) can generate new Cmd's. I think that is some applications
>>> there could be the need to react automatically with a new Cmd to some
>>> events that happened
>>>
>>> To make everything clearer in my mind, I wrote my own implementation of
>>> something similar to what you did. You can find it here:
>>>
>>> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>>>
>>> It should be just a functional transposition of a standard es/cqrs
>>> architecture (I actually used also es/cqrs jargon), adacted to the Elm
>>> Architecture.
>>>
>>> I'd really like to know what you think of it. Let me know if something
>>> is not clear enough
>>>
>>> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:

 So, I made a Gist
 
 of the helper stuff which splits Facts and Acts. I call the helper
 Factor... (Fact or Act ~=> Factor). There is a subsequent comment with an
 example program explaining the helper's usage.

 --
> You received this message because you are subscribed to a topic in the
> Google Groups "Elm Discuss" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/
> topic/elm-discuss/yKRYkoiQmPs/unsubscribe.
> To 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-18 Thread Marco Perone
Thanks Kasey for your observations!

I agree with everything except for one thing. Regarding `process`, I don't 
think it should return a Cmd Command. Cmd generates asynchronous 
operations, and we receive a notification when they are completed, so I'd 
rather represent this message with an Event. I guess that `process` should 
return something like Command | Cmd Event, to allow both synchronous and 
asynchronous commands

On Wednesday, August 17, 2016 at 9:31:02 PM UTC+2, Kasey Speakman wrote:
>
> So, reading through your implementation:
>
> Bug: In `projection`, you're doing a foldl on your history, but you're 
> putting new events at the head of your history using cons (::). So your 
> history be replayed in reverse order. I think there was a quite humorous 
> Red Dwarf episode about that.
>
> Possible typo: `process` should return a Cmd Command instead of Cmd Event 
> if we're talking about the Process Manager pattern. I would also do a List 
> instead of Maybe. (You can Cmd.batch them, and Cmd.none is actually 
> implemented as Cmd.batch on an empty list)
>
> Also, `process` is called incorrectly if it only uses Events to make 
> decisions. It should be called with all history, not just the events 
> generated from the one command. With only current events, it might be 
> missing the information needed to know if a Command is warranted. RPG 
> example: your game didn't have full history, so even though you got a 
> GoblinSlayer sword 5 minutes ago, it didn't on turn Glow on when 
> GoblinsEnteredTheArea.
>
> `commandHandler` - I believe the definition of commandHandler as `Command 
> -> Events -> Events` is too narrow. A command handler is often responsible 
> for wrangling external resources (e.g. API calls). The only way to make 
> this possible is to return `Cmd Events`. I also imagine it possible to 
> perform some IO through Cmd and subsequently need to issue another Command 
> to do something else with logic or IO. (Generally, I think multiple API 
> calls would be handled better by an API gateway, but I wouldn't want to 
> limit possibilities here.) I think Cmd Msg or Cmd (List Msg) would be more 
> expected here.
>
> As previously mentioned, I don't think it's a good idea to carry around 
> the increment value and actually calculate it in the `eventHandler`. The 
> relating of Incremented to the plus operator and Decremented to minus is 
> logic, and logic should be under the command handler. Updating a model with 
> event data should be as dumb as possible, because it should not have the 
> possibility to fail when simply responding to facts. Not sure if plus/minus 
> overflow in Elm (in JS, they flip sign on overflow), but other kinds of 
> operators could.
>
> On Wednesday, August 17, 2016 at 11:32:27 AM UTC-5, Marco Perone wrote:
>>
>> Hi!
>>
>> I was eventually able to read carefully the thread and give some thoughts 
>> about it.
>>
>> @kasey, I had a look to your Gist and it looks really interesting! Some 
>> notes about it:
>>
>> - I think it would be better to store in the parameter of the Fact's the 
>> increment, and not the state of the application. It looks to me that you 
>> are mixing two concerns, i.e. the state of the applications and the events 
>> that happens to it
>>
>> - if I'm not mistaken, from you implementation it seems that only Act's 
>> (and not Fact's) can generate new Cmd's. I think that is some applications 
>> there could be the need to react automatically with a new Cmd to some 
>> events that happened
>>
>> To make everything clearer in my mind, I wrote my own implementation of 
>> something similar to what you did. You can find it here:
>>
>> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>>
>> It should be just a functional transposition of a standard es/cqrs 
>> architecture (I actually used also es/cqrs jargon), adacted to the Elm 
>> Architecture.
>>
>> I'd really like to know what you think of it. Let me know if something is 
>> not clear enough
>>
>> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>>>
>>> So, I made a Gist 
>>>  of 
>>> the helper stuff which splits Facts and Acts. I call the helper Factor... 
>>> (Fact or Act ~=> Factor). There is a subsequent comment with an example 
>>> program explaining the helper's usage.
>>>
>>>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread OvermindDL1
On Wednesday, August 17, 2016 at 2:00:47 PM UTC-6, Kasey Speakman wrote:
>
> One question @Evan. How are you keeping events? I would assume in Elm 
> structures, since you can't send union types through ports be default. 
> Asking in case you have some magic for transferring them out to Javascript. 
> The idea of writing de/en-coders for every message case (in order to 
> transmit or load/save in Session State) makes my brain shut down.
>

This looks like the code from a cursor search, in other words it is stored 
in elm it seem?

https://github.com/elm-lang/elm-reactor/blob/master/src/debugger/History.elm 

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread OvermindDL1
On Wednesday, August 17, 2016 at 1:15:49 PM UTC-6, Evan wrote:
>
> Warning, I have not read everything here. About ignoring commands though, 
> think of the type of a Html.App.program
>
> program : { init, update, view, subscriptions } -> Program Never
>
> The essence of this is just a record. So you can wrap that record however 
> you want. Say like this:
>
> myProgram : ({ init, update, view, subscriptions } as details) =
>   { details | update = \msg model -> (fst (update msg model), Cmd.none) }
>
> Now you have programs that drop all commands.
>
> I'm in the process of revining elm-reactor to track history for exactly 
> the kinds of things you have in mind (testing, etc.) and I am using this 
> basic technique. Anyone can do this. You can write time-travel in pure Elm 
> this way. Make the update log all the messages it gets.
>

This is what I do in my ProgramEx library to have the separate filtering 
step, and is how I would imagine a thing like this thread would be done as 
well, the API itself though still seems hard to get right.  Hmm, an idea 
though...

What if update was all just Cmd's, it did not return a model, but certain 
commands would update the model.  like using the `put` and `update` syntax 
that I propose in the other thread, you could do something like:
```elm

# Example for a multi-counter where each has an Integer IDupdate : Msg -> Model 
-> Cmd Msgupdate msg model =
  case msg of

{- Example using Cmd.putModel -}
Increment id ->
  Cmd.putModel
[Model.Fields.counter, Model.Counter.Key id]
( Just ( (Dict.get id model.counters |> Maybe.withDefault 0) + 1 ) )

{- Example using Cmd.updateModel -}
Decrement id ->
  Cmd.updateModel
[Model.Fields.counter, Model.Counter.Key id]
(\t ->
  Just ((t |> Maybe.withDefault 1 ) - 1)
)

```

That way both commands are commands, and model mutations are commands.  A 
benefit is since you know which are prev->next state updates (updateModel) 
and which are purely 'set' updates (putModel) then you know how they could 
be combined and simplify their storage accordingly.  You could even not 
have a `Cmd.updateModel` and instead require another command with a new 
argument that then sets it via a Put, thus no functions would be stored at 
the expense of another model-update message for updates (which is probably 
better anyway for such tracking).  As such the above Decrement would end up 
being something like this for this specific case:
```elm

Decrement id ->
  Cmd.msg (Increment -1)

```

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Kasey Speakman
One question @Evan. How are you keeping events? I would assume in Elm 
structures, since you can't send union types through ports be default. 
Asking in case you have some magic for transferring them out to Javascript. 
The idea of writing de/en-coders for every message case (in order to 
transmit or load/save in Session State) makes my brain shut down.

On Wednesday, August 17, 2016 at 2:15:49 PM UTC-5, Evan wrote:
>
> Warning, I have not read everything here. About ignoring commands though, 
> think of the type of a Html.App.program
>
> program : { init, update, view, subscriptions } -> Program Never
>
> The essence of this is just a record. So you can wrap that record however 
> you want. Say like this:
>
> myProgram : ({ init, update, view, subscriptions } as details) =
>   { details | update = \msg model -> (fst (update msg model), Cmd.none) }
>
> Now you have programs that drop all commands.
>
> I'm in the process of revining elm-reactor to track history for exactly 
> the kinds of things you have in mind (testing, etc.) and I am using this 
> basic technique. Anyone can do this. You can write time-travel in pure Elm 
> this way. Make the update log all the messages it gets.
>
> Again, I have no idea what's happening in this discussion though, so 
> hopefully that's a helpful insight.
>
>
> On Thursday, August 11, 2016 at 10:37:48 AM UTC-7, Kasey Speakman wrote:
>>
>> Hi all,
>>
>> I'm getting to know Elm. I recently read this article 
>>  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 , 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Kasey Speakman
So, reading through your implementation:

Bug: In `projection`, you're doing a foldl on your history, but you're 
putting new events at the head of your history using cons (::). So your 
history be replayed in reverse order. I think there was a quite humorous 
Red Dwarf episode about that.

Possible typo: `process` should return a Cmd Command instead of Cmd Event 
if we're talking about the Process Manager pattern. I would also do a List 
instead of Maybe. (You can Cmd.batch them, and Cmd.none is actually 
implemented as Cmd.batch on an empty list)

Also, `process` is called incorrectly if it only uses Events to make 
decisions. It should be called with all history, not just the events 
generated from the one command. With only current events, it might be 
missing the information needed to know if a Command is warranted. RPG 
example: your game didn't have full history, so even though you got a 
GoblinSlayer sword 5 minutes ago, it didn't on turn Glow on when 
GoblinsEnteredTheArea.

`commandHandler` - I believe the definition of commandHandler as `Command 
-> Events -> Events` is too narrow. A command handler is often responsible 
for wrangling external resources (e.g. API calls). The only way to make 
this possible is to return `Cmd Events`. I also imagine it possible to 
perform some IO through Cmd and subsequently need to issue another Command 
to do something else with logic or IO. (Generally, I think multiple API 
calls would be handled better by an API gateway, but I wouldn't want to 
limit possibilities here.) I think Cmd Msg or Cmd (List Msg) would be more 
expected here.

As previously mentioned, I don't think it's a good idea to carry around the 
increment value and actually calculate it in the `eventHandler`. The 
relating of Incremented to the plus operator and Decremented to minus is 
logic, and logic should be under the command handler. Updating a model with 
event data should be as dumb as possible, because it should not have the 
possibility to fail when simply responding to facts. Not sure if plus/minus 
overflow in Elm (in JS, they flip sign on overflow), but other kinds of 
operators could.

On Wednesday, August 17, 2016 at 11:32:27 AM UTC-5, Marco Perone wrote:
>
> Hi!
>
> I was eventually able to read carefully the thread and give some thoughts 
> about it.
>
> @kasey, I had a look to your Gist and it looks really interesting! Some 
> notes about it:
>
> - I think it would be better to store in the parameter of the Fact's the 
> increment, and not the state of the application. It looks to me that you 
> are mixing two concerns, i.e. the state of the applications and the events 
> that happens to it
>
> - if I'm not mistaken, from you implementation it seems that only Act's 
> (and not Fact's) can generate new Cmd's. I think that is some applications 
> there could be the need to react automatically with a new Cmd to some 
> events that happened
>
> To make everything clearer in my mind, I wrote my own implementation of 
> something similar to what you did. You can find it here:
>
> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>
> It should be just a functional transposition of a standard es/cqrs 
> architecture (I actually used also es/cqrs jargon), adacted to the Elm 
> Architecture.
>
> I'd really like to know what you think of it. Let me know if something is 
> not clear enough
>
> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>>
>> So, I made a Gist 
>>  of 
>> the helper stuff which splits Facts and Acts. I call the helper Factor... 
>> (Fact or Act ~=> Factor). There is a subsequent comment with an example 
>> program explaining the helper's usage.
>>
>>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Kasey Speakman
Dunno why I didn't think of that. It should have been obvious to me.

On Wednesday, August 17, 2016 at 2:15:49 PM UTC-5, Evan wrote:
>
> Warning, I have not read everything here. About ignoring commands though, 
> think of the type of a Html.App.program
>
> program : { init, update, view, subscriptions } -> Program Never
>
> The essence of this is just a record. So you can wrap that record however 
> you want. Say like this:
>
> myProgram : ({ init, update, view, subscriptions } as details) =
>   { details | update = \msg model -> (fst (update msg model), Cmd.none) }
>
> Now you have programs that drop all commands.
>
> I'm in the process of revining elm-reactor to track history for exactly 
> the kinds of things you have in mind (testing, etc.) and I am using this 
> basic technique. Anyone can do this. You can write time-travel in pure Elm 
> this way. Make the update log all the messages it gets.
>
> Again, I have no idea what's happening in this discussion though, so 
> hopefully that's a helpful insight.
>
>
> On Thursday, August 11, 2016 at 10:37:48 AM UTC-7, Kasey Speakman wrote:
>>
>> Hi all,
>>
>> I'm getting to know Elm. I recently read this article 
>>  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 , 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Evan
Warning, I have not read everything here. About ignoring commands though, 
think of the type of a Html.App.program

program : { init, update, view, subscriptions } -> Program Never

The essence of this is just a record. So you can wrap that record however 
you want. Say like this:

myProgram : ({ init, update, view, subscriptions } as details) =
  { details | update = \msg model -> (fst (update msg model), Cmd.none) }

Now you have programs that drop all commands.

I'm in the process of revining elm-reactor to track history for exactly the 
kinds of things you have in mind (testing, etc.) and I am using this basic 
technique. Anyone can do this. You can write time-travel in pure Elm this 
way. Make the update log all the messages it gets.

Again, I have no idea what's happening in this discussion though, so 
hopefully that's a helpful insight.


On Thursday, August 11, 2016 at 10:37:48 AM UTC-7, Kasey Speakman wrote:
>
> Hi all,
>
> I'm getting to know Elm. I recently read this article 
>  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 , 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Marco Perone
@OvermindDL1, you're right, model.write is goin to get pretty huge. I
actually didn't try how far you could get with this approach until it
becomes a burden and starts to slow down the whole application. It'd be
really interesting to build a simple chat app with this approach and see
how big the model becomes.

A thing that come to mind that could help is use some data store (local
storage, for example) to persist the main part of the history and keep only
the latest events in memory

2016-08-17 18:49 GMT+02:00 OvermindDL1 :

> Hmm, interesting style, although I worry about how huge the model.write
> could get considering it saves every event ever. Say in a given chat app
> this could get amazingly huge.  How would that be handled in this pattern?
>
>
> On Wednesday, August 17, 2016 at 10:32:27 AM UTC-6, Marco Perone wrote:
>>
>> Hi!
>>
>> I was eventually able to read carefully the thread and give some thoughts
>> about it.
>>
>> @kasey, I had a look to your Gist and it looks really interesting! Some
>> notes about it:
>>
>> - I think it would be better to store in the parameter of the Fact's the
>> increment, and not the state of the application. It looks to me that you
>> are mixing two concerns, i.e. the state of the applications and the events
>> that happens to it
>>
>> - if I'm not mistaken, from you implementation it seems that only Act's
>> (and not Fact's) can generate new Cmd's. I think that is some applications
>> there could be the need to react automatically with a new Cmd to some
>> events that happened
>>
>> To make everything clearer in my mind, I wrote my own implementation of
>> something similar to what you did. You can find it here:
>>
>> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>>
>> It should be just a functional transposition of a standard es/cqrs
>> architecture (I actually used also es/cqrs jargon), adacted to the Elm
>> Architecture.
>>
>> I'd really like to know what you think of it. Let me know if something is
>> not clear enough
>>
>> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>>>
>>> So, I made a Gist
>>>  of
>>> the helper stuff which splits Facts and Acts. I call the helper Factor...
>>> (Fact or Act ~=> Factor). There is a subsequent comment with an example
>>> program explaining the helper's usage.
>>>
>>> --
> You received this message because you are subscribed to a topic in the
> Google Groups "Elm Discuss" group.
> To unsubscribe from this topic, visit https://groups.google.com/d/
> topic/elm-discuss/yKRYkoiQmPs/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> elm-discuss+unsubscr...@googlegroups.com.
> 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Kasey Speakman
Btw, the "event compression" only works for sequential messages of 
identical type (assuming idempotence). So Incremented 1, Incremented 2 
could compress to just Incremented 2, but Incremented 1, Decremented 0 
could not compress obviously. The counter example is bad here as it doesn't 
express how different the events can affect the model in orthogonal ways... 
all these events are affecting the same piece of data, so they could all be 
compressed down to the last event. But that's not a guarantee you can make 
in general.

On Wednesday, August 17, 2016 at 1:22:20 PM UTC-5, Kasey Speakman wrote:
>
> Thanks for the comment!
>
> - I think it would be better to store in the parameter of the Fact's the 
>> increment, and not the state of the application. It looks to me that you 
>> are mixing two concerns, i.e. the state of the applications and the events 
>> that happens to it
>>
>
> The counter example is too simple to properly express this, but the Fact 
> doesn't store the whole application state, only data applicable to the 
> event. For instance, imagine the apply function was `NameChanged name -> 
> {model | Name = name }`. It doesn't change the whole model, but it changes 
> a part of the model it applies to. In the counter example, the part 
> unfortunately happens to be the whole model.
>
> If the data instead carried the increment instead of the final value, then 
> the logic of how the counter works is decentralized... part of it (model + 
> 1, model - 1) is in the apply function now. You wouldn't put other kinds of 
> logic in the apply function (e.g. HTTP call). Storing the increment in the 
> event is also no longer idempotent. Idempotence is typically something you 
> want on the back-end because it allows you to deliver a message more than 
> once with no ill effects. However, it is valuable in the UI because it 
> could allow you to "compress" events to prevent history from getting too 
> large. For example, say someone spammed the Increment button 100 times, 
> giving you Incremented 1... Incremented 100. When applied in order, the 
> result is the same as just applying the last event of the same type; 
> Incremented 100. Now you are loosing history that way (and undo-ability), 
> but you can choose to make that trade-off for space without a deep 
> understanding of the events. In order to do the same if you were carrying 
> the increment, you would have understand what the event was doing and apply 
> logic to the messages to figure out the "compressed" message's data (add 
> the increments), so you have another place where you are putting logic.
>
> However, the compression benefit is probably mitigated by Elm not having a 
> way to determine if two union cases are the same type (no metaprogramming 
> that I know of). You'd have to manually check for specific sequential 
> messages you want to compress.
>
> - if I'm not mistaken, from you implementation it seems that only Act's 
>> (and not Fact's) can generate new Cmd's. I think that is some applications 
>> there could be the need to react automatically with a new Cmd to some 
>> events that happened
>>
>
> This (events to commands, aka Process Manager aka Saga) is not covered in 
> my example. Seems like the easiest way to accomplish this is to have 3rd 
> method which is called after `apply` that checks the model (or the part 
> where the process manager has been keeping track of state) to see if a new 
> Act needs to be issued. Maybe something like this:
>
> propose : Model -> Cmd Act
> propose model =
>   if model.orderProcess.orderPlaced && model.orderProcess.paymentFailed 
> then
> CancelOrder model.orderProcess.orderId |> actCmd
>   else if model.orderProcess.orderPlaced && model.orderProcess.paidInFull 
> then
> ShipOrder model.orderProcess.orderId |> actCmd
>   else
> Cmd.none
>
> That's assuming your `apply` method is updating the model with those flags 
> in response to the appropriate events. Of course, this particular logic 
> doesn't make sense on the front end, but this type of pattern could.
>
> On Wednesday, August 17, 2016 at 11:32:27 AM UTC-5, Marco Perone wrote:
>>
>> Hi!
>>
>> I was eventually able to read carefully the thread and give some thoughts 
>> about it.
>>
>> @kasey, I had a look to your Gist and it looks really interesting! Some 
>> notes about it:
>>
>> - I think it would be better to store in the parameter of the Fact's the 
>> increment, and not the state of the application. It looks to me that you 
>> are mixing two concerns, i.e. the state of the applications and the events 
>> that happens to it
>>
>> - if I'm not mistaken, from you implementation it seems that only Act's 
>> (and not Fact's) can generate new Cmd's. I think that is some applications 
>> there could be the need to react automatically with a new Cmd to some 
>> events that happened
>>
>> To make everything clearer in my mind, I wrote my own implementation of 
>> something similar to what you did. You can find it here:
>>

[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Kasey Speakman
Thanks for the comment!

- I think it would be better to store in the parameter of the Fact's the 
> increment, and not the state of the application. It looks to me that you 
> are mixing two concerns, i.e. the state of the applications and the events 
> that happens to it
>

The counter example is too simple to properly express this, but the Fact 
doesn't store the whole application state, only data applicable to the 
event. For instance, imagine the apply function was `NameChanged name -> 
{model | Name = name }`. It doesn't change the whole model, but it changes 
a part of the model it applies to. In the counter example, the part 
unfortunately happens to be the whole model.

If the data instead carried the increment instead of the final value, then 
the logic of how the counter works is decentralized... part of it (model + 
1, model - 1) is in the apply function now. You wouldn't put other kinds of 
logic in the apply function (e.g. HTTP call). Storing the increment in the 
event is also no longer idempotent. Idempotence is typically something you 
want on the back-end because it allows you to deliver a message more than 
once with no ill effects. However, it is valuable in the UI because it 
could allow you to "compress" events to prevent history from getting too 
large. For example, say someone spammed the Increment button 100 times, 
giving you Incremented 1... Incremented 100. When applied in order, the 
result is the same as just applying the last event of the same type; 
Incremented 100. Now you are loosing history that way (and undo-ability), 
but you can choose to make that trade-off for space without a deep 
understanding of the events. In order to do the same if you were carrying 
the increment, you would have understand what the event was doing and apply 
logic to the messages to figure out the "compressed" message's data (add 
the increments), so you have another place where you are putting logic.

However, the compression benefit is probably mitigated by Elm not having a 
way to determine if two union cases are the same type (no metaprogramming 
that I know of). You'd have to manually check for specific sequential 
messages you want to compress.

- if I'm not mistaken, from you implementation it seems that only Act's 
> (and not Fact's) can generate new Cmd's. I think that is some applications 
> there could be the need to react automatically with a new Cmd to some 
> events that happened
>

This (events to commands, aka Process Manager aka Saga) is not covered in 
my example. Seems like the easiest way to accomplish this is to have 3rd 
method which is called after `apply` that checks the model (or the part 
where the process manager has been keeping track of state) to see if a new 
Act needs to be issued. Maybe something like this:

propose : Model -> Cmd Act
propose model =
  if model.orderProcess.orderPlaced && model.orderProcess.paymentFailed then
CancelOrder model.orderProcess.orderId |> actCmd
  else if model.orderProcess.orderPlaced && model.orderProcess.paidInFull 
then
ShipOrder model.orderProcess.orderId |> actCmd
  else
Cmd.none

That's assuming your `apply` method is updating the model with those flags 
in response to the appropriate events. Of course, this particular logic 
doesn't make sense on the front end, but this type of pattern could.

On Wednesday, August 17, 2016 at 11:32:27 AM UTC-5, Marco Perone wrote:
>
> Hi!
>
> I was eventually able to read carefully the thread and give some thoughts 
> about it.
>
> @kasey, I had a look to your Gist and it looks really interesting! Some 
> notes about it:
>
> - I think it would be better to store in the parameter of the Fact's the 
> increment, and not the state of the application. It looks to me that you 
> are mixing two concerns, i.e. the state of the applications and the events 
> that happens to it
>
> - if I'm not mistaken, from you implementation it seems that only Act's 
> (and not Fact's) can generate new Cmd's. I think that is some applications 
> there could be the need to react automatically with a new Cmd to some 
> events that happened
>
> To make everything clearer in my mind, I wrote my own implementation of 
> something similar to what you did. You can find it here:
>
> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>
> It should be just a functional transposition of a standard es/cqrs 
> architecture (I actually used also es/cqrs jargon), adacted to the Elm 
> Architecture.
>
> I'd really like to know what you think of it. Let me know if something is 
> not clear enough
>
> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>>
>> So, I made a Gist 
>>  of 
>> the helper stuff which splits Facts and Acts. I call the helper Factor... 
>> (Fact or Act ~=> Factor). There is a subsequent comment with an example 
>> program explaining the helper's usage.
>>
>>

-- 
You received this message because 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread OvermindDL1
Hmm, interesting style, although I worry about how huge the model.write 
could get considering it saves every event ever. Say in a given chat app 
this could get amazingly huge.  How would that be handled in this pattern?


On Wednesday, August 17, 2016 at 10:32:27 AM UTC-6, Marco Perone wrote:
>
> Hi!
>
> I was eventually able to read carefully the thread and give some thoughts 
> about it.
>
> @kasey, I had a look to your Gist and it looks really interesting! Some 
> notes about it:
>
> - I think it would be better to store in the parameter of the Fact's the 
> increment, and not the state of the application. It looks to me that you 
> are mixing two concerns, i.e. the state of the applications and the events 
> that happens to it
>
> - if I'm not mistaken, from you implementation it seems that only Act's 
> (and not Fact's) can generate new Cmd's. I think that is some applications 
> there could be the need to react automatically with a new Cmd to some 
> events that happened
>
> To make everything clearer in my mind, I wrote my own implementation of 
> something similar to what you did. You can find it here:
>
> https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm
>
> It should be just a functional transposition of a standard es/cqrs 
> architecture (I actually used also es/cqrs jargon), adacted to the Elm 
> Architecture.
>
> I'd really like to know what you think of it. Let me know if something is 
> not clear enough
>
> On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>>
>> So, I made a Gist 
>>  of 
>> the helper stuff which splits Facts and Acts. I call the helper Factor... 
>> (Fact or Act ~=> Factor). There is a subsequent comment with an example 
>> program explaining the helper's usage.
>>
>>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-17 Thread Marco Perone
Hi!

I was eventually able to read carefully the thread and give some thoughts 
about it.

@kasey, I had a look to your Gist and it looks really interesting! Some 
notes about it:

- I think it would be better to store in the parameter of the Fact's the 
increment, and not the state of the application. It looks to me that you 
are mixing two concerns, i.e. the state of the applications and the events 
that happens to it

- if I'm not mistaken, from you implementation it seems that only Act's 
(and not Fact's) can generate new Cmd's. I think that is some applications 
there could be the need to react automatically with a new Cmd to some 
events that happened

To make everything clearer in my mind, I wrote my own implementation of 
something similar to what you did. You can find it here:

https://github.com/marcosh/elm-escqrs/blob/master/EsCqrsMain.elm

It should be just a functional transposition of a standard es/cqrs 
architecture (I actually used also es/cqrs jargon), adacted to the Elm 
Architecture.

I'd really like to know what you think of it. Let me know if something is 
not clear enough

On Sunday, August 14, 2016 at 7:37:25 AM UTC+2, Kasey Speakman wrote:
>
> So, I made a Gist 
>  of 
> the helper stuff which splits Facts and Acts. I call the helper Factor... 
> (Fact or Act ~=> Factor). There is a subsequent comment with an example 
> program explaining the helper's usage.
>
>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-13 Thread Kasey Speakman
So, I made a Gist 
 of the 
helper stuff which splits Facts and Acts. I call the helper Factor... (Fact 
or Act ~=> Factor). There is a subsequent comment with an example program 
explaining the helper's usage.

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-12 Thread Kasey Speakman
Hmm, union types are JSON-serializable elsewhere (e.g. JSON.NET, although 
they are gly in JSON), so just something that eventually needs doing I 
suppose.

What conversion method did you have in mind that's not hard?

On Friday, August 12, 2016 at 1:59:43 PM UTC-5, OvermindDL1 wrote:
>
> I entirely missed that.  ^.^
>
> Hmm, is interesting.  Flags take Json'able types so those would not be 
> passable there, would need to convert first, but not hard.
>
>
>
> On Friday, August 12, 2016 at 12:53:36 PM UTC-6, Kasey Speakman wrote:
>>
>> I did that if you look at link to marcosh's github I posted above.
>>
>> On Friday, August 12, 2016 at 1:50:12 PM UTC-5, OvermindDL1 wrote:
>>>
>>> Hmm, I'd be curious if you could whip up a full compileable example, say 
>>> a Multi-Counter project example we could paste into elm-try.  Perhaps mark 
>>> things that are boilerplate and could be hoisted out to a parent library 
>>> too so we can ignore those?  :-)
>>>
>>>
>>> On Friday, August 12, 2016 at 12:15:20 PM UTC-6, Kasey Speakman wrote:

 Skimming through the code, it looks like batch commands will happen in 
 order. The mentioned `mailbox.push` was from the Elm source code.

 Also, I fleshed out an example with both a clean separation and using 
 event sourcing. I posted it with some commentary on marcosh's github 
 .

 I like the terminology in this example much better than my previous 
 examples, especially because `Action` was a previous concept in Elm.

 type Act = Increment | Decrement

 type Fact = Incremented Int | Decremented Int

 type Msg = Perform Act | Apply Fact

 perform : Act -> Model -> Cmd Msg

 apply : Fact -> Model -> Model

 update : Msg -> Model -> (Model, Cmd Msg)
 update msg model =
   case msg of
 Perform act ->
   (model, perform act model)

 Apply fact ->
   (apply fact model, Cmd.none)


 The Facts here are also idempotent 
  (no dependency on previous 
 values). That's not as important in this example, but can as its extended.

 On Friday, August 12, 2016 at 9:15:23 AM UTC-5, OvermindDL1 wrote:
>
> Will your pushed command appear after or before a potentially pushed 
> 'other' command, say from an incoming port, or button click?  That is the 
> part I am not sure about yet (not read enough Elm internals 'quite' yet).
>
> On Thursday, August 11, 2016 at 6:31:06 PM UTC-6, Kasey Speakman wrote:
>>
>> Checked the current implementation of Cmd.batch and it appears 
>> sequential (`mailbox.push`). Ordering guarantees are not documented so I 
>> suppose they shouldn't be depended on. But otherwise, the one I coded 
>> above 
>> that guarantees Act doesn't change the model and Evt doesn't have 
>> effects 
>> would work.
>>
>> On Thursday, August 11, 2016 at 6:33:39 PM UTC-5, Kasey Speakman 
>> wrote:
>>>
>>> Yes, that's why I said back to square one if Cmd.batch isn't 
>>> ordered. The only thing this is guaranteeing (and the only intended 
>>> guarantee) is that the messages which only update the model are 
>>> separated 
>>> from the ones which cause effects. The ones which cause effects produce 
>>> ones which update the model, same as always.
>>>
>>> It occurs to me that some of the benefit of event sourcing the UI 
>>> could be gained by adding features to the TTD, since it has the magic 
>>> which 
>>> ignores Cmds on replay. Some are already listed as ideas at 
>>> http://debug.elm-lang.org/. I'd still have to keep the messages in 
>>> my model and provide a way for the user to transmit them in a bug 
>>> report. 
>>> But if I could load them in the TTD, that would make repro a snap.
>>>
>>> On Thursday, August 11, 2016 at 5:22:05 PM UTC-5, OvermindDL1 wrote:

 Isn't `doSideEffects` basically just the current `update` function 
 though?  Except it is returning a list of changes (via message) to 
 perform 
 to a model instead of doing it in-place?  What is this saving 
 precisely?



 On Thursday, August 11, 2016 at 4:05:57 PM UTC-6, Kasey Speakman 
 wrote:
>
> Actually, I'd probably use a List instead of Maybe on the 
> immediately returned event(s).
>
> doSideEffects : Act -> Model -> (List Evt, Cmd Evt)
> doSideEffects act model = 
>   case act of
> UpdateCustomer customer ->
>   ( [ CustomerUpdateRequested ]
>   , callServerWithCustomer customer
>   )
>
> ...
>
> updateModel : Evt -> Model -> Model
> ... -- implementation as previous
>
> 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-12 Thread OvermindDL1
Hmm, I'd be curious if you could whip up a full compileable example, say a 
Multi-Counter project example we could paste into elm-try.  Perhaps mark 
things that are boilerplate and could be hoisted out to a parent library 
too so we can ignore those?  :-)


On Friday, August 12, 2016 at 12:15:20 PM UTC-6, Kasey Speakman wrote:
>
> Skimming through the code, it looks like batch commands will happen in 
> order. The mentioned `mailbox.push` was from the Elm source code.
>
> Also, I fleshed out an example with both a clean separation and using 
> event sourcing. I posted it with some commentary on marcosh's github 
> .
>
> I like the terminology in this example much better than my previous 
> examples, especially because `Action` was a previous concept in Elm.
>
> type Act = Increment | Decrement
>
> type Fact = Incremented Int | Decremented Int
>
> type Msg = Perform Act | Apply Fact
>
> perform : Act -> Model -> Cmd Msg
>
> apply : Fact -> Model -> Model
>
> update : Msg -> Model -> (Model, Cmd Msg)
> update msg model =
>   case msg of
> Perform act ->
>   (model, perform act model)
>
> Apply fact ->
>   (apply fact model, Cmd.none)
>
>
> The Facts here are also idempotent 
>  (no dependency on previous 
> values). That's not as important in this example, but can as its extended.
>
> On Friday, August 12, 2016 at 9:15:23 AM UTC-5, OvermindDL1 wrote:
>>
>> Will your pushed command appear after or before a potentially pushed 
>> 'other' command, say from an incoming port, or button click?  That is the 
>> part I am not sure about yet (not read enough Elm internals 'quite' yet).
>>
>> On Thursday, August 11, 2016 at 6:31:06 PM UTC-6, Kasey Speakman wrote:
>>>
>>> Checked the current implementation of Cmd.batch and it appears 
>>> sequential (`mailbox.push`). Ordering guarantees are not documented so I 
>>> suppose they shouldn't be depended on. But otherwise, the one I coded above 
>>> that guarantees Act doesn't change the model and Evt doesn't have effects 
>>> would work.
>>>
>>> On Thursday, August 11, 2016 at 6:33:39 PM UTC-5, Kasey Speakman wrote:

 Yes, that's why I said back to square one if Cmd.batch isn't ordered. 
 The only thing this is guaranteeing (and the only intended guarantee) is 
 that the messages which only update the model are separated from the ones 
 which cause effects. The ones which cause effects produce ones which 
 update 
 the model, same as always.

 It occurs to me that some of the benefit of event sourcing the UI could 
 be gained by adding features to the TTD, since it has the magic which 
 ignores Cmds on replay. Some are already listed as ideas at 
 http://debug.elm-lang.org/. I'd still have to keep the messages in my 
 model and provide a way for the user to transmit them in a bug report. But 
 if I could load them in the TTD, that would make repro a snap.

 On Thursday, August 11, 2016 at 5:22:05 PM UTC-5, OvermindDL1 wrote:
>
> Isn't `doSideEffects` basically just the current `update` function 
> though?  Except it is returning a list of changes (via message) to 
> perform 
> to a model instead of doing it in-place?  What is this saving precisely?
>
>
>
> On Thursday, August 11, 2016 at 4:05:57 PM UTC-6, Kasey Speakman wrote:
>>
>> Actually, I'd probably use a List instead of Maybe on the immediately 
>> returned event(s).
>>
>> doSideEffects : Act -> Model -> (List Evt, Cmd Evt)
>> doSideEffects act model = 
>>   case act of
>> UpdateCustomer customer ->
>>   ( [ CustomerUpdateRequested ]
>>   , callServerWithCustomer customer
>>   )
>>
>> ...
>>
>> updateModel : Evt -> Model -> Model
>> ... -- implementation as previous
>>
>> update : Msg -> Model -> (Model, Cmd Msg)
>> update msg model =
>>   case msg of
>> Action act ->
>>   let
>> (events, command) = doSideEffects act model
>>   in
>> (List.foldr updateModel model events, Cmd.map Evt command)
>>
>> Event evt ->
>>   (updateModel evt model, Cmd.none)
>>
>>
>>
>> On Thursday, August 11, 2016 at 4:26:03 PM UTC-5, Kasey Speakman 
>> wrote:
>>>
>>> Yes, that was the goal. That way the UI state is utterly 
>>> deterministic / reproducible in isolation of all outside services.
>>>
>>> That's a good point on the race conditions. I only use Cmd.batch 
>>> because it's the facility that came to mind. (I'm still getting 
>>> acquainted 
>>> with Elm.) I don't know if Cmd.batch makes any ordering guarantee.
>>>
>>> If not we'd be more or less back to square one. Abuse `update` to do 
>>> both things.
>>>
>>> doSideEffects: Act -> Model -> (Maybe Evt, Cmd Evt)
>>> 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread Kasey Speakman
Yes, that's why I said back to square one if Cmd.batch isn't ordered. The 
only thing this is guaranteeing (and the only intended guarantee) is that 
the messages which only update the model are separated from the ones which 
cause effects. The ones which cause effects produce ones which update the 
model, same as always.

It occurs to me that some of the benefit of event sourcing the UI could be 
gained by adding features to the TTD, since it has the magic which ignores 
Cmds on replay. Some are already listed as ideas at 
http://debug.elm-lang.org/. I'd still have to keep the messages in my model 
and provide a way for the user to transmit them in a bug report. But if I 
could load them in the TTD, that would make repro a snap.

On Thursday, August 11, 2016 at 5:22:05 PM UTC-5, OvermindDL1 wrote:
>
> Isn't `doSideEffects` basically just the current `update` function 
> though?  Except it is returning a list of changes (via message) to perform 
> to a model instead of doing it in-place?  What is this saving precisely?
>
>
>
> On Thursday, August 11, 2016 at 4:05:57 PM UTC-6, Kasey Speakman wrote:
>>
>> Actually, I'd probably use a List instead of Maybe on the immediately 
>> returned event(s).
>>
>> doSideEffects : Act -> Model -> (List Evt, Cmd Evt)
>> doSideEffects act model = 
>>   case act of
>> UpdateCustomer customer ->
>>   ( [ CustomerUpdateRequested ]
>>   , callServerWithCustomer customer
>>   )
>>
>> ...
>>
>> updateModel : Evt -> Model -> Model
>> ... -- implementation as previous
>>
>> update : Msg -> Model -> (Model, Cmd Msg)
>> update msg model =
>>   case msg of
>> Action act ->
>>   let
>> (events, command) = doSideEffects act model
>>   in
>> (List.foldr updateModel model events, Cmd.map Evt command)
>>
>> Event evt ->
>>   (updateModel evt model, Cmd.none)
>>
>>
>>
>> On Thursday, August 11, 2016 at 4:26:03 PM UTC-5, Kasey Speakman wrote:
>>>
>>> Yes, that was the goal. That way the UI state is utterly deterministic / 
>>> reproducible in isolation of all outside services.
>>>
>>> That's a good point on the race conditions. I only use Cmd.batch because 
>>> it's the facility that came to mind. (I'm still getting acquainted with 
>>> Elm.) I don't know if Cmd.batch makes any ordering guarantee.
>>>
>>> If not we'd be more or less back to square one. Abuse `update` to do 
>>> both things.
>>>
>>> doSideEffects: Act -> Model -> (Maybe Evt, Cmd Evt)
>>> doSideEffects act model =
>>>   case act of
>>> UpdateCustomer customer ->
>>>   (Just CustomerUpdateRequested, callServerWithCustomer customer)
>>>
>>> ...
>>>
>>> updateModel: Evt -> Model -> Model
>>> ... -- implementation as previous
>>>
>>> maybeUpdateModel:  Maybe Evt -> Model -> Model
>>> maybeUpdateModel evtOpt model =
>>>   case evtOpt of
>>> Nothing ->
>>>   model
>>>
>>> Just evt ->
>>>   updateModel evt model
>>>
>>> update : Msg -> Model -> (Model, Cmd Msg)
>>> update msg model =
>>>   case msg of
>>> Action act ->
>>>   let
>>> (eventNow, command) = doSideEffects act model
>>>   in
>>> (maybeUpdateModel eventNow model, Cmd.map Evt command)
>>>
>>> Event evt ->
>>>   (updateModel evt model, Cmd.none)
>>>
>>> So this should apply an event immediately if one is needed for the 
>>> action. But it still keeps the model updating events separate.
>>>
>>> These immediate events would be seen by a userland event-store 
>>> implementation (which is underneath updateModel), but I bet the TTD 
>>> wouldn't see it since it doesn't come from Elm.
>>>
>>> On Thursday, August 11, 2016 at 3:43:36 PM UTC-5, OvermindDL1 wrote:

 So you really are wanting to hard device events into two different 
 ones, those that can *only* alter the model, and those that can *only* 
 send 
 commands (which may call ones that alter the model).  Unsure if it might 
 actually happen but might have to take into account possible race 
 conditions for if other messages appear before your other expected ones 
 are 
 processed through?  Easier to do that atomically all at once?


 On Thursday, August 11, 2016 at 2:25:22 PM UTC-6, Kasey Speakman wrote:
>
> doSideEffects above would also have to map Cmd Evt to Cmd Msg.
>


-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread Kasey Speakman
Actually, I'd probably use a List instead of Maybe on the immediately 
returned event(s).

doSideEffects : Act -> Model -> (List Evt, Cmd Evt)
doSideEffects act model = 
  case act of
UpdateCustomer customer ->
  ( [ CustomerUpdateRequested ]
  , callServerWithCustomer customer
  )

...

updateModel : Evt -> Model -> Model
... -- implementation as previous

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
Action act ->
  let
(events, command) = doSideEffects act model
  in
(List.foldr updateModel model events, Cmd.map Evt command)

Event evt ->
  (updateModel evt model, Cmd.none)



On Thursday, August 11, 2016 at 4:26:03 PM UTC-5, Kasey Speakman wrote:
>
> Yes, that was the goal. That way the UI state is utterly deterministic / 
> reproducible in isolation of all outside services.
>
> That's a good point on the race conditions. I only use Cmd.batch because 
> it's the facility that came to mind. (I'm still getting acquainted with 
> Elm.) I don't know if Cmd.batch makes any ordering guarantee.
>
> If not we'd be more or less back to square one. Abuse `update` to do both 
> things.
>
> doSideEffects: Act -> Model -> (Maybe Evt, Cmd Evt)
> doSideEffects act model =
>   case act of
> UpdateCustomer customer ->
>   (Just CustomerUpdateRequested, callServerWithCustomer customer)
>
> ...
>
> updateModel: Evt -> Model -> Model
> ... -- implementation as previous
>
> maybeUpdateModel:  Maybe Evt -> Model -> Model
> maybeUpdateModel evtOpt model =
>   case evtOpt of
> Nothing ->
>   model
>
> Just evt ->
>   updateModel evt model
>
> update : Msg -> Model -> (Model, Cmd Msg)
> update msg model =
>   case msg of
> Action act ->
>   let
> (eventNow, command) = doSideEffects act model
>   in
> (maybeUpdateModel eventNow model, Cmd.map Evt command)
>
> Event evt ->
>   (updateModel evt model, Cmd.none)
>
> So this should apply an event immediately if one is needed for the action. 
> But it still keeps the model updating events separate.
>
> These immediate events would be seen by a userland event-store 
> implementation (which is underneath updateModel), but I bet the TTD 
> wouldn't see it since it doesn't come from Elm.
>
> On Thursday, August 11, 2016 at 3:43:36 PM UTC-5, OvermindDL1 wrote:
>>
>> So you really are wanting to hard device events into two different ones, 
>> those that can *only* alter the model, and those that can *only* send 
>> commands (which may call ones that alter the model).  Unsure if it might 
>> actually happen but might have to take into account possible race 
>> conditions for if other messages appear before your other expected ones are 
>> processed through?  Easier to do that atomically all at once?
>>
>>
>> On Thursday, August 11, 2016 at 2:25:22 PM UTC-6, Kasey Speakman wrote:
>>>
>>> doSideEffects above would also have to map Cmd Evt to Cmd Msg.
>>>
>>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread OvermindDL1
So you really are wanting to hard device events into two different ones, 
those that can *only* alter the model, and those that can *only* send 
commands (which may call ones that alter the model).  Unsure if it might 
actually happen but might have to take into account possible race 
conditions for if other messages appear before your other expected ones are 
processed through?  Easier to do that atomically all at once?


On Thursday, August 11, 2016 at 2:25:22 PM UTC-6, Kasey Speakman wrote:
>
> doSideEffects above would also have to map Cmd Evt to Cmd Msg.
>

-- 
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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread Kasey Speakman
My mistake, SubmitCustomerChanges was supposed to be UpdateCustomer above.

On Thursday, August 11, 2016 at 3:16:12 PM UTC-5, Kasey Speakman wrote:
>
> Oh! What I was doing in my examples was pretending there was a version of 
> Elm that natively supported `command` and `update` methods instead of just 
> `update`. I was exploring what that could look like, how it would affect 
> things.
>
> I don't have a complete example in mind. The original post was more to get 
> the idea out there and discuss it.
>
> So, I suppose I could also explore putting the command/event separation 
> into practice as subsets of Msg which should work with non-imaginary Elm.
>
> type Act
>   = UpdateCustomer customer
>   | ... -- another command
>
> type Evt
>   = NameChanged name
>   | CustomerUpdateRequested
>   | CustomerUpdateFailed err
>   | CustomerUpdateSucceeded
>
> type Msg
>   = Action act
>   | Event evt
>
> doSideEffects: Act -> Model -> Cmd Evt
> doSideEffects act model =
>   case act of
> SubmitCustomerChanges customer ->
>   Cmd.batch
> [ Cmd.fromEvt CustomerUpdateRequested
> , callServerWithCustomer customer -- or model.Customer?
> ]
>
> ...
>
> updateModel: Evt -> Model -> Model
> ... -- implementation as previous
>
> update : Msg -> Model -> (Model, Cmd Msg)
> update msg model =
>   case msg of
> Action act ->
>   (model, doSideEffects act model)
>
> Event evt ->
>   (updateModel evt model, Cmd.none)
>
> Apologize for errors... writing code in this groups editor.
>
> Anyway, this is the other choice I mentioned where you could let the view 
> send either a command or event. This could prevent redundant "commands", 
> example: `onInput`s which only change the model could issue an event 
> directly instead of a command first. I thought this would require more 
> discipline to use, but now that I see it, I think using "commands" (Action 
> above) and "events" appropriately is enforced by `update`. If you want an 
> event when an action happens, you could use a Cmd.batch (as in 
> CustomerUpdateRequested above). That enforces model updates being separate 
> messages from effects.
>
> For event-sourcing, you could replay only the `Event`s in complete 
> isolation of the outside world to arrive at an interesting UI state. For 
> example, an incorrect state that was bug reported.
>
> On Thursday, August 11, 2016 at 2:21:42 PM UTC-5, Kasey Speakman wrote:
>>
>> 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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread Kasey Speakman
Oh! What I was doing in my examples was pretending there was a version of 
Elm that natively supported `command` and `update` methods instead of just 
`update`. I was exploring what that could look like, how it would affect 
things.

I don't have a complete example in mind. The original post was more to get 
the idea out there and discuss it.

So, I suppose I could also explore putting the command/event separation 
into practice as subsets of Msg which should work with non-imaginary Elm.

type Act
  = UpdateCustomer customer
  | ... -- another command

type Evt
  = NameChanged name
  | CustomerUpdateRequested
  | CustomerUpdateFailed err
  | CustomerUpdateSucceeded

type Msg
  = Action act
  | Event evt

doSideEffects: Act -> Model -> Cmd Evt
doSideEffects act model =
  case act of
SubmitCustomerChanges customer ->
  Cmd.batch
[ Cmd.fromEvt CustomerUpdateRequested
, callServerWithCustomer customer -- or model.Customer?
]

...

updateModel: Evt -> Model -> Model
... -- implementation as previous

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
Action act ->
  (model, doSideEffects act model)

Event evt ->
  (updateModel evt model, Cmd.none)

Apologize for errors... writing code in this groups editor.

Anyway, this is the other choice I mentioned where you could let the view 
send either a command or event. This could prevent redundant "commands", 
example: `onInput`s which only change the model could issue an event 
directly instead of a command first. I thought this would require more 
discipline to use, but now that I see it, I think using "commands" (Action 
above) and "events" appropriately is enforced by `update`. If you want an 
event when an action happens, you could use a Cmd.batch (as in 
CustomerUpdateRequested above). That enforces model updates being separate 
messages from effects.

For event-sourcing, you could replay only the `Event`s in complete 
isolation of the outside world to arrive at an interesting UI state. For 
example, an incorrect state that was bug reported.

On Thursday, August 11, 2016 at 2:21:42 PM UTC-5, Kasey Speakman wrote:
>
> 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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread OvermindDL1
Can you supply a complete example of what you want it to look like 
(excepting view, we don't care about view right now).?


On Thursday, August 11, 2016 at 1:25:38 PM UTC-6, OvermindDL1 wrote:
>
> In this case it is just filling in for 'something' that can dispatch some 
> messages to `update` and dispatch commands to `command`.  I'm not sure how 
> to dispatch those without some dispatcher that is already acting like the 
> existing update...
>
>
> On Thursday, August 11, 2016 at 1:21:42 PM UTC-6, Kasey Speakman wrote:
>>
>> 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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread OvermindDL1
In this case it is just filling in for 'something' that can dispatch some 
messages to `update` and dispatch commands to `command`.  I'm not sure how 
to dispatch those without some dispatcher that is already acting like the 
existing update...


On Thursday, August 11, 2016 at 1:21:42 PM UTC-6, Kasey Speakman wrote:
>
> 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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread Kasey Speakman
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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread OvermindDL1
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 

[elm-discuss] Re: More thorough side-effect isolation

2016-08-11 Thread OvermindDL1
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 
>>  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 , 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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.