[elm-discuss] Re: Debouncing, throttling, exponential backoff, relating effects to time - valid use of effect manager?

2017-10-29 Thread Ilias Van Peer
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 

[elm-discuss] Re: Debouncing, throttling, exponential backoff, relating effects to time - valid use of effect manager?

2017-10-28 Thread 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 

[elm-discuss] Re: Debouncing, throttling, exponential backoff, relating effects to time - valid use of effect manager?

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