Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
import Control.Concurrent.ParallelIO.Global (parallel)
import Control.Arrow (left)
data DbError = DbError
data Input = Input
data Result = Result
someOperation :: Either DbError [Input]
-> (Input -> IO (Either DbError Result))
-> IO (Either DbError [Result])
someOperation (Left err) op = return $ Left err
someOperation (Right inputs) op = do
res <- parallel $ map op inputs
return $ sequence res
-- Another variation
someOperation eitherInputs op = left eitherInputs \inputs -> do
res <- parallel $ map op inputs
return $ sequence res

This comment has been minimized.

Copy link

@YoEight YoEight commented Sep 29, 2014

Somehow I think async package is more practical at concurrent/parallel things, using its mapConcurrently function.

import Control.Concurrent.Async

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

The fact that someOperation carries a callback Input -> IO (Either DbError Result) shows that same callback should have been applied upfront.

Your Input processing should look like this:

doingStuffWithInput :: Input -> IO (Either DbError Result)

I imagine you need something like this at some point:

processInputs :: [Input] -> IO (Either DbError [Result])
processInputs = fmap sequence . traverse doingStuffWithInput

The thing is, you want doingStuffWithInput to be executed in parallel. Alright:

processInputsInParallel :: [Input] -> IO (Either DbError [Result])
processInputsInParallel = fmap sequence . mapConcurrently doingStuffWithInput

And you've done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment