Skip to content

Commit 47ea676

Browse files
committed
MonadPar WIP
1 parent 4ab4eb7 commit 47ea676

File tree

4 files changed

+85
-23
lines changed

4 files changed

+85
-23
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"purescript-console": "^1.0.0",
2121
"purescript-exceptions": "^1.0.0",
2222
"purescript-functions": "^1.0.0",
23-
"purescript-transformers": "^1.0.0"
23+
"purescript-transformers": "^1.0.0",
24+
"purescript-parallel": "^1.0.0"
2425
},
2526
"devDependencies": {
2627
"purescript-partial": "^1.1.2"

src/Control/Monad/Aff.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,11 @@ exports._tailRecM = function (isLeft, f, a) {
320320
}(a);
321321
};
322322
};
323+
324+
325+
var avar = require("../Control.Monad.Aff.AVar/foreign.js");
326+
327+
exports._makeVar = avar._makeVar;
328+
exports._takeVar = avar._takeVar;
329+
exports._putVar = avar._putVar;
330+
exports._killVar = avar._killVar;

src/Control/Monad/Aff.purs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module Control.Monad.Aff
2121
where
2222

2323
import Prelude
24+
2425
import Control.Alt (class Alt)
2526
import Control.Alternative (class Alternative)
2627
import Control.Monad.Cont.Class (class MonadCont)
@@ -30,7 +31,9 @@ import Control.Monad.Eff.Exception (Error, EXCEPTION, throwException, error)
3031
import Control.Monad.Error.Class (class MonadError, throwError)
3132
import Control.Monad.Rec.Class (class MonadRec)
3233
import Control.MonadPlus (class MonadZero, class MonadPlus)
34+
import Control.Parallel.Class (class MonadRace, class MonadPar)
3335
import Control.Plus (class Plus)
36+
3437
import Data.Either (Either(..), either, isLeft)
3538
import Data.Foldable (class Foldable, foldl)
3639
import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
@@ -202,6 +205,56 @@ instance semigroupCanceler :: Semigroup (Canceler e) where
202205
instance monoidCanceler :: Monoid (Canceler e) where
203206
mempty = Canceler (const (pure true))
204207

208+
instance monadParAff :: MonadPar (Aff e) where
209+
par f ma mb = do
210+
va <- _makeVar nonCanceler
211+
vb <- _makeVar nonCanceler
212+
c1 <- forkAff (putOrKill va =<< attempt ma)
213+
c2 <- forkAff (putOrKill vb =<< attempt mb)
214+
f <$> (takeVar va) <*> (takeVar vb)
215+
where
216+
putOrKill :: forall a. AVar a -> Either Error a -> Aff e Unit
217+
putOrKill v = either (killVar v) (putVar v)
218+
219+
instance monadRaceAff :: MonadRace (Aff e) where
220+
stall = throwError $ error "Stalled"
221+
race a1 a2 = do
222+
va <- _makeVar nonCanceler -- the `a` value
223+
ve <- _makeVar nonCanceler -- the error count (starts at 0)
224+
putVar ve 0
225+
c1 <- forkAff $ either (maybeKill va ve) (putVar va) =<< attempt a1
226+
c2 <- forkAff $ either (maybeKill va ve) (putVar va) =<< attempt a2
227+
takeVar va `cancelWith` (c1 <> c2)
228+
where
229+
maybeKill :: forall a. AVar a -> AVar Int -> Error -> Aff e Unit
230+
maybeKill va ve err = do
231+
e <- takeVar ve
232+
if e == 1 then killVar va err else pure unit
233+
putVar ve (e + 1)
234+
235+
--------------------------------
236+
237+
foreign import data AVar :: * -> *
238+
239+
takeVar :: forall e a. AVar a -> Aff e a
240+
takeVar q = runFn2 _takeVar nonCanceler q
241+
242+
putVar :: forall e a. AVar a -> a -> Aff e Unit
243+
putVar q a = runFn3 _putVar nonCanceler q a
244+
245+
killVar :: forall e a. AVar a -> Error -> Aff e Unit
246+
killVar q e = runFn3 _killVar nonCanceler q e
247+
248+
foreign import _makeVar :: forall e a. Canceler e -> Aff e (AVar a)
249+
250+
foreign import _takeVar :: forall e a. Fn2 (Canceler e) (AVar a) (Aff e a)
251+
252+
foreign import _putVar :: forall e a. Fn3 (Canceler e) (AVar a) a (Aff e Unit)
253+
254+
foreign import _killVar :: forall e a. Fn3 (Canceler e) (AVar a) Error (Aff e Unit)
255+
256+
--------------------------------
257+
205258
foreign import _cancelWith :: forall e a. Fn3 (Canceler e) (Aff e a) (Canceler e) (Aff e a)
206259

207260
foreign import _setTimeout :: forall e a. Fn3 (Canceler e) Int (Aff e a) (Aff e a)

test/Test/Main.purs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import Prelude
44

