Comparing version 3.0.0 to 3.1.0
185
fluture.js
@@ -34,2 +34,3 @@ //// ____ _ _ | ||
chain: 'fantasy-land/chain', | ||
chainRec: 'fantasy-land/chainRec', | ||
ap: 'fantasy-land/ap', | ||
@@ -63,4 +64,4 @@ of: 'fantasy-land/of' | ||
function isObject(x){ | ||
return typeof x === 'object' && x !== null; | ||
function isObject(o){ | ||
return o !== null && typeof o === 'object'; | ||
} | ||
@@ -73,3 +74,3 @@ | ||
function isIteration(o){ | ||
return isObject(o) && 'value' in o && 'done' in o && typeof o.done === 'boolean'; | ||
return isObject(o) && typeof o.done === 'boolean'; | ||
} | ||
@@ -113,2 +114,4 @@ | ||
const ordinal = ['first', 'second', 'third', 'fourth', 'fifth']; | ||
const Next = x => ({done: false, value: x}); | ||
const Done = x => ({done: true, value: x}); | ||
@@ -175,2 +178,30 @@ //Partially apply a function with a single argument. | ||
function check$chainRec(f){ | ||
if(!isFunction(f)) error$invalidArgument('Future.chainRec', 0, 'be a function', f); | ||
if(!isTernary(f)) error$invalidArgument('Future.chainRec', 0, 'take three arguments', f); | ||
} | ||
function check$chainRec$f(m, f, i, x){ | ||
if(!isFuture(m)) throw new TypeError( | ||
'Future.chainRec expects the function its given to return a Future every' | ||
+ ' time it is called. The value returned from' | ||
+ (ordinal[i] ? ` the ${ordinal[i]} call` : ` call ${i}`) | ||
+ ' was not a Future.' | ||
+ `\n Actual: ${show(m)}\n From calling: ${showf(f)}\n With: (Next, Done, ${show(x)})` | ||
); | ||
} | ||
function check$chainRec$it(it, i){ | ||
if(!isIteration(it)) throw new TypeError( | ||
'Future.chainRec expects the function its given to return a Future of an' | ||
+ ' Iteration every time it is called. The Future returned from' | ||
+ (ordinal[i] ? ` the ${ordinal[i]} call` : ` call ${i}`) | ||
+ ' did not resolve to a member of Iteration.' | ||
+ '\n You can create an uncomplete or complete Iteration using the next' | ||
+ ' or done functions respectively. These are passed into your callback' | ||
+ ' as first and second arguments.' | ||
+ `\n Actual: Future.of(${show(it)})` | ||
); | ||
} | ||
function check$recur(it, f){ | ||
@@ -307,3 +338,3 @@ if(!isFuture(it)) error$invalidContext('Future#recur', it); | ||
if(!isFunction(f)) error$invalidArgument('Future.encase2', 0, 'be a function', f); | ||
if(!isBinary(f)) error$invalidArgument('Future.encase2', 0, 'take at least two arguments', f); | ||
if(!isBinary(f)) error$invalidArgument('Future.encase2', 0, 'take two arguments', f); | ||
} | ||
@@ -313,3 +344,3 @@ | ||
if(!isFunction(f)) error$invalidArgument('Future.encase3', 0, 'be a function', f); | ||
if(!isTernary(f)) error$invalidArgument('Future.encase3', 0, 'take at least three arguments', f); | ||
if(!isTernary(f)) error$invalidArgument('Future.encase3', 0, 'take three arguments', f); | ||
} | ||
@@ -360,4 +391,4 @@ | ||
function FutureClass(f, guard){ | ||
this._f = guard === true ? Future$guardedFork : Future$rawFork; | ||
function FutureClass(safe, f){ | ||
this._f = safe === true ? Future$safeFork : f; | ||
this._raw = f; | ||
@@ -368,11 +399,47 @@ } | ||
check$Future(f); | ||
return new FutureClass(f, true); | ||
return new FutureClass(true, f); | ||
} | ||
function Future$of(x){ | ||
return new FutureClass(function Future$of$fork(rej, res){ | ||
return new FutureClass(false, function Future$of$fork(rej, res){ | ||
res(x); | ||
return noop; | ||
}); | ||
} | ||
function Future$chainRec(f, init){ | ||
if(arguments.length === 1) return unaryPartial(Future$chainRec, f); | ||
check$chainRec(f); | ||
return new FutureClass(false, function(rej, res){ | ||
let cancel = noop, i = 0; | ||
(function Future$chainRec$recur(state){ | ||
let isSync = null; | ||
function Future$chainRec$res(it){ | ||
check$chainRec$it(it, i); | ||
i = i + 1; | ||
if(isSync === null){ | ||
isSync = true; | ||
state = it; | ||
}else{ | ||
Future$chainRec$recur(it); | ||
} | ||
} | ||
while(!state.done){ | ||
isSync = null; | ||
const m = f(Next, Done, state.value); | ||
check$chainRec$f(m, f, i, state.value); | ||
cancel = m._f(rej, Future$chainRec$res); | ||
if(isSync === true){ | ||
continue; | ||
}else{ | ||
isSync = false; | ||
return; | ||
} | ||
} | ||
res(state.value); | ||
}(Next(init))); | ||
return function Future$chainRec$cancel(){ cancel() }; | ||
}); | ||
} | ||
function Future$fork(rej, res){ | ||
@@ -383,11 +450,5 @@ check$fork(this, rej, res); | ||
function Future$rawFork(rej, res){ | ||
const f = this._raw(rej, res); | ||
check$fork$f(f, this._raw); | ||
return f || noop; | ||
} | ||
function Future$guardedFork(rej, res){ | ||
function Future$safeFork(rej, res){ | ||
let open = true; | ||
const f = this._raw(function Future$guard$rej(x){ | ||
const f = this._raw(function Future$safeFork$rej(x){ | ||
if(open){ | ||
@@ -397,3 +458,3 @@ open = false; | ||
} | ||
}, function Future$guard$res(x){ | ||
}, function Future$safeFork$res(x){ | ||
if(open){ | ||
@@ -405,3 +466,3 @@ open = false; | ||
check$fork$f(f, this._raw); | ||
return function Future$guardedFork$cancel(){ | ||
return function Future$safeFork$cancel(){ | ||
open && f && f(); | ||
@@ -415,3 +476,3 @@ open = false; | ||
const _this = this; | ||
return new FutureClass(function Future$chain$fork(rej, res){ | ||
return new FutureClass(false, function Future$chain$fork(rej, res){ | ||
let cancel; | ||
@@ -430,3 +491,3 @@ const r = _this._f(rej, function Future$chain$res(x){ | ||
const _this = this; | ||
return new FutureClass(function Future$chain$fork(rej, res){ | ||
return new FutureClass(false, function Future$chain$fork(rej, res){ | ||
return _this._f(rej, function Future$chain$res(x){ | ||
@@ -443,3 +504,3 @@ const m = f(x); | ||
const _this = this; | ||
return new FutureClass(function Future$chainRej$fork(rej, res){ | ||
return new FutureClass(false, function Future$chainRej$fork(rej, res){ | ||
let cancel; | ||
@@ -458,3 +519,3 @@ const r = _this._f(function Future$chainRej$rej(x){ | ||
const _this = this; | ||
return new FutureClass(function Future$map$fork(rej, res){ | ||
return new FutureClass(false, function Future$map$fork(rej, res){ | ||
return _this._f(rej, function Future$map$res(x){ | ||
@@ -469,3 +530,3 @@ res(f(x)); | ||
const _this = this; | ||
return new FutureClass(function Future$mapRej$fork(rej, res){ | ||
return new FutureClass(false, function Future$mapRej$fork(rej, res){ | ||
return _this._f(function Future$mapRej$rej(x){ | ||
@@ -480,3 +541,3 @@ rej(f(x)); | ||
const _this = this; | ||
return new FutureClass(function Future$bimap$fork(rej, res){ | ||
return new FutureClass(false, function Future$bimap$fork(rej, res){ | ||
return _this._f(function Future$bimap$rej(x){ | ||
@@ -493,3 +554,3 @@ rej(f(x)); | ||
const _this = this; | ||
return new FutureClass(function Future$ap$fork(g, res){ | ||
return new FutureClass(false, function Future$ap$fork(g, res){ | ||
let _f, _x, ok1, ok2, ko; | ||
@@ -514,3 +575,3 @@ const rej = x => ko || (ko = 1, g(x)); | ||
const _this = this; | ||
return new FutureClass(function Future$swap$fork(rej, res){ | ||
return new FutureClass(false, function Future$swap$fork(rej, res){ | ||
return _this._f(res, rej); | ||
@@ -527,3 +588,3 @@ }); | ||
const _this = this; | ||
return new FutureClass(function Future$race$fork(rej, res){ | ||
return new FutureClass(false, function Future$race$fork(rej, res){ | ||
let settled = false, c1 = noop, c2 = noop; | ||
@@ -540,3 +601,3 @@ const once = f => a => settled || (settled = true, c1(), c2(), f(a)); | ||
const _this = this; | ||
return new FutureClass(function Future$or$fork(rej, res){ | ||
return new FutureClass(false, function Future$or$fork(rej, res){ | ||
let ok = false, ko = false, val, err; | ||
@@ -558,3 +619,3 @@ const c1 = _this._f( | ||
const _this = this; | ||
return new FutureClass(function Future$fold$fork(rej, res){ | ||
return new FutureClass(false, function Future$fold$fork(rej, res){ | ||
return _this._f(e => res(f(e)), x => res(g(x))); | ||
@@ -567,3 +628,3 @@ }); | ||
const _this = this; | ||
return new FutureClass(function Future$hook$fork(rej, res){ | ||
return new FutureClass(false, function Future$hook$fork(rej, res){ | ||
let cancel; | ||
@@ -591,3 +652,3 @@ const ret = _this._f(rej, function Future$hook$res(resource){ | ||
const _this = this; | ||
return new FutureClass(function Future$finally$fork(rej, res){ | ||
return new FutureClass(false, function Future$finally$fork(rej, res){ | ||
let cancel; | ||
@@ -636,3 +697,3 @@ const r = _this._f(function Future$finally$rej(e){ | ||
}; | ||
return new FutureClass(function Future$cache$fork(rej, res){ | ||
return new FutureClass(false, function Future$cache$fork(rej, res){ | ||
let cancel = noop; | ||
@@ -663,2 +724,3 @@ switch(state){ | ||
of: Future$of, | ||
[FL.chainRec]: Future$chainRec, | ||
[FL.chain]: Future$chain, | ||
@@ -689,5 +751,8 @@ chain: Future$chain, | ||
Future[FL.of] = Future.of = Future$of; | ||
Future[FL.chainRec] = Future.chainRec = Future$chainRec; | ||
Future.Future = Future; | ||
Future.util = { | ||
Next, | ||
Done, | ||
isForkable, | ||
@@ -779,4 +844,5 @@ isFuture, | ||
Future.reject = function Future$reject(x){ | ||
return new FutureClass(function Future$reject$fork(rej){ | ||
return new FutureClass(false, function Future$reject$fork(rej){ | ||
rej(x); | ||
return noop; | ||
}); | ||
@@ -788,3 +854,3 @@ }; | ||
check$after(n); | ||
return new FutureClass(function Future$after$fork(rej, res){ | ||
return new FutureClass(false, function Future$after$fork(rej, res){ | ||
const t = setTimeout(res, n, x); | ||
@@ -797,5 +863,5 @@ return function Future$after$cancel(){ clearTimeout(t) }; | ||
check$cast(m); | ||
return new FutureClass(function Future$cast$fork(rej, res){ | ||
return new FutureClass(true, function Future$cast$fork(rej, res){ | ||
m.fork(rej, res); | ||
}, true); | ||
}); | ||
}; | ||
@@ -806,11 +872,7 @@ | ||
if(arguments.length === 1) return unaryPartial(Future.encase, f); | ||
return new FutureClass(function Future$encase$fork(rej, res){ | ||
return new FutureClass(false, function Future$encase$fork(rej, res){ | ||
let r; | ||
try{ | ||
r = f(x); | ||
} | ||
catch(e){ | ||
return void rej(e); | ||
} | ||
try{ r = f(x) }catch(e){ return void rej(e) } | ||
res(r); | ||
return noop; | ||
}); | ||
@@ -823,11 +885,7 @@ }; | ||
if(arguments.length === 2) return binaryPartial(Future.encase2, f, x); | ||
return new FutureClass(function Future$encase2$fork(rej, res){ | ||
return new FutureClass(false, function Future$encase2$fork(rej, res){ | ||
let r; | ||
try{ | ||
r = f(x, y); | ||
} | ||
catch(e){ | ||
return void rej(e); | ||
} | ||
try{ r = f(x, y) }catch(e){ return void rej(e) } | ||
res(r); | ||
return noop; | ||
}); | ||
@@ -841,11 +899,7 @@ }; | ||
if(arguments.length === 3) return ternaryPartial(Future.encase3, f, x, y); | ||
return new FutureClass(function Future$encase3$fork(rej, res){ | ||
return new FutureClass(false, function Future$encase3$fork(rej, res){ | ||
let r; | ||
try{ | ||
r = f(x, y, z); | ||
} | ||
catch(e){ | ||
return void rej(e); | ||
} | ||
try{ r = f(x, y, z) }catch(e){ return void rej(e) } | ||
res(r); | ||
return noop; | ||
}); | ||
@@ -860,7 +914,7 @@ }; | ||
check$node(f); | ||
return new FutureClass(function Future$node$fork(rej, res){ | ||
return new FutureClass(true, function Future$node$fork(rej, res){ | ||
f(function Future$node$done(a, b){ | ||
a ? rej(a) : res(b); | ||
}); | ||
}, true); | ||
}); | ||
}; | ||
@@ -872,3 +926,3 @@ | ||
const l = ms.length; | ||
return l < 1 ? Future$of([]) : new FutureClass(function Future$parallel$fork(rej, res){ | ||
return l < 1 ? Future$of([]) : new FutureClass(false, function Future$parallel$fork(rej, res){ | ||
let ko = false; | ||
@@ -890,11 +944,10 @@ let ok = 0; | ||
check$do(f); | ||
return new FutureClass(function Future$do$fork(rej, res){ | ||
return new FutureClass(false, function Future$do$fork(rej, res){ | ||
const g = f(); | ||
check$do$g(g); | ||
const next = function Future$do$next(x){ | ||
return Future$chainRec(function Future$do$next(next, _, x){ | ||
const o = g.next(x); | ||
check$do$next(o); | ||
return o.done ? Future$of(o.value) : o.value.chain(Future$do$next); | ||
}; | ||
return next()._f(rej, res); | ||
return o.done ? Future$of(o) : o.value.map(next); | ||
}, undefined)._f(rej, res); | ||
}); | ||
@@ -901,0 +954,0 @@ }; |
{ | ||
"name": "fluture", | ||
"version": "3.0.0", | ||
"version": "3.1.0", | ||
"description": "FantasyLand compliant (monadic) alternative to Promises", | ||
@@ -62,3 +62,3 @@ "main": "fluture.js", | ||
"fantasy-land": "^1.0.1", | ||
"fun-task": "^1.1.1", | ||
"fun-task": "^1.5.1", | ||
"istanbul": "^0.4.2", | ||
@@ -72,3 +72,3 @@ "jsverify": "^0.7.1", | ||
"ramda": "^0.22.1", | ||
"ramda-fantasy": "^0.6.0", | ||
"ramda-fantasy": "^0.7.0", | ||
"rimraf": "^2.4.3", | ||
@@ -75,0 +75,0 @@ "sanctuary": "^0.11.1" |
@@ -65,2 +65,3 @@ # Fluture | ||
* [node](#node) | ||
* [chainRec](#chainrec) | ||
1. [Transforming Futures](#transforming-futures) | ||
@@ -103,3 +104,3 @@ * [map](#map) | ||
Fluture implements [FantasyLand 1.x][1] and [Static Land][25] compatible | ||
`Functor`, `Bifunctor`, `Apply`, `Applicative`, `Chain` and `Monad`. | ||
`Functor`, `Bifunctor`, `Apply`, `Applicative`, `Chain`, `ChainRec` and `Monad`. | ||
@@ -124,3 +125,6 @@ ## Documentation | ||
- **Apply** - Values which conform to the [Fantasy Land Apply specification][14]. | ||
- **Iterator** - Values which conform to the [Iterator protocol][18]. | ||
- **Iterator** - Objects with `next`-methods which conform to the [Iterator protocol][18]. | ||
- **Iteration** - `{done, value}`-Objects as defined by the [Iterator protocol][18]. | ||
- **Next** - An incomplete (`{done: false}`) Iteration. | ||
- **Done** - A complete (`{done: true}`) Iteration. | ||
- **Cancel** - The nullary cancellation functions returned from computations. | ||
@@ -257,2 +261,22 @@ | ||
#### chainRec | ||
##### `.chainRec :: ((b -> Next, c -> Done, b) -> Future a Iteration) -> b -> Future a c` | ||
Stack- and memory-safe asynchronous "recursion" based on [FantasyLand ChainRec][26]. | ||
Calls the given function with the initial value (as third argument), and expects | ||
a Future of an [Iteration](#type-signatures). If the Iteration is incomplete | ||
(`{done: false}`), then the function is called again with the Iteration value | ||
until it returns a Future of a complete (`{done: true}`) Iteration. | ||
For convenience and interoperability, the first two arguments passed to the | ||
function are functions for creating an incomplete Iteration, and for creating a | ||
complete Iteration, respectively. | ||
```js | ||
Future.chainRec((next, done, x) => Future.of(x < 1000000 ? next(x + 1) : done(x)), 0) | ||
.fork(console.error, console.log); | ||
//> 1000000 | ||
``` | ||
### Transforming Futures | ||
@@ -817,1 +841,2 @@ | ||
[25]: https://github.com/rpominov/static-land | ||
[26]: https://github.com/fantasyland/fantasy-land#chainrec |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
58654
809
838