Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Applicative and Alternative instances for Async #90

Open
vwwv opened this issue Oct 24, 2018 · 5 comments
Open

Applicative and Alternative instances for Async #90

vwwv opened this issue Oct 24, 2018 · 5 comments

Comments

@vwwv
Copy link

vwwv commented Oct 24, 2018

Is there a reason not to have them? If not would a PR adding them be welcomed?

@cohei
Copy link

cohei commented Oct 25, 2018

Concurrently is expected to use for those instances, but I'm not sure.

@vwwv
Copy link
Author

vwwv commented Oct 25, 2018

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 an Internal 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?

@vwwv
Copy link
Author

vwwv commented Oct 25, 2018

I'll send an actual PR so you can check if it is ok.

@simonmar
Copy link
Owner

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?

@LukaJCB
Copy link

LukaJCB commented Nov 6, 2018

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants