Re: [elm-discuss] Re: How do you handle dependencies between updaters?
On Tuesday, March 21, 2017 at 10:57:43 PM UTC, Mark Hamburg wrote: > > We've done that as well in places. But I was mostly looking for an example > of how to access extra data during an update. > > On Tue, Mar 21, 2017 at 3:20 PM, 'Rupert Smith' via Elm Discuss < > elm-d...@googlegroups.com > wrote: > >> Why not use a secure cookie? Then the browser adds it to the request for >> you. It is also more secure and has the advantage that if the user >> CTRL+clicks a link in your application opening up the same application in >> >1 tab, that the cookies flow across automatically. >> > The reason I pointed this out is that the auth module is one that is likely to be needed from a lot of places, so is likely to be at the heart of the dependency graph of an application. For that reason, I decided to treat it differently. At first I set up ports so that any module importing Auth could directly pass it login/logout/refresh/unauthed requests. Then I changed it to use messaging implemented as an effects manager: https://github.com/rupertlssmith/elmq. I only did this for my Auth module, although it could be done for any inter-module communication. Really helped to simplify the dependency matrix. -- 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: How do you handle dependencies between updaters?
We've done that as well in places. But I was mostly looking for an example of how to access extra data during an update. Another example from our codebase is accessing the User record (name, email address, etc) which we store at the top of the session model. The updater for a more specific state can send an out message up the stack to get the user record for use in the update without needing to store a copy of the data in the state or plumb through passing it down everywhere. That said, it isn't clear how that plumbing compares to the out message plumbing which is not insubstantial. But using out messages to retrieve values does avoid having huge and seemingly haphazard parameter lists. Mark On Tue, Mar 21, 2017 at 3:20 PM, 'Rupert Smith' via Elm Discuss < elm-discuss@googlegroups.com> wrote: > On Tuesday, March 21, 2017 at 6:27:01 PM UTC, Mark Hamburg wrote: >> >> P.P.S. If you want your mind more deeply twisted, here is what we do when >> we want to store the auth token fairly high up but a piece of code needs it >> for constructing an HTTP request: >> > > Why not use a secure cookie? Then the browser adds it to the request for > you. It is also more secure and has the advantage that if the user > CTRL+clicks a link in your application opening up the same application in > >1 tab, that the cookies flow across automatically. > > -- > 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. > -- 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: How do you handle dependencies between updaters?
On Tuesday, March 21, 2017 at 6:27:01 PM UTC, Mark Hamburg wrote: > > P.P.S. If you want your mind more deeply twisted, here is what we do when > we want to store the auth token fairly high up but a piece of code needs it > for constructing an HTTP request: > Why not use a secure cookie? Then the browser adds it to the request for you. It is also more secure and has the advantage that if the user CTRL+clicks a link in your application opening up the same application in >1 tab, that the cookies flow across automatically. -- 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: How do you handle dependencies between updaters?
And if we were more deeply nested, the NeedAuthorization could also have been forwarded via code like this — note also that I fixed the failure to properly type the case entries in my previous message: applySubModelOutMsg : SubModelOutMsg -> Model -> ( Model, List OutMsg ) applySubModelOutMsg subModelOutMsg model = case subModelOutMsg of SubModelCommand cmd -> ( model, [ Command <| Cmd.map ToSubModel cmd ] ) SubModelNeedAuthorization updateGen -> ( model, [ NeedAuthorization (updateGen >> updateSubModel) ] ) Mark On Tue, Mar 21, 2017 at 11:26 AM, Mark Hamburgwrote: > Oliver asked whether our out messages approach had an equivalent of > Cmd.map. I'll paraphrase some code to show how it works. It's definitely > more code than the simple Cmd approach but it provides more functionality > as well. I'm simplifying away a lot of details like the fact that the login > submodel below would probably be stored as a `Maybe Login.Model` since once > we've logged in we don't need it any more. > > update : Msg -> Model -> ( Model, List OutMsg ) > update msg model = > case msg of > ToLogin loginMsg -> > updateLogin (Login.update loginMsg) model > > updateLogin : > (Login.Model -> ( Login.Model, List Login.OutMsg )) > -> (Model -> ( Model, List OutMsg )) > updateLogin loginUpdater model = > Update.start model.login > |> Update.andThen loginUpdater > |> Update.map (asLoginIn model) > |> Update.applyOutMessages applyLoginOutMsg > > asLoginIn : Model -> Login.Model -> Model > asLoginIn model newLogin = > { model | login = newLogin } > > applyLoginOutMsg : Login.OutMsg -> Model -> ( Model, List OutMsg ) > applyLoginOutMsg loginOutMsg model = > case loginOutMsg of > Login.Command cmd -> > ( model, [ Command <| Cmd.map ToLogin cmd ] ) > Login.DidLogin authorization -> > didLogin authorization model > > didLogin : Authorization -> Model -> ( Model, List OutMsg ) > didLogin authorization model = ... > > The Update module provides a collection of functions for dealing with > types with the shape ( Model, List OutMsg ). Update.map maps the model. > Update.andThen is a monadic chaining operation. Update.applyOutMessages > folds the out messages over the model performing a series of updates and > accumulating a new list of out messages (generally of a different type). > > Applying out messages is definitely more involved than mapping commands > and it gets repetitive to always have to handle standard cases like mapping > commands, but the flexibility to have the submodel signal something like > the fact that we successfully logged in is a big win and standardizing on > doing this via out messages builds a more consistent code rhythm than > adding lots of one off extra results to update functions. > > Mark > > P.S. If anyone has a recommendation for a better name for > Update.applyOutMessages, I'd love to hear it. The current name feels > excessively verbose. > > P.P.S. If you want your mind more deeply twisted, here is what we do when > we want to store the auth token fairly high up but a piece of code needs it > for constructing an HTTP request: > > type SubModelOutMsg > = Command (Cmd Msg) > | NeedAuthorization (Authorization -> SubModel -> ( SubModel, List > SubModelOutMsg )) > > applySubModelOutMsg : SubModelOutMsg -> Model -> ( Model, List OutMsg ) > applySubModelOutMsg subModelOutMsg model = > case subModelOutMsg of > Command cmd -> > ( model, [ Command <| Cmd.map ToSubModel cmd ] ) > NeedAuthorization updateGen -> > updateSubModel (updateGen model.authorization) model > > updateSubModel : > (SubModel -> ( SubModel, List SubModelOutMsg ) ) > -> (Model -> ( Model, List OutMsg )) > updateSubModel subModelUpdater model = > Update.start model.subModel > |> Update.andThen subModelUpdater > |> Update.map (asSubModelIn model) > |> Update.applyOutMessages applySubModelOutMsg > > > > On Tue, Mar 21, 2017 at 9:11 AM, 'Rupert Smith' via Elm Discuss < > elm-discuss@googlegroups.com> wrote: > >> On Monday, March 20, 2017 at 11:58:38 AM UTC, Eirik Sletteberg wrote: >>> >>> In larger Elm apps, it makes sense to divide Updaters so you can >>> package-by-feature. >>> For example, a single page application could have updaters like this: >>> >>> - Configuration updater >>> - Session updater >>> - User Profile updater >>> - User Settings updater >>> - Content updater >>> - Some other business specific updater >>> >>> The challenge is when there are dependencies between Updaters, for >>> example the User Profile model might need data from the Session model, the >>> Session updater might need to send messages to the User updater (Load user >>> profile when session is updated), or the Content updater may need to check >>> for the Session updater (get session ID to send as parameter
Re: [elm-discuss] Re: How do you handle dependencies between updaters?
Oliver asked whether our out messages approach had an equivalent of Cmd.map. I'll paraphrase some code to show how it works. It's definitely more code than the simple Cmd approach but it provides more functionality as well. I'm simplifying away a lot of details like the fact that the login submodel below would probably be stored as a `Maybe Login.Model` since once we've logged in we don't need it any more. update : Msg -> Model -> ( Model, List OutMsg ) update msg model = case msg of ToLogin loginMsg -> updateLogin (Login.update loginMsg) model updateLogin : (Login.Model -> ( Login.Model, List Login.OutMsg )) -> (Model -> ( Model, List OutMsg )) updateLogin loginUpdater model = Update.start model.login |> Update.andThen loginUpdater |> Update.map (asLoginIn model) |> Update.applyOutMessages applyLoginOutMsg asLoginIn : Model -> Login.Model -> Model asLoginIn model newLogin = { model | login = newLogin } applyLoginOutMsg : Login.OutMsg -> Model -> ( Model, List OutMsg ) applyLoginOutMsg loginOutMsg model = case loginOutMsg of Login.Command cmd -> ( model, [ Command <| Cmd.map ToLogin cmd ] ) Login.DidLogin authorization -> didLogin authorization model didLogin : Authorization -> Model -> ( Model, List OutMsg ) didLogin authorization model = ... The Update module provides a collection of functions for dealing with types with the shape ( Model, List OutMsg ). Update.map maps the model. Update.andThen is a monadic chaining operation. Update.applyOutMessages folds the out messages over the model performing a series of updates and accumulating a new list of out messages (generally of a different type). Applying out messages is definitely more involved than mapping commands and it gets repetitive to always have to handle standard cases like mapping commands, but the flexibility to have the submodel signal something like the fact that we successfully logged in is a big win and standardizing on doing this via out messages builds a more consistent code rhythm than adding lots of one off extra results to update functions. Mark P.S. If anyone has a recommendation for a better name for Update.applyOutMessages, I'd love to hear it. The current name feels excessively verbose. P.P.S. If you want your mind more deeply twisted, here is what we do when we want to store the auth token fairly high up but a piece of code needs it for constructing an HTTP request: type SubModelOutMsg = Command (Cmd Msg) | NeedAuthorization (Authorization -> SubModel -> ( SubModel, List SubModelOutMsg )) applySubModelOutMsg : SubModelOutMsg -> Model -> ( Model, List OutMsg ) applySubModelOutMsg subModelOutMsg model = case subModelOutMsg of Command cmd -> ( model, [ Command <| Cmd.map ToSubModel cmd ] ) NeedAuthorization updateGen -> updateSubModel (updateGen model.authorization) model updateSubModel : (SubModel -> ( SubModel, List SubModelOutMsg ) ) -> (Model -> ( Model, List OutMsg )) updateSubModel subModelUpdater model = Update.start model.subModel |> Update.andThen subModelUpdater |> Update.map (asSubModelIn model) |> Update.applyOutMessages applySubModelOutMsg On Tue, Mar 21, 2017 at 9:11 AM, 'Rupert Smith' via Elm Discuss < elm-discuss@googlegroups.com> wrote: > On Monday, March 20, 2017 at 11:58:38 AM UTC, Eirik Sletteberg wrote: >> >> In larger Elm apps, it makes sense to divide Updaters so you can >> package-by-feature. >> For example, a single page application could have updaters like this: >> >> - Configuration updater >> - Session updater >> - User Profile updater >> - User Settings updater >> - Content updater >> - Some other business specific updater >> >> The challenge is when there are dependencies between Updaters, for >> example the User Profile model might need data from the Session model, the >> Session updater might need to send messages to the User updater (Load user >> profile when session is updated), or the Content updater may need to check >> for the Session updater (get session ID to send as parameter to the API >> when fetching content), or some business-specific updater may need to >> interact with both the Content updater, the User updater, and the >> Configuration updater. >> > > I would apply a technique similar to CRC Cards from OO design. Instead of > Class-Responsibility-Collaboration, make it Module-Responsibility- > Collaborations. > > You have got a fair idea of what the split of responsibilities into > modules is (configuration, session, user profile, user setting, content, > and so on). For each module it is worth also explicitly spelling out what > its dependencies (Collaborations) are. Analyzed that way, you might find a > more optimal grouping of the responsibilities into modules that gives you > less of a dependency head-ache. Even though that grouping may no longer > align with your first
[elm-discuss] Re: How do you handle dependencies between updaters?
On Monday, March 20, 2017 at 11:58:38 AM UTC, Eirik Sletteberg wrote: > > In larger Elm apps, it makes sense to divide Updaters so you can > package-by-feature. > For example, a single page application could have updaters like this: > > - Configuration updater > - Session updater > - User Profile updater > - User Settings updater > - Content updater > - Some other business specific updater > > The challenge is when there are dependencies between Updaters, for example > the User Profile model might need data from the Session model, the Session > updater might need to send messages to the User updater (Load user profile > when session is updated), or the Content updater may need to check for the > Session updater (get session ID to send as parameter to the API when > fetching content), or some business-specific updater may need to interact > with both the Content updater, the User updater, and the Configuration > updater. > I would apply a technique similar to CRC Cards from OO design. Instead of Class-Responsibility-Collaboration, make it Module-Responsibility-Collaborations. You have got a fair idea of what the split of responsibilities into modules is (configuration, session, user profile, user setting, content, and so on). For each module it is worth also explicitly spelling out what its dependencies (Collaborations) are. Analyzed that way, you might find a more optimal grouping of the responsibilities into modules that gives you less of a dependency head-ache. Even though that grouping may no longer align with your first pass at splitting things up into a modular design, it may be a way to a better design. Occasionally I have had a module that produces 'out messages' to signal some condition that an update method higher up in the structure has to deal with, possibly even updating the state of some other module beneath it, so it is effectively a side-ways message. I can see that this is a bit of a draw-back that modular designs sometimes inevitably lead to. I am avoiding modularizing too early, and using Model-Responsibility-Collaboration to drive the split into modules in a more optimal way, or even deciding not to at all if makes it apparent that I can't find a good modular design. -- 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: How do you handle dependencies between updaters?
The main reason to separate is when the smaller pieces have their own conceptual integrity. That becomes something one can manage independently and maintain more local invariants about thereby making that piece of the code easier to reason about. But a dependency has to be managed somewhere and generally that needs to happen wherever things come together in the model hierarchy. For example, let's say we have a list of chats and a current chat. We're going to receive the list of chats from the server. The current chat is going to be something we're going to determine locally. The protocol that we speak with the server might be involved enough that we want to wrap this in its own module. (For example, the server might be shipping deltas rather than whole lists.) One of the things that can happen is that a chat could get deleted, so an update to the chat list could cause us to have to update the current chat. Here is how that code roughly works out. (I've got some monadic types that make it easier to write update functions, but I'm staying away from them in this example.) type alias Model = { chatList : ChatList.Model , currentChat : Maybe ChatID } type Msg = ToChatList ChatList.Msg | ... update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of ToChatList chatListMsg -> updateChatList (ChatList.update chatListMsg) model updateChatList : (ChatList.Model -> ( ChatList.Model, Cmd ChatList.Msg ) ) -> Model -> ( Model, Cmd Msg ) updateChatList chatListUpdater model = let ( newChatList, chatListCmd ) = chatListUdpater model.chatList newModel = { model | chatList = newChatList } cmd = Cmd.map ToChatList chatListCmd ( finalModel, finalCmd ) = updateChatListDependencies newModel in ( finalModel, Cmd.batch [ cmd, finalCmd ] ) updateChatListDependencies : Model -> ( Model, Cmd Msg ) updateChatListDependencies model = let newCurrentChat = model.currentChat |> Maybe.andThen (constrainToChatList (ChatList.getList model.chatList)) in ( { model | currentChat = newCurrentChat }, Cmd.none ) constrainToChatList : List Chat -> ChatID -> Maybe ChatID constrainToChatList chatList chatID = if List.any (Chat.id >> (==) chatID) chatList then Just chatID else Nothing The key logic here with respect to the dependent values is in updateChatList and its call to updateChatListDependencies. In this implementation, the model is not responsible for directly maintaining the list of chats but it is responsible for maintaining the constraints that depend on the list of chats. Mark On Tue, Mar 21, 2017 at 6:35 AM, Eirik Slettebergwrote: > That was what I was thinking, put all the application state in one model, > and all updaters will deal with that single model, instead of each Updater > having its own sub-model. In the end, almost all the data is dependent > somehow. > > tirsdag 21. mars 2017 12.22.15 UTC+1 skrev Fedor Nezhivoi følgende: >> >> > for example the User Profile model might need data from the Session >> model >> >> This is probably the biggest issue with how people used to do it in >> Redux. If you read it closely then you'll see that your data is dependent. >> By separating it between modules you do not make it in decoupled, you just >> create more boilerplate and complexity in how it works together. This was >> one of the reasons Redux discarded `waitFor` mechanism from Flux. If you >> have dependent data just put it in one reducer, that's it. I guess this >> pretty much applies here for Elm as well. >> > -- > 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. > -- 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: How do you handle dependencies between updaters?
That was what I was thinking, put all the application state in one model, and all updaters will deal with that single model, instead of each Updater having its own sub-model. In the end, almost all the data is dependent somehow. tirsdag 21. mars 2017 12.22.15 UTC+1 skrev Fedor Nezhivoi følgende: > > > for example the User Profile model might need data from the Session model > > This is probably the biggest issue with how people used to do it in Redux. > If you read it closely then you'll see that your data is dependent. By > separating it between modules you do not make it in decoupled, you just > create more boilerplate and complexity in how it works together. This was > one of the reasons Redux discarded `waitFor` mechanism from Flux. If you > have dependent data just put it in one reducer, that's it. I guess this > pretty much applies here for Elm as well. > -- 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: How do you handle dependencies between updaters?
> for example the User Profile model might need data from the Session model This is probably the biggest issue with how people used to do it in Redux. If you read it closely then you'll see that your data is dependent. By separating it between modules you do not make it in decoupled, you just create more boilerplate and complexity in how it works together. This was one of the reasons Redux discarded `waitFor` mechanism from Flux. If you have dependent data just put it in one reducer, that's it. I guess this pretty much applies here for Elm as well. -- 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: How do you handle dependencies between updaters?
Is it an option to make all the updaters deal with the root model and the root message? And in the "main" updater, just compose the other updaters? It could make things simpler, but hurt isolation. Also I'm not sure whether that would introduce circular dependencies between modules? mandag 20. mars 2017 12.58.38 UTC+1 skrev Eirik Sletteberg følgende: > > In larger Elm apps, it makes sense to divide Updaters so you can > package-by-feature. > For example, a single page application could have updaters like this: > > - Configuration updater > - Session updater > - User Profile updater > - User Settings updater > - Content updater > - Some other business specific updater > > The challenge is when there are dependencies between Updaters, for example > the User Profile model might need data from the Session model, the Session > updater might need to send messages to the User updater (Load user profile > when session is updated), or the Content updater may need to check for the > Session updater (get session ID to send as parameter to the API when > fetching content), or some business-specific updater may need to interact > with both the Content updater, the User updater, and the Configuration > updater. > > In Redux, one would use combineReducers to mount each reducer under its > own path, and then one can trigger actions across reducers. How would you > solve this in 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: How do you handle dependencies between updaters?
And it helps to not think about the functions "interacting" with each other. They don't. A function can call another function. Nothing is stopping you from calling the content update function or the user update function from another update function, but I find it helps to just factor out the common functionality into separate functions that can be called from multiple places. And if you have an update function that needs to update several "sub-models", just pass all the sub-models and get the updated sub-models back. Or pass the main model and let it update the parts it needs to update. > The challenge is when there are dependencies between Updaters, for example >> the User Profile model might need data from the Session model, the Session >> updater might need to send messages to the User updater (Load user profile >> when session is updated), or the Content updater may need to check for the >> Session updater (get session ID to send as parameter to the API when >> fetching content), or some business-specific updater may need to interact >> with both the Content updater, the User updater, and the Configuration >> updater. >> >> In Redux, one would use combineReducers to mount each reducer under its >> own path, and then one can trigger actions across reducers. How would you >> solve this in Elm? >> > > I find it helps to think not about sending messages to somebody but > returning a command. If the session updater needs to load a user profile, > it returns a command do to that and you map that onto the user message > type. If the user profile needs data from the session model, you pass that > data to the view function. > > It only gets hard when you try to think of them as separate components. > They're not, they are just a collection of functions. > -- 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: How do you handle dependencies between updaters?
> The challenge is when there are dependencies between Updaters, for example > the User Profile model might need data from the Session model, the Session > updater might need to send messages to the User updater (Load user profile > when session is updated), or the Content updater may need to check for the > Session updater (get session ID to send as parameter to the API when > fetching content), or some business-specific updater may need to interact > with both the Content updater, the User updater, and the Configuration > updater. > > In Redux, one would use combineReducers to mount each reducer under its > own path, and then one can trigger actions across reducers. How would you > solve this in Elm? > I find it helps to think not about sending messages to somebody but returning a command. If the session updater needs to load a user profile, it returns a command do to that and you map that onto the user message type. If the user profile needs data from the session model, you pass that data to the view function. It only gets hard when you try to think of them as separate components. They're not, they are just a collection of functions. -- 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: How do you handle dependencies between updaters?
I've came up with solution very similar to Oliver's :) Top `Page`(or `Screen`) update functions are getting the `Store` which is a top level app model. Alternative way is to have `mapToContext` function that receives some `Props` and `Store` and maps those to some useful context(it might be useful for both view and update functions, btw). Each top-level `Page` update fn also returns an instance of `Action` that helps modifying the store. On Monday, March 20, 2017 at 1:58:38 PM UTC+2, Eirik Sletteberg wrote: > > In larger Elm apps, it makes sense to divide Updaters so you can > package-by-feature. > For example, a single page application could have updaters like this: > > - Configuration updater > - Session updater > - User Profile updater > - User Settings updater > - Content updater > - Some other business specific updater > > The challenge is when there are dependencies between Updaters, for example > the User Profile model might need data from the Session model, the Session > updater might need to send messages to the User updater (Load user profile > when session is updated), or the Content updater may need to check for the > Session updater (get session ID to send as parameter to the API when > fetching content), or some business-specific updater may need to interact > with both the Content updater, the User updater, and the Configuration > updater. > > In Redux, one would use combineReducers to mount each reducer under its > own path, and then one can trigger actions across reducers. How would you > solve this in 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.