From 89616636fd66d7f2dabb532389467e35ba9ebab1 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Tue, 20 Feb 2018 15:02:57 +0100 Subject: [PATCH] maybe: generalize S.mapMaybe --- index.js | 25 ++++++++++++++----------- test/mapMaybe.js | 23 +++++++++++++++++++++-- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index 34660398..70008cd0 100644 --- a/index.js +++ b/index.js @@ -2195,25 +2195,28 @@ S.justs = def('justs', {f: [Z.Filterable, Z.Functor]}, [f($Maybe(a)), f(a)], justs); - //# mapMaybe :: (a -> Maybe b) -> Array a -> Array b + //# mapMaybe :: (Filterable f, Functor f) => (a -> Maybe b) -> f a -> f b //. - //. Takes a function and an array, applies the function to each element of - //. the array, and returns an array of "successful" results. If the result of - //. applying the function to an element of the array is Nothing, the result - //. is discarded; if the result is a Just, the Just's value is included in - //. the output array. - //. - //. In general terms, `mapMaybe` filters an array while mapping over it. + //. Takes a function and a structure, applies the function to each element + //. of the structure, and returns the "successful" results. If the result of + //. applying the function to an element is Nothing, the result is discarded; + //. if the result is a Just, the Just's value is included. //. //. ```javascript //. > S.mapMaybe(S.head, [[], [1, 2, 3], [], [4, 5, 6], []]) //. [1, 4] + //. + //. > S.mapMaybe(S.head, {x: [1, 2, 3], y: [], z: [4, 5, 6]}) + //. {x: 1, z: 4} //. ``` - function mapMaybe(f, xs) { - return justs(Z.map(f, xs)); + function mapMaybe(f, filterable) { + return justs(Z.map(f, filterable)); } S.mapMaybe = - def('mapMaybe', {}, [Fn(a, $Maybe(b)), $.Array(a), $.Array(b)], mapMaybe); + def('mapMaybe', + {f: [Z.Filterable, Z.Functor]}, + [Fn(a, $Maybe(b)), f(a), f(b)], + mapMaybe); //# encase :: (a -> b) -> a -> Maybe b //. diff --git a/test/mapMaybe.js b/test/mapMaybe.js index 5baf7ad9..8c958081 100644 --- a/test/mapMaybe.js +++ b/test/mapMaybe.js @@ -1,19 +1,38 @@ 'use strict'; -var S = require('..'); +var S = require('./internal/sanctuary'); +var List = require('./internal/List'); var eq = require('./internal/eq'); +var Cons = List.Cons; +var Nil = List.Nil; + + test('mapMaybe', function() { eq(typeof S.mapMaybe, 'function'); eq(S.mapMaybe.length, 2); - eq(S.mapMaybe.toString(), 'mapMaybe :: (a -> Maybe b) -> Array a -> Array b'); + eq(S.mapMaybe.toString(), 'mapMaybe :: (Filterable f, Functor f) => (a -> Maybe b) -> f a -> f b'); eq(S.mapMaybe(S.head, []), []); eq(S.mapMaybe(S.head, [[], [], []]), []); eq(S.mapMaybe(S.head, [[1, 2], [3, 4], [5, 6]]), [1, 3, 5]); eq(S.mapMaybe(S.head, [[1], [], [3], [], [5], []]), [1, 3, 5]); + eq(S.mapMaybe(S.head, {}), {}); + eq(S.mapMaybe(S.head, {a: [], b: [], c: []}), {}); + eq(S.mapMaybe(S.head, {a: [1, 2], b: [3, 4], c: [5, 6]}), {a: 1, b: 3, c: 5}); + eq(S.mapMaybe(S.head, {a: [1], b: [], c: [3], d: [], e: [5], f: []}), {a: 1, c: 3, e: 5}); + + eq(S.mapMaybe(S.head, S.Nothing), S.Nothing); + eq(S.mapMaybe(S.head, S.Just([])), S.Nothing); + eq(S.mapMaybe(S.head, S.Just([1, 2])), S.Just(1)); + + eq(S.mapMaybe(S.head, Nil), Nil); + eq(S.mapMaybe(S.head, Cons([], Cons([], Cons([], Nil)))), Nil); + eq(S.mapMaybe(S.head, Cons([1, 2], Cons([3, 4], Cons([5, 6], Nil)))), Cons(1, Cons(3, Cons(5, Nil)))); + eq(S.mapMaybe(S.head, Cons([1], Cons([], Cons([3], Cons([], Cons([5], Cons([], Nil))))))), Cons(1, Cons(3, Cons(5, Nil)))); + });