Your final example (exponential backoff on HTTP requests) doesn't need any
magic.
You can use `Http.toTask` to turn it into a task and implement a generic
"retry task at most x times with backoff" like this:
retry : Int -> Time -> Task x a -> Task x a
retry maxTries backOff task =
if maxTries == 0 then
task
else
Task.onError
(\_ ->
Process.sleep backOff
|> Task.andThen
(\_ -> retry (maxTries - 1) (backOff * 2) task)
)
task
Op zondag 29 oktober 2017 00:30:45 UTC+2 schreef Henry:
>
> Thank you Ryan for the excellent reply! You made a lot of good points, and
> I appreciate the overview on the available libraries and their drawbacks.
>
> I feel like the effect manager conveys the intent of the code better, you
> get to say "I want this to happen" and then shove the state in a lock box,
> throw it in a closet, throw the closet in a river, and pretend like the
> hole in the side of your house was always there, and is perfectly normal.
> The use of global string IDs is a big downside though, it feels dirty
> writing code like that when everything else is wrapped in ribbons, laced
> with foil, and covered in the wondrous glitter of the type system.
>
> With relating effects to time, the main examples I think of are:
> debouncing searches, throttling clicks/events (you can only do X once every
> 10 seconds), exponential backoff (for network requests). I've asked a few
> people if they know the name of that class of problems, relating events to
> time, and I still don't know the name of them, but some friends now think
> I'm an idiot who doesn't know what "history" is.
>
> I was trying to think of various ways it could look in the language (with
> little regard to what is feasible...), and these are a few
>
> let
> debouncedInput = debounce 200 onInputininput [ debouncedInput
> SearchOnServer ]
>
>
> This way the message and model are unchanged, and debouncedInput handles
> everything auto-magically, much the same way onInput does already.
> Ideally you could use that with Html.Events.on, or any of its ilk. The
> upside here is that it is very clear what is happening, because you get to
> state it right where it happens, but it would need to be implemented in
> VirtualDom and it would only work for HTML events. It could be use for
> throttling chat messages, button clicks, scroll events, etc. The event
> listener implementation is in VirtualDom here (
> https://github.com/elm-lang/virtual-dom/blob/dev/src/Elm/Kernel/VirtualDom.js#L521-L527
> )
>
> Another potential way (ala unbounce or mceldeen's implementations) is
> handling the individual message, but debouncing a subsequent message. We
> can collect the text from the search bar, and run the search after the user
> has quit typing.
>
> update : Msg -> Model -> ( Model, Cmd Msg )update msg model =
> case msg of
> SearchUpdate newSearch ->
> ( { model | search = newSearch }, debounce "search" 200
> PerformSearch )
>
>
> I feel it would be even better to be able to write as
>
> ( { model | search = newSearch }, debounce 200 PerformSearch )
>
>
> For HTTP requests I would use the "second message' pattern as well, with
> one event sending a Cmd that will resolve later and then make the
> request. With exponential backoff there is added state for the number of
> tries so far, so my ideal API handles all of that for me with magic
>
> Http.getWithExponentialBackoffAndAMakeAMartini decoder
> ("https://grass-fed-lemonade.com/search" ++ query)
>
>
> But a more realistic version is probably something like
>
> update : Msg -> Model -> ( Model, Cmd Msg )update msg model =
> case msg of
> SearchFailed err ->
> ( { model | failed = model.failed + 1 }
> , Process.sleep (model.failed * 2 * 1000)
> |> Task.perform (\_ -> PerformSearch)
>
>
> I think any inclusion of "magic" (re: hidden state), should be weighed
> carefully, and in this instance I think the increased clarity of the code
> is worth it, though clarity is subjective as well.
>
> On Friday, October 13, 2017 at 5:23:45 PM UTC-4, Ryan Rempel wrote:
>>
>> On Thursday, October 5, 2017 at 9:27:27 AM UTC-5, Henry wrote:
>>>
>>> Evan has said before that there are around 10 valid uses of an effect
>>> manager, do you think relating effects to time is one of them?
>>>
>>
>> One way of thinking about this question is to compare existing debouncers
>> that use an effects manager vs. those which do not.
>>
>> Two debouncers which use an effects manager are:
>>
>> https://github.com/unbounce/elm-debounce
>> https://github.com/mceldeen/elm-debouncer
>>
>> Two debouncers which do not use an effects manager are:
>>
>> http://package.elm-lang.org/packages/jinjor/elm-debounce/latest
>> http://package.elm-lang.org/packages/mpizenberg/elm-debounce/latest
>>
>> Now, both approaches need to keep some state, of course.
>>
>> The advantage of an effects manager is that it can keep some state behind
>> the scenes, so to speak, without requiring the user of the package to
>> integrate the state into the `model`, `msg` and `update` scheme in the
>> usual way.
>>
>> However, I don't think there is anything an effects manager can
>> accomplish (at least with respect to debouncing) that cannot also be done
>> without an effects manager, at the cost of additional wiring and verbosity.
>> That is, at the cost of making the state visible, and requiring you to
>> integrate it into your `model`, `msg` and `update` scheme, you can achieve
>> everything you'd want with respect to debouncing without using an effects
>> module.
>>
>> In fact, there are some advantages in not using an effects module. If you
>> look at the debouncers that use an effects module, they employ a string ID
>> in order to distinguish between one debouncer and another. (That is, the
>> module is possibly tracking the state for multiple debouncers internally,
>> so you need to provide a string ID to distinguish between one and another).
>> But, of course, this isn't entirely satisfactory, since it forces you to
>> maintain some scheme of globally-unique strings within your program. (Which
>> is not necessarily that hard, really, but it is something which you'd
>> normally want to avoid).
>>
>> That problem doesn't arise if you have to explicitly integrate some state
>> into your `model`, `msg` and `update` in the usual way, since then you just
>> provide the relevant state when needed ... you can't accidentally refer to
>> the wrong bit of state by providing a string ID that is also used elsewhere.
>>
>> Of course, there may be a clever way to write an effects module that
>> avoids this problem.
>>
>
--
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.