{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
module Control.Effects.Async where
import Import
import Control.Effects
import qualified Control.Concurrent.Async as Async
import Control.Monad.Runnable
import Data.Maybe
data Async thread m = AsyncMethods
{ _async :: forall a. m a -> m (thread m a)
, _waitAsync :: forall a. thread m a -> m a
, _isAsyncDone :: forall a n. thread n a -> m Bool
, _cancelAsync :: forall a n. thread n a -> m () }
class ThreadIdentifier thread where
mapThread :: (m a -> n b) -> thread m a -> thread n b
instance ThreadIdentifier thread => Effect (Async thread) where
type CanLift (Async thread) t = RunnableTrans t
type ExtraConstraint (Async thread) m = UniqueEffect Async m thread
mergeContext mm = AsyncMethods
(\a -> mm >>= ($ a) . _async)
(\a -> mm >>= ($ a) . _waitAsync)
(\a -> mm >>= ($ a) . _isAsyncDone)
(\a -> mm >>= ($ a) . _cancelAsync)
liftThrough (AsyncMethods f g h i) = AsyncMethods
(\tma -> do
st <- currentTransState
!res <- lift (f (runTransformer tma st))
return $ mapThread (lift >=> restoreTransState) res
)
(\a -> do
st <- currentTransState
res <- lift (g (mapThread (`runTransformer` st) a))
restoreTransState res
)
(lift . h)
(lift . i)
async :: MonadEffect (Async thread) m => m a -> m (thread m a)
waitAsync :: MonadEffect (Async thread) m => thread m a -> m a
isAsyncDone :: MonadEffect (Async thread) m => thread n a -> m Bool
cancelAsync :: MonadEffect (Async thread) m => thread n a -> m ()
AsyncMethods async waitAsync isAsyncDone cancelAsync = effect
newtype AsyncThread m a = AsyncThread (Async.Async (m a))
deriving (Functor, Eq, Ord)
instance ThreadIdentifier AsyncThread where
mapThread f (AsyncThread as) = AsyncThread (fmap f as)
instance UniqueEffect Async (RuntimeImplemented (Async thread) m) thread
instance UniqueEffect Async IO AsyncThread
instance MonadEffect (Async AsyncThread) IO where
effect = AsyncMethods
(fmap (AsyncThread . fmap return) . Async.async)
(\(AsyncThread as) -> join (Async.wait as))
(\(AsyncThread as) -> isJust <$> Async.poll as)
(\(AsyncThread as) -> Async.cancel as)
implementAsyncViaIO :: IO a -> IO a
implementAsyncViaIO = id
parallelMapM :: (MonadEffect (Async thread) m, Traversable t) => (a -> m b) -> t a -> m (t b)
parallelMapM f = mapM waitAsync <=< mapM (async . f)
parallelMapM_ :: (MonadEffect (Async thread) m, Traversable t) => (a -> m b) -> t a -> m ()
parallelMapM_ f = mapM_ waitAsync <=< mapM (async . f)