diff --git a/index.js b/index.js index 3b460119..0442ce5b 100644 --- a/index.js +++ b/index.js @@ -867,11 +867,11 @@ //. ``` S.join = def('join', {m: [Z.Chain]}, [m(m(a)), m(a)], Z.join); - //# chainRec :: ChainRec m => TypeRep m -> (a -> Either (m b) (m b)) -> a -> m b + //# chainRec :: ChainRec m => TypeRep m -> (a -> m (Either a b)) -> a -> m b //. //. Performs a [`chain`](#chain)-like computation with constant stack usage. //. Similar to [`Z.chainRec`][], but curried and more convenient due to the - //. use of the Either type to indicate completion. + //. use of the Either type to indicate completion (via a Right). //. //. ```javascript //. > S.chainRec(Array, @@ -880,17 +880,17 @@ //. . '') //. ['oo!', 'oo?', 'on!', 'on?', 'no!', 'no?', 'nn!', 'nn?'] //. ``` + function chainRec(typeRep, f, x) { + function step(next, done, x) { + return Z.map(function(e) { return either(next, done, e); }, f(x)); + } + return Z.chainRec(typeRep, step, x); + } S.chainRec = def('chainRec', {m: [Z.ChainRec]}, - [TypeRep($.TypeVariable('m')), Fn(a, $Either(m(b), m(b))), a, m(b)], - function(typeRep, f, x) { - function step(next, done, x) { - var either = f(x); - return Z.map(either.isLeft ? next : done, either.value); - } - return Z.chainRec(typeRep, step, x); - }); + [TypeRep($.TypeVariable('m')), Fn(a, m($Either(a, b))), a, m(b)], + chainRec); //# extend :: Extend w => (w a -> b) -> w a -> w b //. diff --git a/test/chainRec.js b/test/chainRec.js index 40b66bbc..296e2ef0 100644 --- a/test/chainRec.js +++ b/test/chainRec.js @@ -1,5 +1,7 @@ 'use strict'; +var Z = require('sanctuary-type-classes'); + var S = require('..'); var eq = require('./internal/eq'); @@ -9,18 +11,18 @@ test('chainRec', function() { eq(typeof S.chainRec, 'function'); eq(S.chainRec.length, 3); - eq(S.chainRec.toString(), 'chainRec :: ChainRec m => TypeRep m -> (a -> Either (m b) (m b)) -> a -> m b'); + eq(S.chainRec.toString(), 'chainRec :: ChainRec m => TypeRep m -> (a -> m (Either a b)) -> a -> m b'); function permute(s) { - return s.length === 2 ? S.Right([s + '!', s + '?']) - : S.Left([s + 'o', s + 'n']); + return s.length === 2 ? Z.map(S.Right, [s + '!', s + '?']) + : Z.map(S.Left, [s + 'o', s + 'n']); } eq(S.chainRec(Array, permute, ''), ['oo!', 'oo?', 'on!', 'on?', 'no!', 'no?', 'nn!', 'nn?']); function stepper(n) { - return n === 3000 ? S.Right(function(env) { return n + env.inc; }) - : S.Left(function(env) { return n + env.step; }); + return n === 3000 ? Z.map(S.Right, function(env) { return n + env.inc; }) + : Z.map(S.Left, function(env) { return n + env.step; }); } eq(S.chainRec(Function, stepper, 0)({step: 2, inc: 100}), 3100);