Skip to content

Commit

Permalink
derive ‘all’, ‘any’, and ‘none’ from ‘reduce’
Browse files Browse the repository at this point in the history
  • Loading branch information
davidchambers committed Feb 19, 2019
1 parent 77614db commit a149cef
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 3 deletions.
85 changes: 82 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,13 @@
};
}

// unary :: (a -> b) -> (a, Any...) -> b
function unary(f) {
return function(x) {
return f (x);
};
}

// type Iteration a = { value :: a, done :: Boolean }

// iterationNext :: a -> Iteration a
Expand Down Expand Up @@ -1974,6 +1981,77 @@
return reduce (function(n, _) { return n + 1; }, 0, foldable);
}

//# all :: Foldable f => (a -> Boolean, f a) -> Boolean
//.
//. Returns `true` if all the elements of the structure satisfy the
//. predicate; `false` otherwise.
//.
//. This function is derived from [`reduce`](#reduce).
//.
//. See also [`any`](#any) and [`none`](#none).
//.
//. ```javascript
//. > all (Number.isInteger, [])
//. true
//.
//. > all (Number.isInteger, [1, 2, 3])
//. true
//.
//. > all (Number.isInteger, [0, 0.25, 0.5, 0.75, 1])
//. false
//. ```
function all(pred, foldable) {
// Fast path for arrays.
if (Array.isArray (foldable)) return foldable.every (unary (pred));
return reduce (function(b, x) { return b && pred (x); }, true, foldable);
}

//# any :: Foldable f => (a -> Boolean, f a) -> Boolean
//.
//. Returns `true` if any element of the structure satisfies the predicate;
//. `false` otherwise.
//.
//. This function is derived from [`reduce`](#reduce).
//.
//. See also [`all`](#all) and [`none`](#none).
//.
//. ```javascript
//. > any (Number.isInteger, [])
//. false
//.
//. > any (Number.isInteger, [1, 2, 3])
//. true
//.
//. > any (Number.isInteger, [0, 0.25, 0.5, 0.75, 1])
//. true
//. ```
function any(pred, foldable) {
// Fast path for arrays.
if (Array.isArray (foldable)) return foldable.some (unary (pred));
return reduce (function(b, x) { return b || pred (x); }, false, foldable);
}

//# none :: Foldable f => (a -> Boolean, f a) -> Boolean
//.
//. Returns `true` if none of the elements of the structure satisfies the
//. predicate; `false` otherwise.
//.
//. This function is derived from [`any`](#any). `none (pred, foldable)` is
//. equivalent to `!(any (pred, foldable))`.
//.
//. See also [`all`](#all).
//.
//. ```javascript
//. > none (Number.isInteger, [])
//. true
//.
//. > none (Number.isInteger, [0, 0.25, 0.5, 0.75, 1])
//. false
//. ```
function none(pred, foldable) {
return !(any (pred, foldable));
}

//# elem :: (Setoid a, Foldable f) => (a, f a) -> Boolean
//.
//. Takes a value and a structure and returns `true` if the
Expand Down Expand Up @@ -2005,9 +2083,7 @@
//. false
//. ```
function elem(x, foldable) {
return reduce (function(b, y) { return b || equals (x, y); },
false,
foldable);
return any (function(y) { return equals (x, y); }, foldable);
}

//# foldMap :: (Monoid m, Foldable f) => (TypeRep m, a -> m, f a) -> m
Expand Down Expand Up @@ -2296,6 +2372,9 @@
zero: zero,
reduce: reduce,
size: size,
all: all,
any: any,
none: none,
elem: elem,
foldMap: foldMap,
reverse: reverse,
Expand Down
69 changes: 69 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,75 @@ test ('size', function() {
eq (Z.size (Tuple ('abc', 123)), 1);
});

test ('all', function() {
eq (Z.all.length, 2);
eq (Z.all.name, 'all');

eq (Z.all (gt (0), []), true);
eq (Z.all (gt (0), [0]), false);
eq (Z.all (gt (0), [1]), true);
eq (Z.all (gt (0), [0, 0]), false);
eq (Z.all (gt (0), [0, 1]), false);
eq (Z.all (gt (0), [1, 0]), false);
eq (Z.all (gt (0), [1, 1]), true);
eq (Z.all (gt (0), Nil), true);
eq (Z.all (gt (0), Cons (0, Nil)), false);
eq (Z.all (gt (0), Cons (1, Nil)), true);
eq (Z.all (gt (0), Cons (0, Cons (0, Nil))), false);
eq (Z.all (gt (0), Cons (0, Cons (1, Nil))), false);
eq (Z.all (gt (0), Cons (1, Cons (0, Nil))), false);
eq (Z.all (gt (0), Cons (1, Cons (1, Nil))), true);
eq (Z.all (gt (0), Nothing), true);
eq (Z.all (gt (0), Just (0)), false);
eq (Z.all (gt (0), Just (1)), true);
});

test ('any', function() {
eq (Z.any.length, 2);
eq (Z.any.name, 'any');

eq (Z.any (gt (0), []), false);
eq (Z.any (gt (0), [0]), false);
eq (Z.any (gt (0), [1]), true);
eq (Z.any (gt (0), [0, 0]), false);
eq (Z.any (gt (0), [0, 1]), true);
eq (Z.any (gt (0), [1, 0]), true);
eq (Z.any (gt (0), [1, 1]), true);
eq (Z.any (gt (0), Nil), false);
eq (Z.any (gt (0), Cons (0, Nil)), false);
eq (Z.any (gt (0), Cons (1, Nil)), true);
eq (Z.any (gt (0), Cons (0, Cons (0, Nil))), false);
eq (Z.any (gt (0), Cons (0, Cons (1, Nil))), true);
eq (Z.any (gt (0), Cons (1, Cons (0, Nil))), true);
eq (Z.any (gt (0), Cons (1, Cons (1, Nil))), true);
eq (Z.any (gt (0), Nothing), false);
eq (Z.any (gt (0), Just (0)), false);
eq (Z.any (gt (0), Just (1)), true);
});

test ('none', function() {
eq (Z.none.length, 2);
eq (Z.none.name, 'none');

eq (Z.none (gt (0), []), true);
eq (Z.none (gt (0), [0]), true);
eq (Z.none (gt (0), [1]), false);
eq (Z.none (gt (0), [0, 0]), true);
eq (Z.none (gt (0), [0, 1]), false);
eq (Z.none (gt (0), [1, 0]), false);
eq (Z.none (gt (0), [1, 1]), false);
eq (Z.none (gt (0), Nil), true);
eq (Z.none (gt (0), Cons (0, Nil)), true);
eq (Z.none (gt (0), Cons (1, Nil)), false);
eq (Z.none (gt (0), Cons (0, Cons (0, Nil))), true);
eq (Z.none (gt (0), Cons (0, Cons (1, Nil))), false);
eq (Z.none (gt (0), Cons (1, Cons (0, Nil))), false);
eq (Z.none (gt (0), Cons (1, Cons (1, Nil))), false);
eq (Z.none (gt (0), Nothing), true);
eq (Z.none (gt (0), Just (0)), true);
eq (Z.none (gt (0), Just (1)), false);
});

test ('elem', function() {
eq (Z.elem.length, 2);
eq (Z.elem.name, 'elem');
Expand Down

0 comments on commit a149cef

Please sign in to comment.