simonmar / async

Run IO operations asynchronously and wait for their results

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

mapConcurrently / forConcurrently + lenses

Icelandjack opened this issue · comments

async has some functions that can be parameterized by optics from lens, is this something that is worth adding.

mapConcurrently :: Traversable t => (a -> IO b) -> t a -> IO (t b)

forConcurrently :: Traversable t => t a -> (a -> IO b)-> IO (t b)

mapConcurrently_ :: Foldable f => (a -> IO b) -> f a -> IO ()

forConcurrently_ :: Foldable f => f a -> (a -> IO b) -> IO ()

can be parameterized by optics from lens

mapConcurrentlyOf :: LensLike Concurrently s t a b -> (a -> IO b) -> (s -> IO t)
mapConcurrentlyOf lens = flip (forConcurrentlyOf lens)

forConcurrentlyOf :: forall s t a b. LensLike Concurrently s t a b -> s -> (a -> IO b) -> IO t
forConcurrentlyOf = coerce (forOf @IO @s @t @a @b)

mapConcurrentlyOf_ :: forall s a r. Getting (Traversed r Concurrently) s a -> (a -> IO r) -> (s -> IO ())
mapConcurrentlyOf_ lens = flip (forConcurrentlyOf_ lens)

forConcurrentlyOf_ :: forall s a r. Getting (Traversed r Concurrently) s a -> s -> (a -> IO r) -> IO ()
forConcurrentlyOf_ = coerce (forOf_ @IO @r @s @a)

that run them concurrently

>> forConcurrentlyOf_ (replicated 10) 'a' print
'a''a''
'''aa'''a'
a''aaa'a'

'''
'

I'm thinking that a much better solution is to create an optic modifier, something that takes lens-like over IO-like and produces LensLike Concurrently.

That way you can write

forConcurrentlyOf  lens = forOf  (asConcurrent lens)
forConcurrentlyOf_ lens = forOf_ (asConcurrent lens)

I'm not a heavy lens user so I have no strong feelings on this, but I'd rather not take a dependency on lens. Can this be added in a separate async-lens package?

@simonmar, lens defines

type LensLike f s t a b = (a -> f b) -> s -> f t

so mapConcurrentlyOf (which I'd call traverseConcurrentlyOf) and forConcurrentlyOf should be no problem. Traversed is a newtype defined in lens, and is frankly a bit of a mess, so I don't think the other two can be supported so easily.

I'd rather not make async depend on lens. Could these be put into a separate package async-lens, say in a module Control.Concurrent.Async.Lens?