55
import Control.Alt ((<|>))
66
import Control.Apply ((*>))
7+
import Control.Parallel.Class (parallel, runParallel)
78
import Control.Monad.Aff (Aff, runAff, makeAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize)
89
import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, killVar)
910
import Control.Monad.Aff.Console (log)
10-
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)
@@ -40,8 +40,8 @@ test_makeAff = unsafePartial do
4040
asyncF <- attempt $ makeAff \reject resolve -> reject (error "ok")
4141
log $ "makeAff asynchronous failure is " <> message (fromLeft asyncF)
4242

43-
asyncF <- attempt $ makeAff \reject resolve -> synchronousUnexpectedThrowError
44-
log $ "makeAff synchronous failure is " <> message (fromLeft asyncF)
43+
asyncF' <- attempt $ makeAff \reject resolve -> synchronousUnexpectedThrowError
44+
log $ "makeAff synchronous failure is " <> message (fromLeft asyncF')
4545

4646
log "Success: makeAff is ok"
4747

@@ -99,25 +99,25 @@ test_finally = do
9999

100100
test_parRace :: TestAVar Unit
101101
test_parRace = do
102-
s <- runPar (Par (later' 100 $ pure "Success: Early bird got the worm") <|>
103-
Par (later' 200 $ pure "Failure: Late bird got the worm"))
102+
s <- runParallel (parallel (later' 100 $ pure "Success: Early bird got the worm") <|>
103+
parallel (later' 200 $ pure "Failure: Late bird got the worm"))
104104
log s
105105

106106
test_parError :: TestAVar Unit
107107
test_parError = do
108-
e <- attempt $ runPar (Par (throwError (error ("Oh noes!"))) *> pure unit)
108+
e <- attempt $ runParallel (parallel (throwError (error ("Oh noes!"))) *> pure unit)
109109
either (const $ log "Success: Exception propagated") (const $ log "Failure: Exception missing") e
110110

111111
test_parRaceKill1 :: TestAVar Unit
112112
test_parRaceKill1 = do
113-
s <- runPar (Par (later' 100 $ throwError (error ("Oh noes!"))) <|>
114-
Par (later' 200 $ pure "Success: Early error was ignored in favor of late success"))
113+
s <- runParallel (parallel (later' 100 $ throwError (error ("Oh noes!"))) <|>
114+
parallel (later' 200 $ pure "Success: Early error was ignored in favor of late success"))
115115
log s
116116

117117
test_parRaceKill2 :: TestAVar Unit
118118
test_parRaceKill2 = do
119-
e <- attempt $ runPar (Par (later' 100 $ throwError (error ("Oh noes!"))) <|>
120-
Par (later' 200 $ throwError (error ("Oh noes!"))))
119+
e <- attempt $ runParallel (parallel (later' 100 $ throwError (error ("Oh noes!"))) <|>
120+
parallel (later' 200 $ throwError (error ("Oh noes!"))))
121121
either (const $ log "Success: Killing both kills it dead") (const $ log "Failure: It's alive!!!") e
122122

123123
test_semigroupCanceler :: Test Unit
@@ -137,13 +137,13 @@ test_cancelLater = do
137137
v <- cancel c (error "Cause")
138138
log (if v then "Success: Canceled later" else "Failure: Did not cancel later")
139139

140-
test_cancelPar :: TestAVar Unit
141-
test_cancelPar = do
142-
c <- forkAff <<< runPar $ Par (later' 100 $ log "Failure: #1 should not get through") <|>
143-
Par (later' 100 $ log "Failure: #2 should not get through")
140+
test_cancelParallel :: TestAVar Unit
141+
test_cancelParallel = do
142+
c <- forkAff <<< runParallel $ parallel (later' 100 $ log "Failure: #1 should not get through") <|>
143+
parallel (later' 100 $ log "Failure: #2 should not get through")
144144
v <- c `cancel` (error "Must cancel")
145-
log (if v then "Success: Canceling composite of two Par succeeded"
146-
else "Failure: Canceling composite of two Par failed")
145+
log (if v then "Success: Canceling composite of two Parallel succeeded"
146+
else "Failure: Canceling composite of two Parallel failed")
147147

148148
test_syncTailRecM :: TestAVar Unit
149149
test_syncTailRecM = do
@@ -224,20 +224,20 @@ main = runAff throwException (const (pure unit)) $ do
224224
log "Testing finally"
225225
test_finally
226226

227-
log "Test Par (*>)"
227+
log "Test Parallel (*>)"
228228
test_parError
229229

230-
log "Testing Par (<|>)"
230+
log "Testing Parallel (<|>)"
231231
test_parRace
232232

233-
log "Testing Par (<|>) - kill one"
233+
log "Testing Parallel (<|>) - kill one"
234234
test_parRaceKill1
235235

236-
log "Testing Par (<|>) - kill two"
236+
log "Testing Parallel (<|>) - kill two"
237237
test_parRaceKill2
238238

239-
log "Testing cancel of Par (<|>)"
240-
test_cancelPar
239+
log "Testing cancel of Parallel (<|>)"
240+
test_cancelParallel
241241

242242
log "Testing synchronous tailRecM"
243243
test_syncTailRecM

0 commit comments

Comments
 (0)