Skip to content

Instantly share code, notes, and snippets.

@danidiaz
Last active August 29, 2015 14:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danidiaz/e9382127d1c4025b9845 to your computer and use it in GitHub Desktop.
Save danidiaz/e9382127d1c4025b9845 to your computer and use it in GitHub Desktop.
A twist on this Gist: https://gist.github.com/ocharles/556b35e3d16565cab457. Retrying actions with delays using the iterative monad transformer. Requires free >= 4.10.0.1.
> import Safe (readMay)
> import Control.Monad
> import Control.Monad.Trans
> import Control.Monad.Trans.Iter (delay,untilJust,IterT,retract,cutoff)
> import Control.Concurrent (threadDelay)
This is an action that may fail:
> maybeReadInteger :: IO (Maybe Integer)
> maybeReadInteger = liftM readMay (putStr ">" >> getLine)
This is an infinite sequece of "delays", of two seconds each:
> delays :: IterT IO a
> delays = forever (delay (lift (threadDelay (2*10^6))))
This tries 4 times to read an integer:
> retryIntegerRead :: IO (Maybe Integer)
> retryIntegerRead =
> (retract . cutoff 4) (delays `mplus` untilJust maybeReadInteger)
`untilJust` turns `maybeReadInteger` into a computation that keeps retrying until it succeeds.
We "sum" that computation with the `delays` one. `mplus` for `IterT`
makes the two computations "race" each other, and returns the value of the one that finishes earlier.
Since we don't want to wait forever in case of repeated failures, we establish a cutoff of 4 and
then retract.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment