From 9c19b9d97b3d9047c93c3de1bf3c1ed02921d93d Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 8 May 2016 21:53:42 -0700 Subject: [PATCH] either: add S.eitherToMaybe --- index.js | 66 ++++++++++++++++++++++++++++--------------- test/Maybe/Maybe.js | 7 ++--- test/eitherToMaybe.js | 39 +++++++++++++++++++++++++ test/match.js | 2 +- 4 files changed, 86 insertions(+), 28 deletions(-) create mode 100644 test/eitherToMaybe.js diff --git a/index.js b/index.js index 930caf8b..b0dcde5d 100644 --- a/index.js +++ b/index.js @@ -1302,7 +1302,7 @@ //. Binary version of [`encase`](#encase). //. //. See also [`encase2_`](#encase2_). - S.encase2 = + var encase2 = S.encase2 = def('encase2', {}, [$.Function, a, b, $Maybe(c)], @@ -1327,7 +1327,7 @@ return f_(x, y); }; }; - return S.encase2(f, x, y); + return encase2(f, x, y); }); //# encase3 :: (a -> b -> c -> d) -> a -> b -> c -> Maybe d @@ -1335,7 +1335,7 @@ //. Ternary version of [`encase`](#encase). //. //. See also [`encase3_`](#encase3_). - S.encase3 = + var encase3 = S.encase3 = def('encase3', {}, [$.Function, a, b, c, $Maybe(d)], @@ -1362,7 +1362,29 @@ }; }; }; - return S.encase3(f, x, y, z); + return encase3(f, x, y, z); + }); + + //# maybeToEither :: a -> Maybe b -> Either a b + //. + //. Converts a Maybe to an Either. A Nothing becomes a Left (containing the + //. first argument); a Just becomes a Right. + //. + //. See also [`eitherToMaybe`](#eitherToMaybe). + //. + //. ```javascript + //. > S.maybeToEither('Expecting an integer', S.parseInt(10, 'xyz')) + //. Left('Expecting an integer') + //. + //. > S.maybeToEither('Expecting an integer', S.parseInt(10, '42')) + //. Right(42) + //. ``` + S.maybeToEither = + def('maybeToEither', + {}, + [a, $Maybe(b), $Either(a, b)], + function(x, maybe) { + return maybe.isNothing ? Left(x) : Right(maybe.value); }); //. ### Either type @@ -1876,7 +1898,7 @@ //. Binary version of [`encaseEither`](#encaseEither). //. //. See also [`encaseEither2_`](#encaseEither2_). - S.encaseEither2 = + var encaseEither2 = S.encaseEither2 = def('encaseEither2', {}, [$.Function, $.Function, a, b, $Either(l, r)], @@ -1902,7 +1924,7 @@ return g_(x, y); }; }; - return S.encaseEither2(f, g, x, y); + return encaseEither2(f, g, x, y); }); //# encaseEither3 :: (Error -> l) -> (a -> b -> c -> r) -> a -> b -> c -> Either l r @@ -1910,7 +1932,7 @@ //. Ternary version of [`encaseEither`](#encaseEither). //. //. See also [`encaseEither3_`](#encaseEither3_). - S.encaseEither3 = + var encaseEither3 = S.encaseEither3 = def('encaseEither3', {}, [$.Function, $.Function, a, b, c, $Either(l, r)], @@ -1938,29 +1960,29 @@ }; }; }; - return S.encaseEither3(f, g, x, y, z); + return encaseEither3(f, g, x, y, z); }); - //# maybeToEither :: a -> Maybe b -> Either a b + //# eitherToMaybe :: Either a b -> Maybe b //. - //. Takes a value of any type and a Maybe, and returns an Either. - //. If the second argument is a Nothing, a Left containing the first - //. argument is returned. If the second argument is a Just, a Right - //. containing the Just's value is returned. + //. Converts an Either to a Maybe. A Left becomes a Nothing; a Right becomes + //. a Just. + //. + //. See also [`maybeToEither`](#maybeToEither). //. //. ```javascript - //. > S.maybeToEither('Expecting an integer', S.parseInt(10, 'xyz')) - //. Left('Expecting an integer') + //. > S.eitherToMaybe(S.Left('Cannot divide by zero')) + //. Nothing() //. - //. > S.maybeToEither('Expecting an integer', S.parseInt(10, '42')) - //. Right(42) + //. > S.eitherToMaybe(S.Right(42)) + //. Just(42) //. ``` - S.maybeToEither = - def('maybeToEither', + S.eitherToMaybe = + def('eitherToMaybe', {}, - [a, $Maybe(b), $Either(a, b)], - function(x, maybe) { - return maybe.isNothing ? Left(x) : Right(maybe.value); + [$Either(a, b), $Maybe(b)], + function(either) { + return either.isLeft ? Nothing() : Just(either.value); }); //. ### Alternative diff --git a/test/Maybe/Maybe.js b/test/Maybe/Maybe.js index d7d03ce7..7f821570 100644 --- a/test/Maybe/Maybe.js +++ b/test/Maybe/Maybe.js @@ -43,9 +43,6 @@ var JustArb = function(arb) { return arb.smap(S.Just, function(m) { return m.value; }, R.toString); }; -// eitherToMaybe :: Either a b -> Maybe b -var eitherToMaybe = S.either(S.K(S.Nothing()), S.Just); - // EitherArb :: Arbitrary a -> Arbitrary b -> Arbitrary (Either a b) var EitherArb = function(lArb, rArb) { return jsc.oneof(LeftArb(lArb), RightArb(rArb)); @@ -97,8 +94,8 @@ describe('Maybe', function() { it('satisfies naturality', function() { jsc.assert(jsc.forall(MaybeArb(EitherArb(jsc.integer, jsc.string)), function(maybe) { - var lhs = eitherToMaybe(maybe.sequence(S.Either.of)); - var rhs = maybe.map(eitherToMaybe).sequence(S.Maybe.of); + var lhs = S.eitherToMaybe(maybe.sequence(S.Either.of)); + var rhs = maybe.map(S.eitherToMaybe).sequence(S.Maybe.of); return lhs.equals(rhs); })); }); diff --git a/test/eitherToMaybe.js b/test/eitherToMaybe.js new file mode 100644 index 00000000..c97e0825 --- /dev/null +++ b/test/eitherToMaybe.js @@ -0,0 +1,39 @@ +'use strict'; + +var throws = require('assert').throws; + +var eq = require('./utils').eq; +var errorEq = require('./utils').errorEq; +var S = require('..'); + + +describe('eitherToMaybe', function() { + + it('is a unary function', function() { + eq(typeof S.eitherToMaybe, 'function'); + eq(S.eitherToMaybe.length, 1); + }); + + it('type checks its arguments', function() { + throws(function() { S.eitherToMaybe(/XXX/); }, + errorEq(TypeError, + 'Invalid value\n' + + '\n' + + 'eitherToMaybe :: Either a b -> Maybe b\n' + + ' ^^^^^^^^^^\n' + + ' 1\n' + + '\n' + + '1) /XXX/ :: RegExp\n' + + '\n' + + 'The value at position 1 is not a member of ‘Either a b’.\n')); + }); + + it('returns a Nothing when applied to a Left', function() { + eq(S.eitherToMaybe(S.Left('Cannot divide by zero')), S.Nothing()); + }); + + it('returns a Just when applied to a Right', function() { + eq(S.eitherToMaybe(S.Right(42)), S.Just(42)); + }); + +}); diff --git a/test/match.js b/test/match.js index e01a8c9c..e4daa7e1 100644 --- a/test/match.js +++ b/test/match.js @@ -56,7 +56,7 @@ describe('match', function() { S.Just([S.Just('bye'), S.Nothing()])); }); - it('returns a Nothing() if no match', function() { + it('returns a Nothing if no match', function() { eq(S.match(/zzz/, 'abcdefg'), S.Nothing()); });