{-# LANGUAGE TemplateHaskell #-} module Polysemy.Async ( -- * Effect Async (..) -- * Actions , async , await -- * Interpretations , runAsync , runAsyncInIO ) where import qualified Control.Concurrent.Async as A import Polysemy ------------------------------------------------------------------------------ -- | An effect for spawning asynchronous computations. -- -- The 'Maybe' returned by 'async' is due to the fact that we can't be sure an -- 'Polysemy.Error.Error' effect didn't fail locally. -- -- @since 0.5.0.0 data Async m a where Async :: m a -> Async m (A.Async (Maybe a)) Await :: A.Async a -> Async m a makeSem ''Async ------------------------------------------------------------------------------ -- | A more flexible --- though less performant --- version of 'runAsyncInIO'. -- -- This function is capable of running 'Async' effects anywhere within an -- effect stack, without relying on an explicit function to lower it into 'IO'. -- Notably, this means that 'Polysemy.State.State' effects will be consistent -- in the presence of 'Async'. -- -- @since 0.5.0.0 runAsync :: LastMember (Lift IO) r => Sem (Async ': r) a -> Sem r a runAsync m = withLowerToIO $ \lower _ -> lower $ interpretH ( \case Async a -> do ma <- runT a ins <- getInspectorT fa <- sendM $ A.async $ lower $ runAsync ma pureT $ fmap (inspect ins) fa Await a -> pureT =<< sendM (A.wait a) ) m {-# INLINE runAsync #-} ------------------------------------------------------------------------------ -- | Run an 'Async' effect via in terms of 'A.async'. -- -- -- @since 0.5.0.0 runAsyncInIO :: Member (Lift IO) r => (forall x. Sem r x -> IO x) -- ^ Strategy for lowering a 'Sem' action down to 'IO'. This is likely -- some combination of 'runM' and other interpreters composed via '.@'. -> Sem (Async ': r) a -> Sem r a runAsyncInIO lower m = interpretH ( \case Async a -> do ma <- runT a ins <- getInspectorT fa <- sendM $ A.async $ lower $ runAsyncInIO lower ma pureT $ fmap (inspect ins) fa Await a -> pureT =<< sendM (A.wait a) ) m {-# INLINE runAsyncInIO #-}