@@ -293,3 +293,64 @@ exports._liftEff = function (nonCanceler, e) {
293
293
return nonCanceler ;
294
294
} ;
295
295
}
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
+ // Observes synchronous effects using a flag.
303
+ // status = 0 (unresolved status)
304
+ // status = 1 (synchronous effect)
305
+ // status = 2 (asynchronous effect)
306
+ while ( true ) {
307
+ status = 0 ;
308
+ canceler = f ( acc ) ( function ( v ) {
309
+ // If the status is still unresolved, we have observed a
310
+ // synchronous effect. Otherwise, the status will be `2`.
311
+ if ( status === 0 ) {
312
+ // Store the result for further synchronous processing.
313
+ result = v ;
314
+ status = 1 ;
315
+ } else {
316
+ // When we have observed an asynchronous effect, we use normal
317
+ // recursion. This is safe because we will be on a new stack.
318
+ if ( isLeft ( v ) ) {
319
+ go ( v . value0 ) ;
320
+ } else {
321
+ try {
322
+ success ( v . value0 ) ;
323
+ } catch ( err ) {
324
+ error ( err ) ;
325
+ }
326
+ }
327
+ }
328
+ } , error ) ;
329
+
330
+ // If the status has already resolved to `1` by our Aff handler, then
331
+ // we have observed a synchronous effect. Otherwise it will still be
332
+ // `0`.
333
+ if ( status === 1 ) {
334
+ // When we have observed a synchronous effect, we merely swap out the
335
+ // accumulator and continue the loop, preserving stack.
336
+ if ( isLeft ( result ) ) {
337
+ acc = result . value0 ;
338
+ continue ;
339
+ } else {
340
+ try {
341
+ success ( result . value0 ) ;
342
+ } catch ( err ) {
343
+ error ( err ) ;
344
+ }
345
+ }
346
+ } else {
347
+ // If the status has not resolved yet, then we have observed an
348
+ // asynchronous effect.
349
+ status = 2 ;
350
+ }
351
+ return canceler ;
352
+ }
353
+
354
+ } ( a ) ;
355
+ } ;
356
+ } ;
0 commit comments