diff --git a/README.md b/README.md
index a9f3ff30..166400e7 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,5 @@
# Fluture
-[
][1]
-
[](https://www.npmjs.com/package/fluture)
[](https://david-dm.org/avaq/fluture)
[](https://travis-ci.org/Avaq/Fluture)
@@ -51,6 +49,7 @@ getPackageName('package.json')
## Table of contents
- [Usage](#usage)
+- [Interoperability](#interoperability)
- [Documentation](#documentation)
1. [Type signatures](#type-signatures)
1. [Creating Futures](#creating-futures)
@@ -93,6 +92,13 @@ getPackageName('package.json')
- [Benchmarks](#benchmarks)
- [The name](#the-name)
+## Interoperability
+
+[
][1]
+
+Fluture implements [FantasyLand 1.x][1] compatible `Functor`, `Bifunctor`,
+`Apply`, `Applicative`, `Chain` and `Monad`.
+
## Documentation
### Type signatures
@@ -314,18 +320,17 @@ process.on('SIGINT', cancel);
```
#### ap
-##### `#ap :: Future a (b -> c) ~> Future a b -> Future a c`
+##### `#ap :: Future a b ~> Future a (b -> c) -> Future a c`
##### `.ap :: Apply m => m (a -> b) -> m a -> m b`
-Apply the resolution value, which is expected to be a function (as in
-`Future.of(a_function)`), to the resolution value in the given Future. Both
-Futures involved will run in parallel, and if one rejects the resulting Future
-will also be rejected. To learn more about the exact behaviour of `ap`, check
-out its [spec][14].
+Applies the function contained in the right-hand Future to the value contained
+in the left-hand Future. Both Futures involved will run in parallel, and if one
+rejects the resulting Future will also be rejected. To learn more about the
+exact behaviour of `ap`, check out its [spec][14].
```js
-Future.of(x => x + 1)
-.ap(Future.of(1))
+Future.of(1)
+.ap(Future.of(x => x + 1))
.fork(console.error, console.log);
//> 2
```
diff --git a/fluture.js b/fluture.js
index 30522fa4..0f3c24b5 100644
--- a/fluture.js
+++ b/fluture.js
@@ -28,11 +28,11 @@
const TYPEOF_FUTURE = 'fluture/Future';
const FL = {
- map: 'map',
- bimap: 'bimap',
- chain: 'chain',
- ap: 'ap',
- of: 'of'
+ map: 'fantasy-land/map',
+ bimap: 'fantasy-land/bimap',
+ chain: 'fantasy-land/chain',
+ ap: 'fantasy-land/ap',
+ of: 'fantasy-land/of'
};
function isForkable(m){
@@ -222,7 +222,8 @@
function check$ap$f(f){
if(!isFunction(f)) throw new TypeError(
- `Future#ap can only be used on Future but was used on a Future of: ${show(f)}`
+ 'Future#ap expects its first argument to be a Future of a Function'
+ + `\n Actual: Future.of(${show(f)})`
);
}
@@ -317,8 +318,8 @@
function check$parallel$m(m, i){
if(!isFuture(m)) throw new TypeError(
- 'Future.parallel expects argument 1 to be an array of Futures.'
- + ` The value at position ${i} in the array was not a Future.\n Actual: ${show(m)}`
+ 'Future.parallel expects its second argument to be an array of Futures.'
+ + ` The value at position ${i} in the array was not a Future\n Actual: ${show(m)}`
);
}
@@ -474,16 +475,16 @@
return new FutureClass(function Future$ap$fork(g, res){
let _f, _x, ok1, ok2, ko;
const rej = x => ko || (ko = 1, g(x));
- const c1 = _this._f(rej, function Future$ap$resThis(f){
- if(!ok2) return void (ok1 = 1, _f = f);
- check$ap$f(f);
- res(f(_x));
- });
- const c2 = m._f(rej, function Future$ap$resThat(x){
+ const c1 = _this._f(rej, function Future$ap$resThis(x){
if(!ok1) return void (ok2 = 1, _x = x)
check$ap$f(_f);
res(_f(x));
});
+ const c2 = m._f(rej, function Future$ap$resThat(f){
+ if(!ok2) return void (ok1 = 1, _f = f);
+ check$ap$f(f);
+ res(f(_x));
+ });
return function Future$ap$cancel(){ c1(); c2() };
});
}
@@ -701,15 +702,6 @@
};
}
- //Creates a dispatcher for a unary method, but takes the object first rather than last.
- function createInvertedUnaryDispatcher(method){
- return function invertedUnaryDispatch(m, a){
- if(arguments.length === 1) return unaryPartial(invertedUnaryDispatch, m);
- if(m && typeof m[method] === 'function') return m[method](a);
- error$invalidArgument(`Future.${method}`, 0, `have a "${method}" method`, m);
- };
- }
-
//Creates a dispatcher for a binary method.
function createBinaryDispatcher(method){
return function binaryDispatch(a, b, m){
@@ -730,13 +722,13 @@
};
}
- Future.chain = createUnaryDispatcher('chain');
+ Future.chain = createUnaryDispatcher(FL.chain);
Future.recur = createUnaryDispatcher('recur');
Future.chainRej = createUnaryDispatcher('chainRej');
- Future.map = createUnaryDispatcher('map');
+ Future.map = createUnaryDispatcher(FL.map);
Future.mapRej = createUnaryDispatcher('mapRej');
- Future.bimap = createBinaryDispatcher('bimap');
- Future.ap = createInvertedUnaryDispatcher('ap');
+ Future.bimap = createBinaryDispatcher(FL.bimap);
+ Future.ap = createUnaryDispatcher(FL.ap);
Future.swap = createNullaryDispatcher('swap');
Future.fork = createBinaryDispatcher('fork');
Future.race = createUnaryDispatcher('race');
diff --git a/package.json b/package.json
index 0716e14d..14ee53fd 100644
--- a/package.json
+++ b/package.json
@@ -58,6 +58,7 @@
"codecov": "^1.0.1",
"data.task": "^3.0.0",
"eslint": "^3.0.1",
+ "fantasy-land": "^1.0.1",
"fun-task": "^1.1.1",
"istanbul": "^0.4.2",
"jsverify": "^0.7.1",
diff --git a/test/fluture.test.js b/test/fluture.test.js
index 5eccaf82..f29ec99e 100644
--- a/test/fluture.test.js
+++ b/test/fluture.test.js
@@ -5,13 +5,7 @@ const Future = require('../fluture');
const Readable = require('stream').Readable;
const jsc = require('jsverify');
const S = require('sanctuary');
-const FL = {
- map: 'map',
- bimap: 'bimap',
- chain: 'chain',
- ap: 'ap',
- of: 'of'
-};
+const FL = require('fantasy-land');
const noop = () => {};
const add = a => b => a + b;
@@ -726,14 +720,14 @@ describe('Future', () => {
fs.forEach(f => expect(f).to.throw(TypeError, /Future/));
});
- it('throws TypeError when not not called on Future', () => {
+ it('throws TypeError when not not called with Future', () => {
const xs = [NaN, {}, [], 1, 'a', new Date, undefined, null];
- const fs = xs.map(x => () => Future.of(x).ap(Future.of(1)).fork(noop, noop));
+ const fs = xs.map(x => () => Future.of(1).ap(Future.of(x)).fork(noop, noop));
fs.forEach(f => expect(f).to.throw(TypeError, /Future/));
});
- it('applies its inner to the inner of the other', () => {
- const actual = Future.of(add(1)).ap(Future.of(1));
+ it('calls the function contained in the given Future to its contained value', () => {
+ const actual = Future.of(1).ap(Future.of(add(1)));
return assertResolved(actual, 2);
});
@@ -747,19 +741,19 @@ describe('Future', () => {
});
it('does not matter if the left resolves late', () => {
- const actual = Future.after(20, add(1)).ap(Future.of(1));
+ const actual = Future.after(20, 1).ap(Future.of(add(1)));
return assertResolved(actual, 2);
});
it('does not matter if the right resolves late', () => {
- const actual = Future.of(add(1)).ap(Future.after(20, 1));
+ const actual = Future.of(1).ap(Future.after(20, add(1)));
return assertResolved(actual, 2);
});
it('forks in parallel', function(){
this.slow(80);
this.timeout(50);
- const actual = Future.after(30, add(1)).ap(Future.after(30, 1));
+ const actual = Future.after(30, 1).ap(Future.after(30, add(1)));
return assertResolved(actual, 2);
});
@@ -1283,6 +1277,7 @@ describe('Fantasy-Land Compliance', function(){
const of = Future[FL.of];
const I = x => x;
+ const T = x => f => f(x);
const B = f => g => x => f(g(x));
const sub3 = x => x - 3;
@@ -1312,23 +1307,23 @@ describe('Fantasy-Land Compliance', function(){
describe('Apply', () => {
test('composition', x => eq(
- of(sub3)[FL.map](B)[FL.ap](of(mul3))[FL.ap](of(x)),
- of(sub3)[FL.ap](of(mul3)[FL.ap](of(x)))
+ of(x)[FL.ap](of(sub3)[FL.ap](of(mul3)[FL.map](B))),
+ of(x)[FL.ap](of(sub3))[FL.ap](of(mul3))
));
});
describe('Applicative', () => {
test('identity', x => eq(
- of(x),
- of(I)[FL.ap](of(x))
+ of(x)[FL.ap](of(I)),
+ of(x)
));
test('homomorphism', x => eq(
- of(sub3(x)),
- of(sub3)[FL.ap](of(x))
+ of(x)[FL.ap](of(sub3)),
+ of(sub3(x))
));
test('interchange', x => eq(
- of(sub3)[FL.ap](of(x)),
- of(f => f(x))[FL.ap](of(sub3))
+ of(x)[FL.ap](of(sub3)),
+ of(sub3)[FL.ap](of(T(x)))
));
});