Skip to content

Commit a520cb6

Browse files
committed
Alternative tailRecM implementation
Avoids async bouncing by observing synchronous effects and looping.
1 parent b472f7f commit a520cb6

File tree

2 files changed

+50
-9
lines changed

2 files changed

+50
-9
lines changed

src/Control/Monad/Aff.js

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,3 +293,49 @@ exports._liftEff = function (nonCanceler, e) {
293293
return nonCanceler;
294294
};
295295
}
296+
297+
exports._tailRecM = function (isLeft, f, a) {
298+
return function(success, error) {
299+
return function go(acc) {
300+
var result, status, canceler;
301+
302+
while (1) {
303+
status = 0;
304+
canceler = f(acc)(function(v) {
305+
if (status === 0) {
306+
result = v;
307+
status = 1;
308+
} else {
309+
try {
310+
if (isLeft(v)) {
311+
go(v.value0);
312+
} else {
313+
success(v.value0);
314+
}
315+
} catch (err) {
316+
error(err);
317+
}
318+
}
319+
}, error);
320+
321+
if (status === 1) {
322+
if (isLeft(result)) {
323+
acc = result.value0;
324+
continue;
325+
} else {
326+
try {
327+
success(result.value0);
328+
} catch (err) {
329+
error(err);
330+
}
331+
break;
332+
}
333+
} else {
334+
status = 2;
335+
return canceler;
336+
}
337+
}
338+
339+
}(a);
340+
};
341+
};

src/Control/Monad/Aff.purs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import Control.Monad.Rec.Class (MonadRec, tailRecM)
3333
import Control.MonadPlus (MonadPlus)
3434
import Control.Plus (Plus)
3535

36-
import Data.Either (Either(..), either)
36+
import Data.Either (Either(..), either, isLeft)
3737
import Data.Foldable (Foldable, foldl)
3838
import Data.Function (Fn2(), Fn3(), runFn2, runFn3)
3939
import Data.Monoid (Monoid, mempty)
@@ -191,14 +191,7 @@ instance alternativeAff :: Alternative (Aff e)
191191
instance monadPlusAff :: MonadPlus (Aff e)
192192

193193
instance monadRecAff :: MonadRec (Aff e) where
194-
tailRecM f a = go 0 f a
195-
where
196-
go size f a = do
197-
e <- f a
198-
case e of
199-
Left a' | size < 100 -> go (size + 1) f a'
200-
| otherwise -> later (tailRecM f a')
201-
Right b -> pure b
194+
tailRecM f a = runFn3 _tailRecM isLeft f a
202195

203196
instance monadContAff :: MonadCont (Aff e) where
204197
callCC f = makeAff (\eb cb -> runAff eb cb (f \a -> makeAff (\_ _ -> cb a)))
@@ -234,3 +227,5 @@ foreign import _attempt :: forall e a. Fn3 (forall x y. x -> Either x y) (forall
234227
foreign import _runAff :: forall e a. Fn3 (Error -> Eff e Unit) (a -> Eff e Unit) (Aff e a) (Eff e Unit)
235228

236229
foreign import _liftEff :: forall e a. Fn2 (Canceler e) (Eff e a) (Aff e a)
230+
231+
foreign import _tailRecM :: forall e a b. Fn3 (Either a b -> Boolean) (a -> Aff e (Either a b)) a (Aff e b)

0 commit comments

Comments
 (0)