Skip to content

Commit 04f9696

Browse files
committed
Applicative instance for Thread
1 parent 67ad0d2 commit 04f9696

File tree

3 files changed

+67
-35
lines changed

3 files changed

+67
-35
lines changed

src/Control/Monad/Aff.js

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
/* jshint -W083, -W098 */
33
"use strict";
44

5+
// A unique value for empty.
6+
var EMPTY = {};
7+
58
/*
69
710
An awkward approximation. We elide evidence we would otherwise need in PS for
@@ -90,47 +93,37 @@ exports.bracket = function (acquire) {
9093
};
9194
};
9295

93-
exports.mapThread = function () {
94-
var EMPTY = {};
95-
96-
return function (f) {
97-
return function (thread) {
98-
var value = EMPTY;
99-
100-
function force() {
101-
if (value === EMPTY) {
102-
return new Aff(BIND, thread.join, function (result) {
103-
value = new Aff(PURE, f(result));
104-
return value;
105-
});
106-
} else {
107-
return value;
108-
}
109-
}
110-
111-
return {
112-
kill: thread.kill,
113-
join: new Aff(BIND, new Aff(PURE, void 0), force)
114-
};
115-
};
116-
};
117-
}();
96+
exports.memoAff = function (aff) {
97+
var value = EMPTY;
98+
return new Aff(BIND, new Aff(PURE, void 0), function () {
99+
if (value === EMPTY) {
100+
return new Aff(BIND, aff, function (result) {
101+
value = new Aff(PURE, result);
102+
return value;
103+
});
104+
} else {
105+
return value;
106+
}
107+
});
108+
};
118109

119110
exports._delay = function () {
120-
var setDelay = function (n, k) {
111+
function setDelay(n, k) {
121112
if (n === 0 && typeof setImmediate !== "undefined") {
122113
return setImmediate(k);
123114
} else {
124115
return setTimeout(k, n);
125116
}
126-
};
127-
var clearDelay = function (n, t) {
117+
}
118+
119+
function clearDelay(n, t) {
128120
if (n === 0 && typeof clearImmediate !== "undefined") {
129121
return clearImmediate(t);
130122
} else {
131123
return clearTimeout(t);
132124
}
133-
};
125+
}
126+
134127
return function (right, ms) {
135128
return new Aff(ASYNC, function (cb) {
136129
return function () {

src/Control/Monad/Aff.purs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import Control.Monad.Rec.Class (class MonadRec, Step(..))
3434
import Control.MonadPlus (class MonadPlus)
3535
import Control.MonadZero (class MonadZero)
3636
import Control.Parallel (parSequence_)
37-
import Control.Parallel.Class (class Parallel)
37+
import Control.Parallel.Class (class Parallel, parallel, sequential)
3838
import Control.Plus (class Plus, empty)
3939
import Data.Either (Either(..), isLeft)
4040
import Data.Function.Uncurried as Fn
@@ -190,7 +190,25 @@ newtype Thread eff a = Thread
190190
}
191191

192192
instance functorThreadFunctor (Thread eff) where
193-
map = mapThread
193+
map f (Thread { kill, join }) = Thread
194+
{ kill
195+
, join: memoAff (f <$> join)
196+
}
197+
198+
instance applyThreadApply (Thread eff) where
199+
apply t1 t2 = Thread
200+
{ kill: \err → sequential $ parallel (killThread err t1) *> parallel (killThread err t2)
201+
, join: memoAff do
202+
f ← joinThread t1
203+
a ← joinThread t2
204+
pure (f a)
205+
}
206+
207+
instance applicativeThreadApplicative (Thread eff) where
208+
pure a = Thread
209+
{ kill: const (pure unit)
210+
, join: pure a
211+
}
194212

195213
killThread eff a. Error Thread eff a Aff eff Unit
196214
killThread e (Thread t) = t.kill e
@@ -242,7 +260,7 @@ foreign import _delay ∷ ∀ a eff. Fn.Fn2 (Unit → Either a Unit) Number (Aff
242260
foreign import _liftEff eff a. Eff eff a Aff eff a
243261
foreign import bracket eff a b. Aff eff a (a Aff eff Unit) (a Aff eff b) Aff eff b
244262
foreign import makeAff eff a. ((Either Error a Eff eff Unit) Eff eff (Canceler eff)) Aff eff a
245-
foreign import mapThread eff a b. (a b) Thread eff a Thread eff b
263+
foreign import memoAff eff a. Aff eff a Aff eff a
246264

247265
foreign import _launchAff
248266
eff a

test/Test/Main.purs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,8 +347,8 @@ test_kill_parallel_alt = assert "kill/parallel/alt" do
347347
_ ← try $ joinThread t2
348348
eq "killedfookilledbardone" <$> readRef ref
349349

350-
test_mapThread eff. TestAff eff Unit
351-
test_mapThread = assert "mapThread" do
350+
test_thread_map eff. TestAff eff Unit
351+
test_thread_map = assert "thread/map" do
352352
ref ← newRef 0
353353
let
354354
mapFn a = runPure do
@@ -364,6 +364,26 @@ test_mapThread = assert "mapThread" do
364364
n ← readRef ref
365365
pure (a == 11 && b == 11 && n == 1)
366366

367+
test_thread_apply eff. TestAff eff Unit
368+
test_thread_apply = assert "thread/apply" do
369+
ref ← newRef 0
370+
let
371+
applyFn a b = runPure do
372+
unsafeRunRef $ Ref.modifyRef ref (_ + 1)
373+
pure (a + b)
374+
t1 ← forkAff do
375+
delay (Milliseconds 10.0)
376+
pure 10
377+
t2 ← forkAff do
378+
delay (Milliseconds 15.0)
379+
pure 12
380+
let
381+
t3 = applyFn <$> t1 <*> t2
382+
a ← joinThread t3
383+
b ← joinThread t3
384+
n ← readRef ref
385+
pure (a == 22 && b == 22 && n == 1)
386+
367387
main TestEff () Unit
368388
main = do
369389
test_pure
@@ -390,4 +410,5 @@ main = do
390410
test_kill_parallel
391411
test_parallel_alt
392412
test_kill_parallel_alt
393-
test_mapThread
413+
test_thread_map
414+
test_thread_apply

0 commit comments

Comments
 (0)