Skip to content

Commit 03618df

Browse files
Return Canceler from runAff/launchAff
1 parent 4ab4eb7 commit 03618df

File tree

2 files changed

+78
-53
lines changed

2 files changed

+78
-53
lines changed

src/Control/Monad/Aff.purs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ foreign import data Aff :: # ! -> * -> *
4646
-- | asynchronous computation.
4747
type PureAff a = forall e. Aff e a
4848

49-
-- | A canceler is asynchronous function that can be used to attempt the
49+
-- | A canceler is an asynchronous function that can be used to attempt the
5050
-- | cancelation of a computation. Returns a boolean flag indicating whether
5151
-- | or not the cancellation was successful. Many computations may be composite,
5252
-- | in such cases the flag indicates whether any part of the computation was
5353
-- | successfully canceled. The flag should not be used for communication.
5454
newtype Canceler e = Canceler (Error -> Aff e Boolean)
5555

5656
-- | Unwraps the canceler function from the newtype that wraps it.
57-
cancel :: forall e. Canceler e -> Error -> Aff e Boolean
57+
cancel :: forall e. Canceler e -> Error -> Aff e Boolean
5858
cancel (Canceler f) = f
5959

6060
-- | This function allows you to attach a custom canceler to an asynchronous
@@ -73,15 +73,20 @@ cancelWith aff c = runFn3 _cancelWith nonCanceler aff c
7373
-- | If you do need to handle exceptions, you can use `runAff` instead, or
7474
-- | you can handle the exception within the Aff computation, using
7575
-- | `catchError` (or any of the other mechanisms).
76-
launchAff :: forall e a. Aff e a -> Eff (err :: EXCEPTION | e) Unit
77-
launchAff = runAff throwException (const (pure unit)) <<< liftEx
76+
launchAff :: forall e a. Aff e a -> Eff (err :: EXCEPTION | e) (Canceler e)
77+
launchAff = lowerEx <<< runAff throwException (const (pure unit)) <<< liftEx
7878
where
7979
liftEx :: Aff e a -> Aff (err :: EXCEPTION | e) a
8080
liftEx = _unsafeInterleaveAff
81+
lowerEx :: Eff (err :: EXCEPTION | e) (Canceler (err :: EXCEPTION | e)) -> Eff (err :: EXCEPTION | e) (Canceler e)
82+
lowerEx = map (Canceler <<< map _unsafeInterleaveAff <<< cancel)
8183

8284
-- | Runs the asynchronous computation. You must supply an error callback and a
8385
-- | success callback.
84-
runAff :: forall e a. (Error -> Eff e Unit) -> (a -> Eff e Unit) -> Aff e a -> Eff e Unit
86+
-- |
87+
-- | Returns a canceler that can be used to attempt cancellation of the
88+
-- | asynchronous computation.
89+
runAff :: forall e a. (Error -> Eff e Unit) -> (a -> Eff e Unit) -> Aff e a -> Eff e (Canceler e)
8590
runAff ex f aff = runFn3 _runAff ex f aff
8691

8792
-- | Creates an asynchronous effect from a function that accepts error and
@@ -194,7 +199,7 @@ instance monadRecAff :: MonadRec (Aff e) where
194199
tailRecM f a = runFn3 _tailRecM isLeft f a
195200

196201
instance monadContAff :: MonadCont (Aff e) where
197-
callCC f = makeAff (\eb cb -> runAff eb cb (f \a -> makeAff (\_ _ -> cb a)))
202+
callCC f = makeAff (\eb cb -> void $ runAff eb cb (f \a -> makeAff (\_ _ -> cb a)))
198203

199204
instance semigroupCanceler :: Semigroup (Canceler e) where
200205
append (Canceler f1) (Canceler f2) = Canceler (\e -> (||) <$> f1 e <*> f2 e)
@@ -224,7 +229,7 @@ foreign import _bind :: forall e a b. Fn3 (Canceler e) (Aff e a) (a -> Aff e b)
224229

225230
foreign import _attempt :: forall e a. Fn3 (forall x y. x -> Either x y) (forall x y. y -> Either x y) (Aff e a) (Aff e (Either Error a))
226231

227-
foreign import _runAff :: forall e a. Fn3 (Error -> Eff e Unit) (a -> Eff e Unit) (Aff e a) (Eff e Unit)
232+
foreign import _runAff :: forall e a. Fn3 (Error -> Eff e Unit) (a -> Eff e Unit) (Aff e a) (Eff e (Canceler e))
228233

229234
foreign import _liftEff :: forall e a. Fn2 (Canceler e) (Eff e a) (Aff e a)
230235

test/Test/Main.purs

Lines changed: 66 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ import Prelude
44

55
import Control.Alt ((<|>))
66
import Control.Apply ((*>))
7-
import Control.Monad.Aff (Aff, runAff, makeAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize)
7+
import Control.Monad.Aff (Aff, runAff, makeAff, launchAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize)
88
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, killVar)
99
import Control.Monad.Aff.Console (log)
1010
import Control.Monad.Aff.Par (Par(..), runPar)
1111
import Control.Monad.Cont.Class (callCC)
1212
import Control.Monad.Eff (Eff)
1313
import Control.Monad.Eff.Console (CONSOLE)
14-
import Control.Monad.Eff.Exception (EXCEPTION, throwException, error, message)
14+
import Control.Monad.Eff.Console (log) as Eff
15+
import Control.Monad.Eff.Exception (EXCEPTION, throwException, error, message, try)
1516
import Control.Monad.Error.Class (throwError)
1617
import Control.Monad.Rec.Class (tailRecM)
1718
import Data.Either (Either(..), either, fromLeft, fromRight)
@@ -137,6 +138,18 @@ test_cancelLater = do
137138
v <- cancel c (error "Cause")
138139
log (if v then "Success: Canceled later" else "Failure: Did not cancel later")
139140

