This is super cool. But what is the function:
(!) : a -> List b -> (a, b) On Wednesday, 1 June 2016 09:45:05 UTC+2, James Wilson wrote: Thanks for your help; I'll have a ponder and probably end up taking an > effect manager route again (I started this way and then ended up with some > weird hybrid where my cache was in the main elm app and an effect manager > did the "lower level" api stuff; but I'm not so happy with it) > > As another effect manager code point if you're intrigued how they work > (and my comments are in any way useful, which they may not be); here's an > effect manager I made for sending and receiving things from a backend I'm > wiring my app up to (so it uses custom Cmds and Subs): > > > https://github.com/jsdw/tl-asset-browser/blob/3e9e8527f65ae0a0a2d5d00d01779bdfdf03701d/src/elm/Api.elm > > Not sure whether it's any help (may just be easier looking at the elm-lang > effect managers!) but just in case :) > > On Wednesday, 1 June 2016 08:31:11 UTC+1, Peter Damoc wrote: >> >> I haven't used an effect manager for this because I haven put in the time >> needed to learn how to create effect managers. :) >> >> If what I've shown here can be accomplished with an effect manager then >> that's the way it should be done. :) >> >> >> >> >> >> >> On Wed, Jun 1, 2016 at 10:21 AM, James Wilson <[email protected]> wrote: >> >>> Thanks, that looks like basically exactly what I'd have guessed :) It's >>> super useful seeing an actual code sample with these ideas in. >>> >>> One thing I wonder now is; why not use an effect manager for this? It >>> basically seems to fit the exact same space (allows you to create a custom >>> Req like thing that can be mapped and batched and passed up the component >>> hierarchy - except that it's just a Cmd instead and plays nice with other >>> Cmds; allows you to maintain and update state (the cache) as you go; allows >>> you to "convert" Reqs to tasks to be run - just Cmds again now). In fact, >>> effect managers don't really seem to help you do anything other than what's >>> described here (plus a subscription side if you want it). Are there any >>> cons to using an effect manager here that you have in mind? >>> >>> On Tuesday, 31 May 2016 20:43:41 UTC+1, Peter Damoc wrote: >>>> >>>> The updating of the cache sounds to me like this: >>>> >>>> 1. if we have the info in cache, just supply the info without a HTTP GET >>>> 2. if we don't have the info in cache, return a different Msg that >>>> encapsulates the msg that requested the original information and the info >>>> required for the cache update. >>>> >>>> Here is a quick update of the code I've previously posted to include >>>> this caching mechanism. >>>> >>>> https://gist.github.com/pdamoc/d492ab58023926cd4d4950f12e5e170d >>>> >>>> >>>> >>>> >>>> On Tue, May 31, 2016 at 10:05 PM, James Wilson <[email protected]> >>>> wrote: >>>> >>>>> The key part that's not coded in the gist is the use of a cache/global >>>>> state object, however I think I see what you're getting at - pass back >>>>> up >>>>> the chain a Req object, say, and at the top we can turn it into a Cmd >>>>> using, say, some top level global state as well as whatever other data we >>>>> need. This may lead to a request being made to the server or it may not. >>>>> >>>>> The other part of the puzzle is actually updating the cache when a >>>>> request is made. Req.toCmd for instance could return an updated >>>>> GlobalState >>>>> so that it's able to cache "pending" states on values (so that we can >>>>> avoid >>>>> duplicating requests). To update the cache when the response actually >>>>> comes >>>>> in we could have toCmd return a Cmd.batch of 2 commands, one that will >>>>> fail/succeed and send a message to the component that initiated the Req, >>>>> and one that will send a message aimed at the top level cache itself. >>>>> >>>>> Thanks Peter, I'll definitely mull over this! >>>>> >>>>> On Tuesday, 31 May 2016 19:45:42 UTC+1, Peter Damoc wrote: >>>>>> >>>>>> ADT in Elm is one of its most powerful weapons. >>>>>> >>>>>> You could encapsulate your requests in a type and use this type at >>>>>> top level to fulfill them. >>>>>> >>>>>> For example: instead of returning Cmd msg you return some Req msg >>>>>> that can be turned into a Cmd msg at top level based on some context >>>>>> information. >>>>>> >>>>>> Here is a gist with a skeleton of how I view this implemented: >>>>>> https://gist.github.com/pdamoc/a47090e69b75433efa60fe4f70e6a06a >>>>>> >>>>>> I've sent the base of the URL as a simple String in `Req.toCmd` but >>>>>> you can imagine a more complex type holding all kind of information >>>>>> (e.g. >>>>>> cache, auth, etc ) . >>>>>> Also, I've kept the type of the Req simple (only saved the rest of >>>>>> the URL based on the user and the request) but one could use it to store >>>>>> all the info needed when you will turn the Req into a Cmd. >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> On Tue, May 31, 2016 at 7:29 PM, James Wilson <[email protected]> >>>>>> wrote: >>>>>> >>>>>>> In Elm, each component basically has its own internal state (which >>>>>>> is actually all just a slice of one global model). In my app, I also >>>>>>> want >>>>>>> global state that is independant of any components; for example a >>>>>>> clientside cache of various API responses (asset details - there could >>>>>>> be >>>>>>> many thousands, user authentication status). >>>>>>> >>>>>>> I want any component to be able to call methods that make use of >>>>>>> this global state. For example, a method to obtain details for items in >>>>>>> the >>>>>>> current view might first look at the global state to see if these items >>>>>>> are >>>>>>> cached. If they arent, the call would provide a Cmd to be issued that >>>>>>> gets >>>>>>> the items (and puts them in the cache), while simultaneously updating >>>>>>> the >>>>>>> state to indicate that they are being loaded (so that the same request >>>>>>> again from another component doesnt trigger another call to the >>>>>>> backend). >>>>>>> If they are cached, they can be easily returned from there. A first >>>>>>> shot at >>>>>>> a signature might look something like: >>>>>>> >>>>>>> getItem : GlobalState -> ID -> Tag -> (GlobalState, Cmd msg) >>>>>>> >>>>>>> >>>>>>> >>>>>>> However we could partially apply functions that exist on some >>>>>>> globalState instantiation to hdie the initial state being passed in and >>>>>>> end >>>>>>> up with: >>>>>>> >>>>>>> state.items.getItem : ID -> Tag -> (GlobalState, Cmd msg) >>>>>>> >>>>>>> >>>>>>> >>>>>>> The downside of this approach is that I have to thread this state >>>>>>> through multiple calls that might make use of it, and thread it back up >>>>>>> explicitly through the update functions to get it back to the top. At >>>>>>> the >>>>>>> top we'd then have something like (excuse any mistakes!): >>>>>>> >>>>>>> update msg model = case msg of >>>>>>> SubMsg m -> >>>>>>> let (newSubModel, subCmds, newGlobalState) = SubComponent.update >>>>>>> m model.subModel >>>>>>> in ({ model | state = newGlobalState, subModel = newSubModel}, >>>>>>> Sub.map SubMsg subCmds) >>>>>>> ... >>>>>>> >>>>>>> >>>>>>> An alternative approach is to hold this global state in an effect >>>>>>> manager, and so in the app you'd end up using the Cmd/Sub mechanism to >>>>>>> ask >>>>>>> for things from the state and internally initiate API requests to >>>>>>> update >>>>>>> the state as necessary. We'd end up with an API more like: >>>>>>> >>>>>>> getItem : ID -> Tag -> Cmd msg >>>>>>> >>>>>>> >>>>>>> or >>>>>>> >>>>>>> state.items.getItem : ID -> Tag -> Cmd msg >>>>>>> >>>>>>> >>>>>>> where the returned Cmd would either lead to an item being sent to >>>>>>> the component immediately via a cache (where Tag is a Msg type the >>>>>>> component knows about) or after it was obtained via some backend. This >>>>>>> would make all retrieving of state async but seems to simplify the >>>>>>> interface (perhaps at the cost of more complexity in implementing the >>>>>>> effect manager). >>>>>>> >>>>>>> Which approach do people think is best for working with global state >>>>>>> (neither is an option if you have a better way!)? Do you get away with >>>>>>> not >>>>>>> needing this kind of thing (and if so, how)? I'd love to hear back, >>>>>>> especially from those that have had experience building larger apps 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 [email protected]. >>>>>>> For more options, visit https://groups.google.com/d/optout. >>>>>>> >>>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> There is NO FATE, we are the creators. >>>>>> blog: http://damoc.ro/ >>>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google >>>>> Groups "Elm Discuss" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>> an email to [email protected]. >>>>> For more options, visit https://groups.google.com/d/optout. >>>>> >>>> >>>> >>>> >>>> -- >>>> There is NO FATE, we are the creators. >>>> blog: http://damoc.ro/ >>>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Elm Discuss" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> For more options, visit https://groups.google.com/d/optout. >>> >> >> >> >> -- >> There is NO FATE, we are the creators. >> blog: http://damoc.ro/ >> > -- You received this message because you are subscribed to the Google Groups "Elm Discuss" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
