Skip to content

Commit 8759fd1

Browse files
authored
Merge pull request #33 from Avaq/av-chainrec
Add FantasyLand ChainRec
2 parents ac2f295 + 41be14d commit 8759fd1

5 files changed

Lines changed: 434 additions & 162 deletions

File tree

‎README.md‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ getPackageName('package.json')
6262
* [try](#try)
6363
* [encase](#encase)
6464
* [node](#node)
65+
* [chainRec](#chainrec)
6566
1. [Transforming Futures](#transforming-futures)
6667
* [map](#map)
6768
* [bimap](#bimap)
@@ -99,7 +100,7 @@ getPackageName('package.json')
99100
[<img src="https://raw.githubusercontent.com/rpominov/static-land/master/logo/logo.png" align="right" height="82" alt="Static Land" />][25]
100101

101102
Fluture implements [FantasyLand 1.x][1] and [Static Land][25] compatible
102-
`Functor`, `Bifunctor`, `Apply`, `Applicative`, `Chain` and `Monad`.
103+
`Functor`, `Bifunctor`, `Apply`, `Applicative`, `Chain`, `ChainRec` and `Monad`.
103104

104105
## Documentation
105106

@@ -119,7 +120,10 @@ A list of all types used within the signatures follows:
119120
- **Bifunctor** - Values which conform to the [Fantasy Land Bifunctor specification][24].
120121
- **Chain** - Values which conform to the [Fantasy Land Chain specification][13].
121122
- **Apply** - Values which conform to the [Fantasy Land Apply specification][14].
122-
- **Iterator** - Values which conform to the [Iterator protocol][18].
123+
- **Iterator** - Objects with `next`-methods which conform to the [Iterator protocol][18].
124+
- **Iteration** - `{done, value}`-Objects as defined by the [Iterator protocol][18].
125+
- **Next** - An incomplete (`{done: false}`) Iteration.
126+
- **Done** - A complete (`{done: true}`) Iteration.
123127
- **Cancel** - The nullary cancellation functions returned from computations.
124128

125129
### Creating Futures
@@ -251,6 +255,26 @@ Future.node(done => fs.readFile('package.json', 'utf8', done))
251255
//> "{...}"
252256
```
253257

258+
#### chainRec
259+
##### `.chainRec :: ((b -> Next, c -> Done, b) -> Future a Iteration) -> b -> Future a c`
260+
261+
Stack- and memory-safe asynchronous "recursion" based on [FantasyLand ChainRec][26].
262+
263+
Calls the given function with the initial value (as third argument), and expects
264+
a Future of an [Iteration](#type-signatures). If the Iteration is incomplete
265+
(`{done: false}`), then the function is called again with the Iteration value
266+
until it returns a Future of a complete (`{done: true}`) Iteration.
267+
268+
For convenience and interoperability, the first two arguments passed to the
269+
function are functions for creating an incomplete Iteration, and for creating a
270+
complete Iteration, respectively.
271+
272+
```js
273+
Future.chainRec((next, done, x) => Future.of(x < 1000000 ? next(x + 1) : done(x)), 0)
274+
.fork(console.error, console.log);
275+
//> 1000000
276+
```
277+
254278
### Transforming Futures
255279

256280
#### map
@@ -810,3 +834,4 @@ means butterfly in Romanian; A creature you might expect to see in Fantasy Land.
810834
[23]: https://vimeo.com/106008027
811835
[24]: https://github.com/fantasyland/fantasy-land#bifunctor
812836
[25]: https://github.com/rpominov/static-land
837+
[26]: https://github.com/fantasyland/fantasy-land#chainrec

‎bench/chainRec.js‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const benchmark = require('benchmark');
2+
const suite = new benchmark.Suite();
3+
const RamdaFuture = require('ramda-fantasy').Future;
4+
const FunTask = require('fun-task');
5+
const Fluture = require('..');
6+
7+
const noop = () => {};
8+
const iterator = of => (next, done, x) => x < 1 ? of(next(x + 0.0001)) : of(done(x));
9+
10+
suite.add('Fluture', () => {
11+
Fluture.chainRec(iterator(Fluture.of), 0).fork(noop, noop);
12+
});
13+
14+
suite.add('Ramda Fantasy', () => {
15+
RamdaFuture.chainRec(iterator(RamdaFuture.of), 0).fork(noop, noop);
16+
});
17+
18+
const handlers = {success: noop, failure: noop};
19+
suite.add('FunTask', () => {
20+
FunTask.chainRec(iterator(FunTask.of), 0).run(handlers);
21+
});
22+
23+
suite.on('complete', require('./_print'))
24+
suite.run()

0 commit comments

Comments
 (0)