exalted.future
Advanced tools
Comparing version 0.0.15 to 0.0.16
@@ -0,1 +1,27 @@ | ||
var compose = function compose() { | ||
for (var _len = arguments.length, rest = new Array(_len), _key = 0; _key < _len; _key++) { | ||
rest[_key] = arguments[_key]; | ||
} | ||
return function () { | ||
var _rest$slice; | ||
return rest.slice(0, rest.length - 1).reduceRight(function (acc, func) { | ||
return func(acc); | ||
}, (_rest$slice = rest.slice(rest.length - 1))[0].apply(_rest$slice, arguments)); | ||
}; | ||
}; | ||
var map = function map() { | ||
for (var _len2 = arguments.length, functions = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
functions[_key2] = arguments[_key2]; | ||
} | ||
return function (functor) { | ||
return functions.reduceRight(function (functor, f) { | ||
return functor.map(f); | ||
}, functor); | ||
}; | ||
}; | ||
var id = function id(a) { | ||
@@ -28,28 +54,2 @@ return a; | ||
var compose = function compose() { | ||
for (var _len = arguments.length, rest = new Array(_len), _key = 0; _key < _len; _key++) { | ||
rest[_key] = arguments[_key]; | ||
} | ||
return function () { | ||
var _rest$slice; | ||
return rest.slice(0, rest.length - 1).reduceRight(function (acc, func) { | ||
return func(acc); | ||
}, (_rest$slice = rest.slice(rest.length - 1))[0].apply(_rest$slice, arguments)); | ||
}; | ||
}; | ||
var map = function map() { | ||
for (var _len2 = arguments.length, functions = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { | ||
functions[_key2] = arguments[_key2]; | ||
} | ||
return function (functor) { | ||
return functions.reduceRight(function (functor, f) { | ||
return functor.map(f); | ||
}, functor); | ||
}; | ||
}; | ||
var eq = function eq(a, r) { | ||
@@ -73,2 +73,5 @@ return r.cata({ | ||
}, | ||
alt: function alt() { | ||
return Right(a); | ||
}, | ||
bimap: function bimap(_, r) { | ||
@@ -121,2 +124,5 @@ return iff(r, a); | ||
}, | ||
alt: function alt() { | ||
return Left(a); | ||
}, | ||
bimap: function bimap(l, _) { | ||
@@ -211,2 +217,11 @@ return iff(l, a); | ||
return { | ||
ap: function ap() { | ||
return Future(action); | ||
}, | ||
alt: function alt() { | ||
return Future(action); | ||
}, | ||
bimap: function bimap() { | ||
return Future(action); | ||
}, | ||
map: function map(func) { | ||
@@ -217,5 +232,26 @@ return chain(action)(function (x) { | ||
}, | ||
chain: chain(action), | ||
cata: function cata(f) { | ||
return action(f.Left, f.Right); | ||
}, | ||
chain: chain(action), | ||
equals: function equals() { | ||
return false; | ||
}, | ||
fold: function fold(f) { | ||
return action(f, f); | ||
}, | ||
foldl: function foldl(f) { | ||
return action(f, id); | ||
}, | ||
foldr: function foldr(f) { | ||
return action(id, f); | ||
}, | ||
inspect: function inspect() { | ||
return 'Future(?)'; | ||
}, | ||
of: function of(a) { | ||
return Future.of(a); | ||
}, | ||
swap: function swap() { | ||
return Future(action); | ||
} | ||
@@ -227,5 +263,6 @@ }; | ||
try { | ||
var a = f(); | ||
var _a = f(); | ||
return Future(function (_, r) { | ||
return r(a); | ||
return r(_a); | ||
}); | ||
@@ -247,3 +284,3 @@ } catch (e) { | ||
return Future(function (reject, resolve) { | ||
return Future.promise(promise.then(resolve, reject)); | ||
return Future.promise(promise.then(resolve, reject)["catch"](reject)); | ||
}); | ||
@@ -283,2 +320,5 @@ }; | ||
}, | ||
alt: function alt() { | ||
return Id(a); | ||
}, | ||
bimap: function bimap(_, r) { | ||
@@ -318,2 +358,5 @@ return iff(r, a); | ||
return 'Id(' + a + ')'; | ||
}, | ||
swap: function swap() { | ||
return Id(a); | ||
} | ||
@@ -363,2 +406,5 @@ }; | ||
return Maybe(a); | ||
}, | ||
swap: function swap() { | ||
return Just(a); | ||
} | ||
@@ -414,2 +460,5 @@ }; | ||
return Maybe(a); | ||
}, | ||
swap: function swap() { | ||
return Nothing(); | ||
} | ||
@@ -416,0 +465,0 @@ }; |
@@ -7,2 +7,10 @@ (function (global, factory) { | ||
const compose = (...rest) => (...a) => | ||
rest | ||
.slice(0, rest.length - 1) | ||
.reduceRight((acc, func) => func(acc), rest.slice(rest.length - 1)[0](...a)); | ||
const map = (...functions) => functor => | ||
functions.reduceRight((functor, f) => functor.map(f), functor); | ||
const id = a => a; | ||
@@ -20,10 +28,2 @@ | ||
const compose = (...rest) => (...a) => | ||
rest | ||
.slice(0, rest.length - 1) | ||
.reduceRight((acc, func) => func(acc), rest.slice(rest.length - 1)[0](...a)); | ||
const map = (...functions) => functor => | ||
functions.reduceRight((functor, f) => functor.map(f), functor); | ||
const eq = (a, r) => r.cata({ Right: b => a === b, Left: b => a === b }); | ||
@@ -33,2 +33,3 @@ | ||
ap: app => (app.isLeft ? app : app.map(b => iff(b, a))), | ||
alt: () => Right(a), | ||
bimap: (_, r) => iff(r, a), | ||
@@ -52,2 +53,3 @@ cata: (f = Identity) => f.Right(a), | ||
ap: app => (app.isLeft ? app : Left(a)), | ||
alt: () => Left(a), | ||
bimap: (l, _) => iff(l, a), | ||
@@ -99,5 +101,15 @@ cata: (f = Identity) => f.Left(a), | ||
const Future = action => ({ | ||
ap: () => Future(action), | ||
alt: () => Future(action), | ||
bimap: () => Future(action), | ||
map: func => chain(action)(x => Future.of(func(x))), | ||
cata: f => action(f.Left, f.Right), | ||
chain: chain(action), | ||
cata: f => action(f.Left, f.Right) | ||
equals: () => false, | ||
fold: f => action(f, f), | ||
foldl: f => action(f, id), | ||
foldr: f => action(id, f), | ||
inspect: () => 'Future(?)', | ||
of: a => Future.of(a), | ||
swap: () => Future(action) | ||
}); | ||
@@ -117,3 +129,3 @@ | ||
Future.promise = promise => | ||
Future((reject, resolve) => Future.promise(promise.then(resolve, reject))); | ||
Future((reject, resolve) => Future.promise(promise.then(resolve, reject).catch(reject))); | ||
@@ -141,2 +153,3 @@ const all = futures => | ||
ap: app => app.map(f => iff(f, a)), | ||
alt: () => Id(a), | ||
bimap: (_, r) => iff(r, a), | ||
@@ -151,3 +164,4 @@ cata: (f = Identity$1) => f.Right(a), | ||
of: a => Id(a), | ||
inspect: () => 'Id(' + a + ')' | ||
inspect: () => 'Id(' + a + ')', | ||
swap: () => Id(a) | ||
}); | ||
@@ -169,3 +183,4 @@ | ||
map: () => Nothing(), | ||
of: a => Maybe(a) | ||
of: a => Maybe(a), | ||
swap: () => Just(a) | ||
}); | ||
@@ -187,3 +202,4 @@ | ||
map: f => Maybe(iff(f, a)), | ||
of: a => Maybe(a) | ||
of: a => Maybe(a), | ||
swap: () => Nothing() | ||
}); | ||
@@ -190,0 +206,0 @@ |
{ | ||
"name": "exalted.future", | ||
"version": "0.0.15", | ||
"version": "0.0.16", | ||
"description": "Exalted monadic library & functional fun, fantasy-land compliant, mostly.", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/pre63/exalted.future.git", |
415
README.md
![](https://badgen.net/bundlephobia/minzip/exalted.future) | ||
![](https://badgen.net/bundlephobia/tree-shaking/exalted.future) | ||
![](https://badgen.net/bundlephobia/dependency-count/exalted.future) | ||
![](https://badgen.net/travis/exalted.future) | ||
*Experimental The api can change between versions.* | ||
# exalted.future | ||
## *Experimental* | ||
A javascript and typescript monadic library & functional fun. [fantasy-land](https://github.com/fantasyland/fantasy-land) compliant, mostly. | ||
The style of monad object is inspired by [DrBoolean](https://github.com/DrBoolean) course on [egghead.io](https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript). | ||
The style of monad object is inspired by [DrBoolean](https://github.com/DrBoolean) course on [egghead.io](https://egghead.io/courses/professor-frisby-introduces-composable-functional-javascript) and his book [Mostly adequate guide to FP](https://github.com/MostlyAdequate/mostly-adequate-guide). | ||
@@ -17,2 +17,17 @@ The choice for `cata`, `encase`, `head`, `tail`, `last` is inspired by rametta's take on monads in [pratica](https://github.com/rametta/pratica). | ||
# Natural Transformation | ||
One of the main goals of the exalted.future is to make it possible to rely on natural transformation when composing Monads. So that you can write in one continuous flow your program, agnostic of the Monad you are working with. That is why `mapReduce`, `reduce`, `fold`, and `fork` use the same language, `cata`. You can always call cata on an object, and it will compute your results. The following example attempts to illustrate that. Regardless that the fetch succeeds or fails the outcome will be the same, indifferent to calling `cata` on Maybe, Either (Left|Right), or Future. | ||
```javascript | ||
Future.promise(fetch('https://jsonplaceholder.typicode.com/todos/1')) | ||
.chain(response => Either.encase(() => response.json())) | ||
.chain(Future.promise) | ||
.chain(Maybe) | ||
.map(todo => todo.title) | ||
.map(t => t.toUpperCase()) | ||
.cata({ | ||
Left: e => console.log('oops', e), | ||
Right: json => console.log(json) | ||
}) | ||
``` | ||
# Install | ||
@@ -36,124 +51,50 @@ ``` bash | ||
* Left is not 100% applicative. | ||
* Not all functions are documented, so you are encouraged to read the source code, you'll find `bimap`, `swap`, `fold`, `foldr`, `foldf`. | ||
## Future | ||
A Future monad for async computation. `Left` is reject and `Right` is resolve. Because `Right` is always right and Left is not. | ||
## All | ||
These functions are available on all types. | ||
### ap | ||
[Apply][8] | ||
``` | ||
chain :: (a -> b) -> b | ||
``` | ||
```javascript | ||
Id(5).chain(a => Id(a)) | ||
//=> Id(5) | ||
// You can use chain to join the monads. | ||
Id(Id(5)).chain(a => a) | ||
//=> Id(5) | ||
``` | ||
### equals | ||
[Setoid][1] | ||
``` | ||
equals :: Id -> Boolean | ||
``` | ||
```javascript | ||
Id(1).equals(Id(1)) | ||
//=> true | ||
Id(2).equals(Id(1)) | ||
//=> false | ||
Id(2).equals(Id(1)) === Id(1).equals(Id(1)) | ||
//=> false | ||
``` | ||
### chain | ||
[Chain][7] | ||
``` | ||
chain :: (a -> b) -> b | ||
``` | ||
```javascript | ||
Id(5).chain(a => Id(a)) | ||
//=> Id(5) | ||
// You can use chain to join the monads. | ||
Id(Id(5)).chain(a => a) | ||
//=> Id(5) | ||
``` | ||
### map | ||
[Functor][3] | ||
``` | ||
map :: (a -> b) -> Id of b | ||
``` | ||
```javascript | ||
Id(7).map(a => a * 2) | ||
//=> Id(14) | ||
``` | ||
### of | ||
[Applicative][4] | ||
``` | ||
of :: a -> Id of a | ||
``` | ||
```javascript | ||
Id(5).of(6) | ||
//=> Id(6) | ||
Id(5).of(Id(6)) | ||
//=> Id(Id(6)) | ||
``` | ||
### fold | ||
[Foldable][6] | ||
``` | ||
fold :: (a -> b) -> b | ||
``` | ||
```javascript | ||
Id(5).fold() | ||
//=> 5 | ||
Id(5).fold() | ||
//=> 6 | ||
``` | ||
### cata | ||
[Foldable][6] | ||
``` | ||
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b | ||
``` | ||
```javascript | ||
Id(5).cata({ | ||
Right: a => a | ||
``` javascript | ||
// Basic usage | ||
Future((err, ok) => ok('Yay')) | ||
.map(res => res.toUpperString()) | ||
.cata({ | ||
Left: err => log(`Err: ${err}`), | ||
Right: res => log(`Res: ${res}`) | ||
}) | ||
//=> 5 | ||
//=> 'YAY' | ||
Id(5).cata({ | ||
Right: a => a + 1 | ||
// Handle promises | ||
Future.promise(fetch('https://api.awesome.com/catOfTheDay')) | ||
.cata({ | ||
Left: err => log('There was an error fetching the cat of the day :('), | ||
Right: cat => log('Cat of the day: ' + cat) | ||
}) | ||
//=> 6 | ||
//=> 'Cat of the day: Garfield' | ||
Right(5).cata({ | ||
Left: a => 8 // ignored | ||
Right: a => a + 1 | ||
// Chain http calls | ||
Future.promise(fetch('https://api.awesome.com/catOfTheDay')) | ||
.chain(cat => Future.promise(fetch(`https://api.catfacts.com/${cat}`))) | ||
.fork({ | ||
Left: err => log('There was an error fetching the cat of the day :('), | ||
Right: facts => log('Facts for cat of the day: ' + facts) | ||
}) | ||
//=> 6 | ||
Left(5).cata({ | ||
Left: a => a + 1 | ||
Right: a => 8 // ignored | ||
}) | ||
//=> 6 | ||
//=> 'Facts for cat of the day: Garfield is awesome.' | ||
``` | ||
### inspect | ||
### Future.all | ||
Concats all the results form the list of futures. | ||
``` | ||
inspect :: () -> String | ||
all :: ([Futures]) -> b | ||
``` | ||
```javascript | ||
Id(5).inspect() | ||
//=> Id(5) | ||
Future.all( | ||
Future.of('apple'), | ||
Future((left, right) => setTimeout(() => right('orange'), 1000)), | ||
Future.of('lemon') | ||
).cata({ | ||
Left: () => (), | ||
Right: ([ apple, orange, lemon ]) => console.log(apple, orange, lemon) | ||
}) //=> apple, orange, lemon | ||
``` | ||
@@ -197,43 +138,2 @@ | ||
### alt | ||
Sets the value to cata on. | ||
``` | ||
alt :: Any -> Nothing of Any | ||
``` | ||
```javascript | ||
Maybe(1).alt(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 1 | ||
Maybe(null).alt(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 5 | ||
``` | ||
### cata | ||
[Foldable][6] | ||
``` | ||
cata :: ({ Left: () -> b, Right: a -> b }) -> a|b | ||
``` | ||
```javascript | ||
Maybe(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 5 | ||
Maybe(5).cata({ | ||
Left: () => { } // not called | ||
Right: a => a + 1 | ||
}) | ||
//=> 6 | ||
Maybe(null).cata({ | ||
Left: () => 'there was a null' | ||
Right: a => a + 1 // not called | ||
}) | ||
//=> there was a null | ||
``` | ||
## Either | ||
@@ -275,90 +175,106 @@ An Either monad and nullable, Left, Right. | ||
### cata | ||
[Foldable][6] - Folds foldable object. | ||
# Functions | ||
The following functions are common to all monads types. | ||
### alt | ||
Sets the value to cata on. | ||
``` | ||
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b | ||
alt :: Any -> Nothing of Any | ||
``` | ||
```javascript | ||
Right(5).cata({ | ||
Left: () => 1, | ||
Right: a => a + 2 | ||
Maybe(1).alt(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 7 | ||
//=> 1 | ||
Left(5).cata(a => a + 1) | ||
//=> 6 | ||
Maybe(null).alt(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 5 | ||
``` | ||
## Future | ||
A Future monad for async computation. | ||
``` javascript | ||
// Basic usage | ||
Future((reject, resolve) => resolve('Yay')) | ||
.map(res => res.toUpperString()) | ||
.fork( | ||
err => log(`Err: ${err}`), | ||
res => log(`Res: ${res}`)) | ||
//=> 'YAY' | ||
// Handle promises | ||
Future.promise(fetch('https://api.awesome.com/catOfTheDay')) | ||
.fork( | ||
err => log('There was an error fetching the cat of the day :('), | ||
cat => log('Cat of the day: ' + cat)) | ||
//=> 'Cat of the day: Garfield' | ||
// Chain http calls | ||
Future.promise(fetch('https://api.awesome.com/catOfTheDay')) | ||
.chain(cat => Future.promise(fetch(`https://api.catfacts.com/${cat}`))) | ||
.fork( | ||
err => log('There was an error fetching the cat of the day :('), | ||
facts => log('Facts for cat of the day: ' + facts)) | ||
//=> 'Facts for cat of the day: Garfield is awesome.' | ||
### ap | ||
[Apply][8] | ||
``` | ||
### all | ||
Forks all the futures. | ||
chain :: (a -> b) -> b | ||
``` | ||
all :: ([Futures]) -> b | ||
``` | ||
```javascript | ||
Future.all( | ||
Future.of('apple'), | ||
Future((left, right) => setTimeout(() => right('orange'), 1000)), | ||
Future.of('lemon') | ||
).fork( | ||
() => (), | ||
([ apple, orange, lemon ]) => | ||
//=> apple, orange, lemon | ||
) | ||
Id(5).chain(a => Id(a)) | ||
//=> Id(5) | ||
// You can use chain to join the monads. | ||
Id(Id(5)).chain(a => a) | ||
//=> Id(5) | ||
``` | ||
### fold | ||
### cata | ||
[Foldable][6] | ||
Folds on identity. | ||
``` | ||
fold :: (a -> b) -> b | ||
cata :: ({ Left: () -> b, Right -> a -> a }) -> a | b | ||
``` | ||
```javascript | ||
Future.of(5).fold() | ||
Id(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 5 | ||
Id(5).cata({ | ||
Right: a => a + 1 | ||
}) | ||
//=> 6 | ||
Right(5).cata({ | ||
Left: a => 8 // ignored | ||
Right: a => a + 1 | ||
}) | ||
//=> 6 | ||
Left(5).cata({ | ||
Left: a => a + 1 | ||
Right: a => 8 // ignored | ||
}) | ||
//=> 6 | ||
Maybe(5).cata({ | ||
Right: a => a | ||
}) | ||
//=> 5 | ||
Maybe(5).cata({ | ||
Left: () => { } // not called | ||
Right: a => a + 1 | ||
}) | ||
//=> 6 | ||
Maybe(null).cata({ | ||
Left: () => 'there was a null' | ||
Right: a => a + 1 // not called | ||
}) | ||
//=> there was a null | ||
Right(5).cata({ | ||
Left: () => 1, | ||
Right: a => a + 2 | ||
}) | ||
//=> 7 | ||
Left(5).cata(a => a + 1) | ||
//=> 6 | ||
``` | ||
### fork | ||
Executes the `Future` returning a `Future` of the resuts. | ||
### chain | ||
[Chain][7] | ||
``` | ||
fork :: (a -> a, b -> b) -> Future of a | b | ||
chain :: (a -> b) -> b | ||
``` | ||
```javascript | ||
Future((left, right) => right(5)).fork(a => a, a => a) | ||
//=> Future of 5 | ||
Id(5).chain(a => Id(a)) | ||
//=> Id(5) | ||
Future((left, right) => left(Error('this is an error'))).fork(a => a) | ||
//=> Future of Error | ||
// You can use chain to join the monads. | ||
Id(Id(5)).chain(a => a) | ||
//=> Id(5) | ||
``` | ||
# Higher Order Utilities | ||
## compose | ||
### compose | ||
Compose takes n functions as arguments and return a function. | ||
@@ -378,3 +294,38 @@ | ||
## map | ||
### equals | ||
[Setoid][1] | ||
``` | ||
equals :: Id -> Boolean | ||
``` | ||
```javascript | ||
Id(1).equals(Id(1)) | ||
//=> true | ||
Id(2).equals(Id(1)) | ||
//=> false | ||
Id(2).equals(Id(1)) === Id(1).equals(Id(1)) | ||
//=> false | ||
``` | ||
### inspect | ||
``` | ||
inspect :: () -> String | ||
``` | ||
```javascript | ||
Id(5).inspect() | ||
//=> Id(5) | ||
``` | ||
### map | ||
[Functor][3] | ||
``` | ||
map :: (a -> b) -> Id of b | ||
``` | ||
```javascript | ||
Id(7).map(a => a * 2) | ||
//=> Id(14) | ||
``` | ||
### map (first class) | ||
Map as partial application and first class with arity support. | ||
@@ -387,3 +338,16 @@ | ||
## head, tail, last | ||
### of | ||
[Applicative][4] | ||
``` | ||
of :: a -> Id of a | ||
``` | ||
```javascript | ||
Id(5).of(6) | ||
//=> Id(6) | ||
Id(5).of(Id(6)) | ||
//=> Id(Id(6)) | ||
``` | ||
### head, tail, last | ||
Returns a Maybe. | ||
@@ -408,23 +372,20 @@ ``` javascript | ||
//=> Nothing() | ||
``` | ||
## encase, encaseEither | ||
### Maybe.encase, Either.encase | ||
Returns `Left | Right`. | ||
``` javascript | ||
encase(() => JSON.parse('["foo","bar","baz"]')) | ||
Maybe.encase(() => JSON.parse('["foo","bar","baz"]')) | ||
//=> Just(['foo','bar','baz']) | ||
encase(() => JSON.parse('[')) | ||
Maybe.encase(() => JSON.parse('[')) | ||
//=> Nothing() | ||
encaseEither(() => JSON.parse('["foo","bar","baz"]')) | ||
Either.encase(() => JSON.parse('["foo","bar","baz"]')) | ||
//=> Right(['foo','bar','baz']) | ||
encaseEither(() => JSON.parse('[')) | ||
Either.encase(() => JSON.parse('[')) | ||
//=> Left(new SyntaxError ('Unexpected end of JSON input')) | ||
``` | ||
[1]: https://github.com/fantasyland/fantasy-land#setoid | ||
@@ -431,0 +392,0 @@ [2]: https://github.com/fantasyland/fantasy-land#semigroup |
Sorry, the diff of this file is not supported yet
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
50572
1149
391