@@ -33,20 +33,22 @@ data ParAff eff a
33
33
= forall b. Map (b -> a) (ParAff eff b)
34
34
| forall b. Apply (ParAff eff (b -> a)) (ParAff eff b)
35
35
| Alt (ParAff eff a) (ParAff eff a)
36
- | Par (Aff eff a)
36
+ | ? Par (Aff eff a)
37
37
38
38
*/
39
39
var MAP = "Map"
40
40
var APPLY = "Apply"
41
41
var ALT = "Alt"
42
42
43
- // These are constructors used to implement the recover stack. We still use the
44
- // Aff constructor so that property offsets can always inline.
45
- var CONS = "Cons" ; // Cons-list
46
- var RECOVER = "Recover" ; // Continue with `Either Error a` (via attempt)
43
+ // Various constructors used in interpretation
44
+ var CONS = "Cons" ; // Cons-list, for stacks
45
+ var RECOVER = "Recover" ; // Continue with error handler
47
46
var RESUME = "Resume" ; // Continue indiscriminately
48
47
var FINALIZED = "Finalized" ; // Marker for finalization
49
- var THREAD = "Thread" ;
48
+
49
+ var FORKED = "Forked" ; // Reference to a forked thread, with resumption stack
50
+ var THREAD = "Thread" ; // Actual thread reference
51
+ var THUNK = "Thunk" ; // Primed effect, ready to invoke
50
52
51
53
function Aff ( tag , _1 , _2 , _3 ) {
52
54
this . tag = tag ;
@@ -570,7 +572,7 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
570
572
var root = EMPTY ;
571
573
572
574
// Walks the applicative tree, substituting non-applicative nodes with
573
- // `THREAD ` nodes. In this tree, all applicative nodes use the `_3` slot
575
+ // `FORKED ` nodes. In this tree, all applicative nodes use the `_3` slot
574
576
// as a mutable slot for memoization. In an unresolved state, the `_3`
575
577
// slot is `EMPTY`. In the cases of `ALT` and `APPLY`, we always walk
576
578
// the left side first, because both operations are left-associative. As
@@ -611,18 +613,18 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
611
613
step = step . _1 ;
612
614
break ;
613
615
default :
614
- // When we hit a leaf value, we suspend the stack in the `THREAD `.
616
+ // When we hit a leaf value, we suspend the stack in the `FORKED `.
615
617
// When the thread resolves, it can bubble back up the tree.
616
618
tid = threadId ++ ;
617
619
status = RETURN ;
618
620
tmp = step ;
619
- step = new Aff ( THREAD , tid , new Aff ( CONS , head , tail ) , EMPTY ) ;
621
+ step = new Aff ( FORKED , tid , new Aff ( CONS , head , tail ) , EMPTY ) ;
620
622
// We prime the effect, but don't immediately run it. We need to
621
623
// walk the entire tree first before actually running effects
622
624
// because they may all be synchronous and resolve immediately, at
623
625
// which point it would attempt to resolve against an incomplete
624
626
// tree.
625
- threads [ tid ] = runAff ( resolve ( step ) ) ( tmp ) ;
627
+ threads [ tid ] = new Aff ( THUNK , runAff ( resolve ( step ) ) ( tmp ) ) ;
626
628
}
627
629
break ;
628
630
case RETURN :
@@ -656,7 +658,10 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
656
658
// Walk the primed threads and fork them. We store the actual `Thread`
657
659
// reference so we can cancel them when needed.
658
660
for ( tid = 0 ; tid < threadId ; tid ++ ) {
659
- threads [ tid ] = threads [ tid ] ( ) ;
661
+ tmp = threads [ tid ] ;
662
+ if ( tmp && tmp . tag === THUNK ) {
663
+ threads [ tid ] = new Aff ( THREAD , tmp . _1 ( ) ) ;
664
+ }
660
665
}
661
666
}
662
667
@@ -747,7 +752,6 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
747
752
head . _3 = step ;
748
753
tmp = true ;
749
754
kid = killId ++ ;
750
-
751
755
// Once a side has resolved, we need to cancel the side that is still
752
756
// pending before we can continue.
753
757
kills [ kid ] = kill ( early , step === lhs ? head . _2 : head . _1 , function ( killResult ) {
@@ -796,16 +800,19 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
796
800
797
801
loop: while ( 1 ) {
798
802
tmp = null ;
799
- kid = null ;
800
803
801
804
switch ( step . tag ) {
802
- case THREAD :
805
+ case FORKED :
803
806
tmp = threads [ step . _1 ] ;
804
- kid = count ++ ;
805
- if ( tmp ) {
807
+ // If we haven't forked the thread yet (such as with a sync Alt),
808
+ // then we should just remove it from the queue and continue.
809
+ if ( tmp . tag === THUNK ) {
810
+ delete threads [ step . _1 ] ;
811
+ cb ( right ( void 0 ) ) ( ) ;
812
+ } else {
806
813
// Again, we prime the effect but don't run it yet, so that we can
807
814
// collect all the threads first.
808
- kills [ kid ] = runAff ( function ( result ) {
815
+ kills [ count ++ ] = runAff ( function ( result ) {
809
816
return function ( ) {
810
817
count -- ;
811
818
if ( fail === null && isLeft ( result ) ) {
@@ -816,7 +823,7 @@ exports._sequential = function (isLeft, fromLeft, fromRight, left, right, runAff
816
823
cb ( fail || right ( void 0 ) ) ( ) ;
817
824
}
818
825
} ;
819
- } ) ( tmp . kill ( error ) ) ;
826
+ } ) ( tmp . _1 . kill ( error ) ) ;
820
827
}
821
828
// Terminal case.
822
829
if ( head === null ) {
0 commit comments