async
async copied to clipboard
Applicative and Alternative instances for Async
Is there a reason not to have them? If not would a PR adding them be welcomed?
Concurrently
is expected to use for those instances, but I'm not sure.
I think it might be useful for some people to have both of them fit those instances, as some people (me included) prefer to use Async
sometimes and Concurrent
other times.
I was thinking about a potential way to implement those instances for Async
, without modifying much of the previous code, could be:
- Move the current definition of
Async
and related functions to anInternal
package, then I think it could be done, keeping the same semantics, with something like:
module Control.Concurrent.Async
( ...
) where
import Control.Concurrent.Async.Internal as Internal
data Async :: * -> * where
BasicAsync :: Internal.Async a -> Async a
ConcurrentAsync :: Async (a -> b) -> Async a -> Async b
AlternativeAsync :: Async a -> Async a -> Async a
EmptyAsync :: -> Async a
PureAsync :: a -> Async a
instance Applicative Async where
(<*>) = ConcurrentAsync
pure = PureAsync
instance Alternative Async where
(<|>) = AlternativeAsync
empty = EmptyAsync
async :: IO a -> IO (Async a)
async = fmap BasicAsync . Internal.async
cancel :: Async a -> IO ()
cancel = \case
BasicAsync x -> Internal.cancel x
ConcurrentAsync x y -> Internal.cancel x >> Internal.cancel y
AlternativeAsync x y -> Internal.cancel x >> Internal.cancel y
EmptyAsync -> return ()
PureAsync _ -> return ()
.... and so on with the rest of the methods
What do you think?
I'll send an actual PR so you can check if it is ok.
I'm not sure I understand the motivation for this, and it adds a lot of complexity. Is there somem reason you can't use Concurrently
?
One thing I like about an Alternative
instance for Async
over an Alternative
instance for Concurrently
, is the fact that with Async
<*>
distributes over <|>
. IMO nice to have both.