141+
test_cancelLaunchLater :: forall e. Eff (console :: CONSOLE, err :: EXCEPTION | e) Unit
142+
test_cancelLaunchLater = do
143+
c <- launchAff $ later' 100 $ log ("Failure: Later was not canceled!")
144+
void $ launchAff $ (do v <- cancel c (error "Cause")
145+
log (if v then "Success: Canceled later" else "Failure: Did not cancel later"))
146+
147+
test_cancelRunLater :: forall e. Eff (console :: CONSOLE | e) Unit
148+
test_cancelRunLater = do
149+
c <- runAff (const (pure unit)) (const (pure unit)) $ later' 100 $ log ("Failure: Later was not canceled!")
150+
void $ try $ launchAff $ (do v <- cancel c (error "Cause")
151+
log (if v then "Success: Canceled later" else "Failure: Did not cancel later"))
152+
140153
test_cancelPar :: TestAVar Unit
141154
test_cancelPar = do
142155
c <- forkAff <<< runPar $ Par (later' 100 $ log "Failure: #1 should not get through") <|>
@@ -187,69 +200,76 @@ delay n = callCC \cont ->
187200
later' n (cont unit)
188201

189202
main :: Eff (console :: CONSOLE, avar :: AVAR, err :: EXCEPTION) Unit
190-
main = runAff throwException (const (pure unit)) $ do
191-
log "Testing sequencing"
192-
test_sequencing 3
203+
main = do
204+
Eff.log "Testing kill of later launched in separate Aff"
205+
test_cancelLaunchLater
206+
207+
Eff.log "Testing kill of later run in separate Aff"
208+
test_cancelRunLater
209+
210+
void $ runAff throwException (const (pure unit)) $ do
211+
log "Testing sequencing"
212+
test_sequencing 3
193213

194-
log "Testing pure"
195-
test_pure
214+
log "Testing pure"
215+
test_pure
196216

197-
log "Testing makeAff"
198-
test_makeAff
217+
log "Testing makeAff"
218+
test_makeAff
199219

200-
log "Testing attempt"
201-
test_attempt
220+
log "Testing attempt"
221+
test_attempt
202222

203-
log "Testing later"
204-
later $ log "Success: It happened later"
223+
log "Testing later"
224+
later $ log "Success: It happened later"
205225

206-
log "Testing kill of later"
207-
test_cancelLater
226+
log "Testing kill of later"
227+
test_cancelLater
208228

209-
log "Testing kill of first forked"
210-
test_killFirstForked
229+
log "Testing kill of first forked"
230+
test_killFirstForked
211231

212-
log "Testing apathize"
213-
test_apathize
232+
log "Testing apathize"
233+
test_apathize
214234

215-
log "Testing semigroup canceler"
216-
test_semigroupCanceler
235+
log "Testing semigroup canceler"
236+
test_semigroupCanceler
217237

218-
log "Testing AVar - putVar, takeVar"
219-
test_putTakeVar
238+
log "Testing AVar - putVar, takeVar"
239+
test_putTakeVar
220240

221-
log "Testing AVar killVar"
222-
test_killVar
241+
log "Testing AVar killVar"
242+
test_killVar
223243

224-
log "Testing finally"
225-
test_finally
244+
log "Testing finally"
245+
test_finally
226246

227-
log "Test Par (*>)"
228-
test_parError
247+
log "Test Par (*>)"
248+
test_parError
229249

230-
log "Testing Par (<|>)"
231-
test_parRace
250+
log "Testing Par (<|>)"
251+
test_parRace
232252

233-
log "Testing Par (<|>) - kill one"
234-
test_parRaceKill1
253+
log "Testing Par (<|>) - kill one"
254+
test_parRaceKill1
235255

236-
log "Testing Par (<|>) - kill two"
237-
test_parRaceKill2
256+
log "Testing Par (<|>) - kill two"
257+
test_parRaceKill2
238258

239-
log "Testing cancel of Par (<|>)"
240-
test_cancelPar
259+
log "Testing cancel of Par (<|>)"
260+
test_cancelPar
241261

242-
log "Testing synchronous tailRecM"
243-
test_syncTailRecM
262+
log "Testing synchronous tailRecM"
263+
test_syncTailRecM
244264

245-
log "pre-delay"
246-
delay 1000
247-
log "post-delay"
265+
log "pre-delay"
266+
delay 1000
267+
log "post-delay"
248268

249-
loopAndBounce 1000000
269+
loopAndBounce 1000000
250270

251-
all 100000
271+
all 100000
252272

253-
cancelAll 100000
273+
cancelAll 100000
254274

255-
log "Done testing"
275+
log "Done testing"

0 commit comments

Comments
 (0)