async
async copied to clipboard
Musings on an Alternative instance for ConcurrentlyE
The Applicative
instance for ConcurrentlyE
behaves like concurrently
for successes and like race
for errors. Does ConcurrentlyE
also admit an Alternative
instance, like Concurrently
does?
One way to define it would be making (<|>
) behave like race
for both successes and errors. The problem is that the instance is boring. It offers nothing you couldn't do by wrapping an IO (Either e a)
in the nomal Concurrently
.
A more interesting instance would require a Semigroup
instance on the error e
, and return either the first success or the combination of all the errors.
Alas, this second definition has a problem. If empty
is the action that waits forever, then, for any action that fails, action <|> empty
will also wait forever! This is because we must wait for all the errors, and empty
never completes. This makes uses of Data.Foldable.asum
also hang.
The semigroupoids package provides Alt
, which is "Alternative
without empty
". It can be used with functions like asum1
.
semigroupoids
is a big package and I'm not proposing depending on it. But perhaps no Alternative
instance for ConcurrentlyE
should be defined, and an Alt
instance could be defined as an orphan in some other package instead.
Come to think of it, "either the first success or the combination of all the errors" is what the proposed Monoid
instance for ConcurrentlyE
does, if you flip the error and success types (the Monoid
gives you "either the first error or the combination of all successes") 🤔