simonmar / async

Run IO operations asynchronously and wait for their results
BSD 3-Clause "New" or "Revised" License
321 stars 64 forks source link

SomeAsync and value replacement #144

Open treeowl opened 1 year ago

treeowl commented 1 year ago

cancelMany :: [Async a] -> IO () is ... okay, but it's annoying when cancelling Asyncs with multiple types. Some options:

-- Not very nice. Allocates wrappers unnecessarily.
data SomeAsync = forall a. SomeAsync !(Async a)
cancelSomeAsyncs :: [SomeAsync] -> IO ()

-- Is a `some` dependency okay, or copying stuff from there?
cancelSomeAsyncs :: [Some Async] -> IO ()

-- Potentially expensive if there's a lot of `fmap`ping and not a lot of inlining.
cancelAsyncs [() <$ thisOne, () <$ thatOne]

-- Can we make <$ cheaper? Yes, but it makes `Async` bigger. Any we need
-- to unsafeCoerce with Any to allow Async to unbox (ugh).
data Async a = Async !ThreadId !(TMVar (Either SomeException Any)) (Any -> a)
a <$ Async tid mv fun = Async tid mv (const a)

Nothing I'd call a beautiful solution.

treeowl commented 1 year ago

Oh yeah, there's also the HListy option:

data Asyncs :: [Type] -> Type where
  Nil :: Asyncs '[]
  (:<) :: {-# UNPACK #-} (Async a) -> Asyncs as -> Asyncs (a ': as)

But a custom heterogeneous list type doesn't seem appropriate for this package.