@@ -0,0 +1,366 @@
1+{-# LANGUAGE UndecidableInstances #-}
7+ -- * Asynchronous actions
10+ , async, asyncBound, asyncOn
11+ , asyncWithUnmask, asyncOnWithUnmask
13+ -- ** Spawning with automatic 'cancel'ation
14+ , withAsync, withAsyncBound, withAsyncOn
15+ , withAsyncWithUnmask, withAsyncOnWithUnmask
17+ -- ** Quering 'Async's
18+ , wait, poll, waitCatch
20+ , uninterruptibleCancel
23+ , A.AsyncCancelled(..)
26+ , A.waitSTM, A.pollSTM, A.waitCatchSTM
28+ -- ** Waiting for multiple 'Async's
29+ , waitAny, waitAnyCatch, waitAnyCancel, waitAnyCatchCancel
30+ , waitEither, waitEitherCatch, waitEitherCancel, waitEitherCatchCancel
34+ -- ** Waiting for multiple 'Async's in STM
38+ , A.waitEitherCatchSTM
44+ , A.ExceptionInLinkedThread(..)
46+ -- * Convenient utilities
47+ , race, race_, concurrently, concurrently_
48+ , mapConcurrently, mapConcurrently_
49+ , forConcurrently, forConcurrently_
50+ , replicateConcurrently, replicateConcurrently_
56+import Control.Applicative
57+import Control.Concurrent (threadDelay)
58+import Control.Concurrent.Async (Async)
59+import Control.Exception (Exception, SomeException)
60+import Control.Monad (forever, void)
61+import Data.Foldable (fold)
62+import qualified Control.Concurrent.Async as A
64+import Effectful.Internal.Effect
65+import Effectful.Internal.Env
66+import Effectful.Internal.Monad
68+-- | Run 'Eff' computations asynchronously using the @async@ library.
70+-- /Note:/ Thread-local state changes in 'Eff' computations lifted into an
71+-- 'Async' will not affect the thread that spawned them.
72+data AsyncE :: Effect where
75+runAsyncE :: IOE :> es => Eff (AsyncE : es) a -> Eff es a
76+runAsyncE = evalEffect (IdE AsyncE)
78+-- | Generalized version of 'A.async'.
79+async :: AsyncE :> es => Eff es a -> Eff es (Async a)
80+async = liftAsync A.async
82+-- | Generalized version of 'A.asyncBound'.
83+asyncBound :: AsyncE :> es => Eff es a -> Eff es (Async a)
84+asyncBound = liftAsync A.asyncBound
86+-- | Generalized version of 'A.asyncOn'.
87+asyncOn :: AsyncE :> es => Int -> Eff es a -> Eff es (Async a)
88+asyncOn cpu = liftAsync (A.asyncOn cpu)
90+-- | Generalized version of 'A.asyncWithUnmask'.
93+ => ((forall b. Eff es b -> Eff es b) -> Eff es a)
95+asyncWithUnmask = liftAsyncWithUnmask A.asyncWithUnmask
97+-- | Generalized version of 'A.asyncOnWithUnmask'.
101+ -> ((forall b. Eff es b -> Eff es b) -> Eff es a)
103+asyncOnWithUnmask cpu = liftAsyncWithUnmask (A.asyncOnWithUnmask cpu)
105+-- | Generalized version of 'A.withAsync'.
109+ -> (Async a -> Eff es b)
111+withAsync = liftWithAsync A.withAsync
113+-- | Generalized version of 'A.withAsyncBound'.
117+ -> (Async a -> Eff es b)
119+withAsyncBound = liftWithAsync A.withAsyncBound
121+-- | Generalized version of 'A.withAsyncOn'.
126+ -> (Async a -> Eff es b)
128+withAsyncOn cpu = liftWithAsync (A.withAsyncOn cpu)
130+-- | Generalized version of 'A.withAsyncWithUnmask'.
133+ => ((forall c. Eff es c -> Eff es c) -> Eff es a)
134+ -> (Async a -> Eff es b)
136+withAsyncWithUnmask = liftWithAsyncWithUnmask A.withAsyncWithUnmask
138+-- | Generalized version of 'A.withAsyncOnWithUnmask'.
139+withAsyncOnWithUnmask
142+ -> ((forall c. Eff es c -> Eff es c) -> Eff es a)
143+ -> (Async a -> Eff es b)
145+withAsyncOnWithUnmask cpu = liftWithAsyncWithUnmask (A.withAsyncOnWithUnmask cpu)
147+-- | Generalized version of 'A.wait'.
148+wait :: AsyncE :> es => Async a -> Eff es a
149+wait = unsafeEff_ . A.wait
151+-- | Generalized version of 'A.poll'.
155+ -> Eff es (Maybe (Either SomeException a))
156+poll = unsafeEff_ . A.poll
158+-- | Generalized version of 'A.cancel'.
159+cancel :: AsyncE :> es => Async a -> Eff es ()
160+cancel = unsafeEff_ . A.cancel
162+-- | Generalized version of 'A.cancelWith'.
163+cancelWith :: (Exception e, AsyncE :> es) => Async a -> e -> Eff es ()
164+cancelWith a = unsafeEff_ . A.cancelWith a
166+-- | Generalized version of 'A.uninterruptibleCancel'.
167+uninterruptibleCancel :: AsyncE :> es => Async a -> Eff es ()
168+uninterruptibleCancel = unsafeEff_ . A.uninterruptibleCancel
170+-- | Generalized version of 'A.waitCatch'.
174+ -> Eff es (Either SomeException a)
175+waitCatch = unsafeEff_ . A.waitCatch
177+-- | Generalized version of 'A.waitAny'.
178+waitAny :: AsyncE :> es => [Async a] -> Eff es (Async a, a)
179+waitAny = unsafeEff_ . A.waitAny
181+-- | Generalized version of 'A.waitAnyCatch'.
185+ -> Eff es (Async a, Either SomeException a)
186+waitAnyCatch = unsafeEff_ . A.waitAnyCatch
188+-- | Generalized version of 'A.waitAnyCancel'.
189+waitAnyCancel :: AsyncE :> es => [Async a] -> Eff es (Async a, a)
190+waitAnyCancel = unsafeEff_ . A.waitAnyCancel
192+-- | Generalized version of 'A.waitAnyCatchCancel'.
196+ -> Eff es (Async a, Either SomeException a)
197+waitAnyCatchCancel = unsafeEff_ . A.waitAnyCatchCancel
199+-- | Generalized version of 'A.waitEither'.
204+ -> Eff es (Either a b)
205+waitEither a b = unsafeEff_ $ A.waitEither a b
207+-- | Generalized version of 'A.waitEitherCatch'.
212+ -> Eff es (Either (Either SomeException a) (Either SomeException b))
213+waitEitherCatch a b = unsafeEff_ $ A.waitEitherCatch a b
215+-- | Generalized version of 'A.waitEitherCancel'.
220+ -> Eff es (Either a b)
221+waitEitherCancel a b = unsafeEff_ $ A.waitEitherCancel a b
223+-- | Generalized version of 'A.waitEitherCatchCancel'.
224+waitEitherCatchCancel
228+ -> Eff es (Either (Either SomeException a) (Either SomeException b))
229+waitEitherCatchCancel a b = unsafeEff_ $ A.waitEitherCatch a b
231+-- | Generalized version of 'A.waitEither_'.
232+waitEither_ :: AsyncE :> es => Async a -> Async b -> Eff es ()
233+waitEither_ a b = unsafeEff_ $ A.waitEither_ a b
235+-- | Generalized version of 'A.waitBoth'.
236+waitBoth :: AsyncE :> es => Async a -> Async b -> Eff es (a, b)
237+waitBoth a b = unsafeEff_ $ A.waitBoth a b
239+-- | Generalized version of 'A.link'.
240+link :: AsyncE :> es => Async a -> Eff es ()
241+link = unsafeEff_ . A.link
243+-- | Generalized version of 'A.link2'.
244+link2 :: AsyncE :> es => Async a -> Async b -> Eff es ()
245+link2 a b = unsafeEff_ $ A.link2 a b
247+-- | Generalized version of 'A.race'.
248+race :: AsyncE :> es => Eff es a -> Eff es b -> Eff es (Either a b)
249+race ma mb = withAsync ma $ \a -> withAsync mb $ \b -> waitEither a b
251+-- | Generalized version of 'A.race_'.
252+race_ :: AsyncE :> es => Eff es a -> Eff es b -> Eff es ()
253+race_ ma mb = withAsync ma $ \a -> withAsync mb $ \b -> waitEither_ a b
255+-- | Generalized version of 'A.concurrently'.
256+concurrently :: AsyncE :> es => Eff es a -> Eff es b -> Eff es (a, b)
257+concurrently ma mb = withAsync ma $ \a -> withAsync mb $ \b -> waitBoth a b
259+-- | Generalized version of 'A.concurrently_'.
260+concurrently_ :: AsyncE :> es => Eff es a -> Eff es b -> Eff es ()
261+concurrently_ ma mb = void $ concurrently ma mb
263+-- | Generalized version of 'A.mapConcurrently'.
265+ :: (Traversable f, AsyncE :> es)
269+mapConcurrently f = runConcurrently . traverse (Concurrently . f)
271+-- | Generalized version of 'A.mapConcurrently_'.
273+ :: (Foldable f, AsyncE :> es)
277+mapConcurrently_ f = runConcurrently . foldMap (Concurrently . void . f)
279+-- | Generalized version of 'A.forConcurrently'.
281+ :: (Traversable f, AsyncE :> es)
285+forConcurrently = flip mapConcurrently
287+-- | Generalized version of 'A.forConcurrently_'.
289+ :: (Foldable f, AsyncE :> es)
293+forConcurrently_ = flip mapConcurrently_
295+-- | Generalized version of 'A.replicateConcurrently'.
296+replicateConcurrently :: AsyncE :> es => Int -> Eff es a -> Eff es [a]
297+replicateConcurrently n =
298+ runConcurrently . sequenceA . replicate n . Concurrently
300+-- | Generalized version of 'A.replicateConcurrently_'.
301+replicateConcurrently_ :: AsyncE :> es => Int -> Eff es a -> Eff es ()
302+replicateConcurrently_ n =
303+ runConcurrently . fold . replicate n . Concurrently . void
305+----------------------------------------
307+-- | Generalized version of 'A.Concurrently'.
308+newtype Concurrently es a = Concurrently { runConcurrently :: Eff es a }
310+instance Functor (Concurrently es) where
311+ fmap f (Concurrently a) = Concurrently (fmap f a)
313+instance AsyncE :> es => Applicative (Concurrently es) where
314+ pure = Concurrently . pure
315+ Concurrently fs <*> Concurrently as =
316+ Concurrently ((\(f, a) -> f a) <$> concurrently fs as)
318+instance AsyncE :> es => Alternative (Concurrently es) where
319+ empty = Concurrently . unsafeEff_ . forever $ threadDelay maxBound
320+ Concurrently as <|> Concurrently bs =
321+ Concurrently (either id id <$> race as bs)
323+instance (AsyncE :> es, Semigroup a) => Semigroup (Concurrently es a) where
326+instance (AsyncE :> es, Monoid a) => Monoid (Concurrently es a) where
327+ mempty = pure mempty
329+----------------------------------------
333+ :: (IO a -> IO (Async a))
336+liftAsync fork action = unsafeEff $ \es0 -> do
338+ fork $ unEff action es
341+ :: (((forall b. IO b -> IO b) -> IO a) -> IO (Async a))
342+ -> ((forall b. Eff es b -> Eff es b) -> Eff es a)
344+liftAsyncWithUnmask fork action = unsafeEff $ \es0 -> do
346+ fork $ \unmask -> unEff (action $ \m -> unsafeEff $ unmask . unEff m) es
349+ :: (IO a -> (Async a -> IO b) -> IO b)
351+ -> (Async a -> Eff es b)
353+liftWithAsync withA action k = unsafeEff $ \es0 -> do
355+ withA (unEff action es)
356+ (\a -> unEff (k a) es0)
358+liftWithAsyncWithUnmask
359+ :: (((forall c. IO c -> IO c) -> IO a) -> (Async a -> IO b) -> IO b)
360+ -> ((forall c. Eff es c -> Eff es c) -> Eff es a)
361+ -> (Async a -> Eff es b)
363+liftWithAsyncWithUnmask withA action k = unsafeEff $ \es0 -> do
365+ withA (\unmask -> unEff (action $ \m -> unsafeEff $ unmask . unEff m) es)
366+ (\a -> unEff (k a) es0)