Commands and Events vs the Elm Architecture

290 views
Skip to first unread message

Thomas Coopman

unread,
Nov 5, 2015, 5:34:02 AM11/5/15
to Elm Discuss
I've been playing with Elm for a while now and I love it very much, so much that I'm thinking about writing a new project in it (instead of React and Redux).

Now I've been thinking about the Elm Architecture for a while where you have these functions:

update : Action -> Model -> (Model, Effects Action)
view : Signal.Address Action -> Model -> Html

What I'd love to do, is make a separation between Commands and Events, where in the current architecture you only have explicit Commands (= Action) and no real Events (The Action you received via Effects could be seen as an Event).
I was thinking along these lines:

updateEvents : Command -> Model -> (Event, Effects Event)
update : Event -> Model -> Model
view : Signal.Address Command -> Model -> Html

As far as I can tell, this gives me stricter separation to execute business logic on the server.

When I take the gif example from the architecture tutorial, I would change that to:

type Command = RequestMore
    
type Event
  = MoreRequested
  | GifReceived String

In the tutorial, your update function would have both the Action to request a new gif, and the Event when a new gif is received.
My updateEvents function would only be responsible for creating events and speaking with the api. The update function would translate events to a new model:

updateEvents : Command -> Model -> (Event, Effects Event)
update cmd model =
  case cmd of
    RequestMore ->
      ( MoreRequested
      , getRandomGif model.topic
      )

update : Event -> Model -> Model
update event model =
  case event of
    MoreRequest ->
      -- Optimistic update or loading
    GifReceived gif ->
      -- ....


This code is just a brainstorm, I just wanted to discuss a bit about this idea:
  • Has anyone tried something like this?
  • Do you think it is a good or bad idea, and why?
  • Do you see any problems with it (like how to connect the Signals)?
  • For smaller projects this probably is overhead?
I think I'm going to play a bit more with the ideas above, but please let me know what you think about it.



Jeff Smits

unread,
Nov 5, 2015, 5:56:53 AM11/5/15
to elm-discuss

If this distinction makes sense, you should try it :) It looks useful. Maybe it’ll be useful enough to create an adaption of start-app that works with this.

For now you can fit this into the Elm Architecture too (if I understood the idea correctly):

type Action =
    Command Command
  | Event Event

stdUpdate : Action -> Model -> (Model, Effects Action)
stdUpdate action model = case action of
  Command command -> 
    let
      (event, effects) = updateEvents command model
    in
      (update event model, Effects.map Event effects)
  Event event ->
    (update event model, Effects.none)

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

Thomas Coopman

unread,
Nov 5, 2015, 6:31:42 AM11/5/15
to elm-discuss

That's a nice idea to start with. Thanks.

I'll try both options and see what's most useful


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/yKTd9sETFQk/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.

Thomas Coopman

unread,
Nov 11, 2015, 3:43:20 AM11/11/15
to Elm Discuss
So I've been a bit busy and I only found the time to play with it some more now, but I'm running into some issues.

Based on StartApp and the gif example from the elm-architecture I've created this: https://gist.github.com/tcoopman/0e6e2e90ef81e674ec30

The problem is that the updateEvents function causes a crash:

type Command = RequestMore
updateEvents : Command -> Model -> (Event, Effects Event)
updateEvents cmd model =
  case cmd of
    RequestMore -> (MoreRequested, getRandomGif model.topic)
    _ -> Debug.crash "how is this possible????"

My code crashes with "how is this possible????".
I don't think my code is complete yet, but I'm pretty sure that this shouldn't happen, as there is only one type of Command?
It looks like:

getRandomGif : String -> Effects Event
getRandomGif topic =
  Http.get decodeUrl (randomUrl topic)
    |> Task.toMaybe
    |> Task.map (Debug.log "new gif" NewGif)
    |> Effects.task

routes the result of the task to updateEvents instead of update.

There is probably something wrong with my code, but it looks like the Elm compiler should have caught it?

Thanks

Janis Voigtländer

unread,
Nov 11, 2015, 7:36:50 AM11/11/15
to elm-d...@googlegroups.com

You are not seeing ghosts. It is indeed the case that in your code the function

updateEvents : Command -> Model -> (Event, Effects Event)

gets called with an Event as the first argument, and the Elm compiler does not prevent that from happening, despite knowing that Command and Event are non-unifiable types.

But why does the type checker not catch this? It is this known problem.

A worrying thought now is: Does the “official” start-app version also suffer from this? Can one write a program with start-app that subverts type soundness?


Thomas Coopman

unread,
Nov 11, 2015, 8:04:49 AM11/11/15
to Elm Discuss
Thanks!

Now I can search on to get my code working. Signals and Effects require a bit of work to understand completely.
Reply all
Reply to author
Forward
0 new messages