Skip to content

Commit 781edf1

Browse files
authored
Merge pull request #87 from garyb/cancelling-alt
Cancel the other branch when there's succeess in a race
2 parents 23797b4 + 47beb23 commit 781edf1

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

src/Control/Monad/Aff.purs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import Data.Foldable (class Foldable, foldl)
3939
import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
4040
import Data.Monoid (class Monoid, mempty)
4141
import Data.Newtype (class Newtype)
42+
import Data.Tuple (Tuple(..), fst, snd)
4243

4344
import Unsafe.Coerce (unsafeCoerce)
4445

@@ -244,11 +245,18 @@ instance altParAff :: Alt (ParAff e) where
244245
alt (ParAff a1) (ParAff a2) = ParAff do
245246
va <- makeVar -- the `a` value
246247
ve <- makeVar -- the error count (starts at 0)
248+
cs <- makeVar -- the cancelers
247249
putVar ve 0
248-
c1 <- forkAff $ either (maybeKill va ve) (putVar va) =<< attempt a1
249-
c2 <- forkAff $ either (maybeKill va ve) (putVar va) =<< attempt a2
250+
c1 <- forkAff $ either (maybeKill va ve) (done cs snd va) =<< attempt a1
251+
c2 <- forkAff $ either (maybeKill va ve) (done cs fst va) =<< attempt a2
252+
putVar cs (Tuple c1 c2)
250253
takeVar va `cancelWith` (c1 <> c2)
251254
where
255+
done :: forall a. AVar (Tuple (Canceler e) (Canceler e)) -> (forall x. Tuple x x -> x) -> AVar a -> a -> Aff e Unit
256+
done cs get va x = do
257+
putVar va x
258+
c <- get <$> takeVar cs
259+
void $ cancel c (error "Alt early exit")
252260
maybeKill :: forall a. AVar a -> AVar Int -> Error -> Aff e Unit
253261
maybeKill va ve err = do
254262
e <- takeVar ve

test/Test/Main.purs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,26 @@ test_cancelParallel = do
202202
log (if v then "Success: Canceling composite of two Parallel succeeded"
203203
else "Failure: Canceling composite of two Parallel failed")
204204

205+
test_cancelRaceLeft :: TestAVar Unit
206+
test_cancelRaceLeft = do
207+
var <- makeVar
208+
c <- sequential
209+
$ parallel (later' 250 $ putVar var true)
210+
<|> parallel (later' 100 $ pure unit)
211+
later' 500 $ putVar var false
212+
l <- takeVar var
213+
when l $ throwError (error "Failure: left side ran even though it lost the race")
214+
215+
test_cancelRaceRight :: TestAVar Unit
216+
test_cancelRaceRight = do
217+
var <- makeVar
218+
c <- sequential
219+
$ parallel (later' 100 $ pure unit)
220+
<|> parallel (later' 250 $ putVar var true)
221+
later' 500 $ putVar var false
222+
l <- takeVar var
223+
when l $ throwError (error "Failure: right side ran even though it lost the race")
224+
205225
test_syncTailRecM :: TestAVar Unit
206226
test_syncTailRecM = do
207227
v <- makeVar' false
@@ -305,6 +325,12 @@ main = do
305325
log "Testing cancel of Parallel (<|>)"
306326
test_cancelParallel
307327

328+
log "Testing cancel of left branch in parallel (<|>)"
329+
test_cancelRaceLeft
330+
331+
log "Testing cancel of right branch in parallel (<|>)"
332+
test_cancelRaceRight
333+
308334
log "Testing synchronous tailRecM"
309335
test_syncTailRecM
310336

0 commit comments

Comments
 (0)