Comparing version 0.6.5 to 1.0.0
145
fluture.js
@@ -0,1 +1,9 @@ | ||
//// ____ _ _ | ||
//// / ___| | | |_ | ||
//// | |__ | | _ _ | _\ _ ___ ___ | ||
//// | __|| || | | || || | | || _// _ \ | ||
//// | | | || |_| || || |_| || | | __/ | ||
//// |_| |_| \__,_||_| \__,_||_| \___\ | ||
//// | ||
/*global define FantasyLand inspectf*/ | ||
@@ -27,2 +35,4 @@ (function(global, f){ | ||
const TYPEOF_FUTURE = 'fluture/Future'; | ||
function isForkable(m){ | ||
@@ -33,3 +43,3 @@ return Boolean(m) && typeof m.fork === 'function' && m.fork.length >= 2; | ||
function isFuture(m){ | ||
return m instanceof FutureClass; | ||
return (m instanceof FutureClass) || Boolean(m) && m['@@type'] === TYPEOF_FUTURE; | ||
} | ||
@@ -53,2 +63,14 @@ | ||
function isObject(x){ | ||
return typeof x === 'object' && x !== null; | ||
} | ||
function isIterator(i){ | ||
return isObject(i) && typeof i.next === 'function'; | ||
} | ||
function isIteration(o){ | ||
return isObject(o) && 'value' in o && 'done' in o && typeof o.done === 'boolean'; | ||
} | ||
/////////////// | ||
@@ -174,2 +196,13 @@ // Utilities // | ||
function check$mapRej(it, f){ | ||
if(!isFuture(it)) error$invalidContext('Future#mapRej', it); | ||
if(!isFunction(f)) error$invalidArgument('Future#mapRej', 0, 'be a function', f); | ||
} | ||
function check$bimap(it, f, g){ | ||
if(!isFuture(it)) error$invalidContext('Future#bimap', it); | ||
if(!isFunction(f)) error$invalidArgument('Future#bimap', 0, 'be a function', f); | ||
if(!isFunction(g)) error$invalidArgument('Future#bimap', 1, 'be a function', g); | ||
} | ||
function check$ap(it, m){ | ||
@@ -180,3 +213,2 @@ if(!isFuture(it)) error$invalidContext('Future#ap', it); | ||
//Check resolution value of the Future on which #ap was called. | ||
function check$ap$f(f){ | ||
@@ -265,2 +297,25 @@ if(!isFunction(f)) throw new TypeError( | ||
function check$do(f){ | ||
if(!isFunction(f)) error$invalidArgument('Future.do', 0, 'be a function', f); | ||
} | ||
function check$do$g(g){ | ||
if(!isIterator(g)) error$invalidArgument( | ||
'Future.do', 0, 'return an iterator, maybe you forgot the "*"', g | ||
); | ||
} | ||
function check$do$next(o){ | ||
if(!isIteration(o)) throw new TypeError( | ||
'Future.do was given an invalid generator:' | ||
+ ' Its iterator did not return a valid iteration from iterator.next()' | ||
+ `\n Actual: ${show(o)}` | ||
); | ||
if(!o.done && !isFuture(o.value)) throw new TypeError( | ||
'A non-Future was produced by iterator.next() in Future.do.' | ||
+ ' If you\'re using a generator, make sure you always `yield` a Future' | ||
+ `\n Actual: ${o.value}` | ||
); | ||
} | ||
//////////// | ||
@@ -270,3 +325,2 @@ // Future // | ||
//Constructor. | ||
function FutureClass(f){ | ||
@@ -276,3 +330,2 @@ this._f = f; | ||
//A createFuture function which pretends to be Future. | ||
function Future(f){ | ||
@@ -283,3 +336,2 @@ check$Future(f); | ||
//The of method. | ||
function Future$of(x){ | ||
@@ -330,2 +382,24 @@ return new FutureClass(function Future$of$fork(rej, res){ | ||
function Future$mapRej(f){ | ||
check$mapRej(this, f); | ||
const _this = this; | ||
return new FutureClass(function Future$mapRej$fork(rej, res){ | ||
_this._f(function Future$mapRej$rej(x){ | ||
rej(f(x)); | ||
}, res); | ||
}); | ||
} | ||
function Future$bimap(f, g){ | ||
check$bimap(this, f, g); | ||
const _this = this; | ||
return new FutureClass(function Future$bimap$fork(rej, res){ | ||
_this._f(function Future$bimap$rej(x){ | ||
rej(f(x)); | ||
}, function Future$bimap$res(x){ | ||
res(g(x)); | ||
}); | ||
}); | ||
} | ||
function Future$ap(m){ | ||
@@ -436,5 +510,4 @@ check$ap(this, m); | ||
//Give Future a prototype. | ||
FutureClass.prototype = Future.prototype = { | ||
'@@type': 'fluture/Future', | ||
'@@type': TYPEOF_FUTURE, | ||
_f: null, | ||
@@ -449,2 +522,4 @@ fork: Future$fork, | ||
map: Future$map, | ||
mapRej: Future$mapRej, | ||
bimap: Future$bimap, | ||
[FL.ap]: Future$ap, | ||
@@ -462,9 +537,5 @@ ap: Future$ap, | ||
//Expose `of` statically as well. | ||
Future[FL.of] = Future.of = Future$of; | ||
//Expose Future statically for ease of destructuring. | ||
Future.Future = Future; | ||
//Expose utilities, mainly for unit testing. | ||
Future.util = { | ||
@@ -477,2 +548,5 @@ isForkable, | ||
isPositiveInteger, | ||
isObject, | ||
isIterator, | ||
isIteration, | ||
preview, | ||
@@ -540,33 +614,14 @@ show, | ||
//chain :: Chain m => (a -> m b) -> m a -> m b | ||
Future.chain = createUnaryDispatcher('chain'); | ||
//chainRej :: (a -> Future a c) -> Future a b -> Future a c | ||
Future.chainRej = createUnaryDispatcher('chainRej'); | ||
//map :: Functor m => (a -> b) -> m a -> m b | ||
Future.map = createUnaryDispatcher('map'); | ||
//ap :: Apply m => m (a -> b) -> m a -> m b | ||
Future.mapRej = createUnaryDispatcher('mapRej'); | ||
Future.bimap = createBinaryDispatcher('bimap'); | ||
Future.ap = createInvertedUnaryDispatcher('ap'); | ||
//fork :: (a -> Void) -> (b -> Void) -> Future a b -> Void | ||
Future.fork = createBinaryDispatcher('fork'); | ||
//race :: Future a b -> Future a b -> Future a b | ||
Future.race = createUnaryDispatcher('race'); | ||
//or :: Future a b -> Future a b -> Future a b | ||
Future.or = createUnaryDispatcher('or'); | ||
//fold :: (a -> c) -> (b -> c) -> Future a b -> Future _ c | ||
Future.fold = createBinaryDispatcher('fold'); | ||
//value :: (b -> Void) -> Future a b -> Void | ||
Future.value = createUnaryDispatcher('value'); | ||
//promise :: Future a b -> Promise b a | ||
Future.promise = createNullaryDispatcher('promise'); | ||
//cache :: Future a b -> Future a b | ||
Future.cache = createNullaryDispatcher('cache'); | ||
@@ -578,7 +633,5 @@ | ||
//Type checks. | ||
Future.isFuture = isFuture; | ||
Future.isForkable = isForkable; | ||
//Create a Future which rejects witth the given value. | ||
Future.reject = function Future$reject(x){ | ||
@@ -590,3 +643,2 @@ return new FutureClass(function Future$reject$fork(rej){ | ||
//Create a Future which resolves after the given time with the given value. | ||
Future.after = function Future$after(n, x){ | ||
@@ -602,5 +654,2 @@ if(arguments.length === 1) return unaryPartial(Future.after, n); | ||
check$cast(m); | ||
if(m instanceof FutureClass){ | ||
return m; | ||
} | ||
return new FutureClass(function Future$cast$fork(rej, res){ | ||
@@ -611,3 +660,2 @@ m.fork(rej, res); | ||
//encase :: (a -> !e | r) -> a -> Future e r | ||
Future.encase = function Future$encase(f, x){ | ||
@@ -628,3 +676,2 @@ check$encase(f); | ||
//encase2 :: (a, b -> !e | r) -> a -> b -> Future e r | ||
Future.encase2 = function Future$encase2(f, x, y){ | ||
@@ -646,3 +693,2 @@ check$encase2(f); | ||
//encase3 :: (a, b, c -> !e | r) -> a -> b -> c -> Future e r | ||
Future.encase3 = function Future$encase3(f, x, y, z){ | ||
@@ -665,4 +711,2 @@ check$encase3(f); | ||
//Create a Future which resolves with the return value of the given function, | ||
//or rejects with the exception thrown by the given function. | ||
Future.try = function Future$try(f){ | ||
@@ -672,3 +716,2 @@ return Future.encase(f, undefined); | ||
//node :: ((err, a) -> Void) -> Future[Error, a] | ||
Future.node = function Future$node(f){ | ||
@@ -681,3 +724,2 @@ check$node(f); | ||
//parallel :: PositiveInteger -> [Future a b] -> Future a [b] | ||
Future.parallel = function Future$parallel(i, ms){ | ||
@@ -700,5 +742,16 @@ if(arguments.length === 1) return unaryPartial(Future.parallel, i); | ||
//Export Future factory. | ||
Future.do = function Future$do(f){ | ||
check$do(f); | ||
const g = f(); | ||
check$do$g(g); | ||
const next = function Future$do$next(x){ | ||
const o = g.next(x); | ||
check$do$next(o); | ||
return o.done ? Future$of(o.value) : o.value.chain(next); | ||
}; | ||
return next(); | ||
}; | ||
return Future; | ||
})); |
{ | ||
"name": "fluture", | ||
"version": "0.6.5", | ||
"version": "1.0.0", | ||
"description": "A mathematically correct alternative to Promises for asynchronous control flow", | ||
@@ -5,0 +5,0 @@ "main": "fluture.js", |
@@ -93,2 +93,3 @@ # Fluture | ||
[Fantasy Land Apply specification][14]. | ||
- **Iterator** - Any object which conforms to the [Iterator protocol][18]. | ||
@@ -206,3 +207,3 @@ ### Creation | ||
#### `parallel :: PositiveInteger -> [Future a b] -> Future a [b]` | ||
#### `parallel :: PositiveInteger -> Array (Future a b) -> Future a (Array b)` | ||
@@ -290,2 +291,32 @@ Creates a Future which when forked runs all Futures in the given `array` in | ||
#### `mapRej :: Future a b ~> (a -> c) -> Future c b` | ||
Map over the **rejection** reason of the Future. This is like `map`, but for the | ||
rejection branch. | ||
```js | ||
Future.reject(new Error('It broke!')).mapRej(err => { | ||
return new Error('Some extra info: ' + err.message); | ||
}) | ||
.fork(console.error, console.log) | ||
//! [Some extra info: It broke!] | ||
``` | ||
#### `bimap :: Future a b ~> (a -> c) -> (b -> d) -> Future c d` | ||
Maps the left function over the rejection value, or the right function over the | ||
resolution value, depending on which is present. | ||
```js | ||
Future.of(1) | ||
.bimap(x => x + !, x => x + 1) | ||
.fork(console.error, console.log); | ||
//> 2 | ||
Future.reject('error') | ||
.bimap(x => x + !, x => x + 1) | ||
.fork(console.error, console.log); | ||
//> "error!" | ||
``` | ||
#### `chain :: Future a b ~> (b -> Future a c) -> Future a c` | ||
@@ -456,2 +487,10 @@ | ||
#### `mapRej :: (a -> b) -> Future a c -> Future b c` | ||
Dispatches the first argument to the `mapRej` method of the second argument. | ||
#### `bimap :: Bifunctor m => (a -> b) -> (c -> d) -> m a c -> m b d` | ||
Dispatches the first two arguments to the `bimap` method of the third argument. | ||
#### `chain :: Chain m => (a -> m b) -> m a -> m b` | ||
@@ -522,7 +561,17 @@ | ||
Returns true for [Futures](#type-signatures) and false for everything else. | ||
Returns true for [Futures](#type-signatures) and false for everything else. This | ||
function (and [`S.is`][17]) also return `true` for instances of Future that were | ||
created within other contexts. It is therefore recommended to use this over | ||
`instanceof`, unless your intent is to explicitly check for Futures created | ||
using the exact `Future` constructor you're testing against. | ||
```js | ||
const m = Future(rej => rej()); | ||
Future.isFuture(m) === (m instanceof Future) === S.is(Future, m); | ||
const Future1 = require('/path/to/fluture'); | ||
const Future2 = require('/other/path/to/fluture'); | ||
const m1 = Future1(noop); | ||
Future1.isFuture(m1) === (m1 instanceof Future1); | ||
const m2 = Future2(noop); | ||
Future1.isFuture(m2) !== (m2 instanceof Future1); | ||
``` | ||
@@ -534,2 +583,25 @@ | ||
#### `do :: (() -> Iterator) -> Future a b` | ||
A specialized version of [fantasy-do][19] which works only for Futures, but has | ||
the advantage of type-checking and not having to pass `Future.of`. | ||
Takes a function which returns an [Iterator][#type-signatures], commonly a | ||
generator-function, and chains every produced Future over the previous. | ||
This allows for writing sequential asynchronous code without the pyramid of | ||
doom. It's known as "coroutines" in Promise land, and "do-notation" in Haskell | ||
land. | ||
```js | ||
Future.do(function*(){ | ||
const thing = yield Future.after(300, 'world'); | ||
const message = yield Future.after(300, 'Hello ' + thing); | ||
return message + '!'; | ||
}) | ||
.fork(console.error, console.log) | ||
//After 600ms: | ||
//> "Hello world!" | ||
``` | ||
### Futurization | ||
@@ -586,1 +658,4 @@ | ||
[16]: https://github.com/fantasyland/fantasy-land#applicative | ||
[17]: http://sanctuary.js.org/#is | ||
[18]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterator | ||
[19]: https://github.com/russellmcc/fantasydo |
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
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
45425
634
0
655