async
async copied to clipboard
Idea for Monad instance of Concurrently compatible with the Applicative Instance
The obvious way to make Concurrently into a Monad doesn't work, since then Monad would be sequential, but Applicative would be concurrent (whereas Monad is usually supposed to be a generalization of Applicative). There is a way to make a Monad instance though that is as concurrent as possible (in particular, ap
would be perfectly concurrent).
The trick is the same one used for fixIO
. Given x :: Concurrently a
and f :: a -> Concurrently b
, we use unsafeInterleaveIO
to start a thread to put x
into a MVar (or TMVar or Async), and then use unsafeInterleaveIO
to read the value from the variable lazily. We can then start f
's action. If f
needs x
's value to do anything, it will be sequential. On the other hand, if f
does not use x
's value at all (such as in ap
), it will be perfectly concurrent. It can also be anywhere in between.
I can do the code if you think this is a good concept. I just thought I'd check with you first to make sure its a good idea though.
Why would someone want a Monad instance for Concurrently
? Can you give an example of how it might be used?
@jml Well, for the getUrl example, we could have it fetch a list of urls from somewhere else. If the place its getting it from is slow, it would be able to start fetching the webpage of first url before it finishes getting the entire list. There are many other ways where having a Monad
instance is just convenient, even if it isn't necessarily concurrent. We could also give Concurrently
a MonadIO
and MonadFix
instance.