Skip to content

Commit

Permalink
Add S.mean that calculates mean of values of a foldable
Browse files Browse the repository at this point in the history
  • Loading branch information
jdudek committed Jun 28, 2016
1 parent bde77ac commit 6e97bb0
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
35 changes: 35 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3083,6 +3083,41 @@
[$.FiniteNumber, $.NonZeroFiniteNumber, $.FiniteNumber],
function(a, b) { return a / b; });

//# mean :: Foldable f => f FiniteNumber -> Maybe FiniteNumber
//.
//. Returns the mean of the given array of (finite) numbers.
//.
//. ```javascript
//. > S.mean([1, 2, 3, 4, 5])
//. S.Just(3)
//.
//. > S.mean([])
//. S.Nothing()
//.
//. > S.mean(S.Just(42))
//. S.Just(42)
//.
//. > S.mean(S.Nothing())
//. S.Nothing()
//. ```
S.mean =
def('mean',
{f: [Foldable]},
[f, $Maybe($.FiniteNumber)],
function(foldable) {
var result = reduce_(
function(acc, n) {
acc.total += n;
acc.count += 1;
return acc;
},
{total: 0, count: 0},
foldable
);
return result.count === 0 ? Nothing()
: Just(result.total / result.count);
});

//# min :: Ord a => a -> a -> a
//.
//. Returns the smaller of its two arguments.
Expand Down
76 changes: 76 additions & 0 deletions test/mean.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';

var throws = require('assert').throws;

var eq = require('./utils').eq;
var errorEq = require('./utils').errorEq;
var S = require('..');


describe('mean', function() {

it('is a unary function', function() {
eq(typeof S.mean, 'function');
eq(S.mean.length, 1);
});

it('type checks its arguments', function() {
throws(function() { S.mean('xxx'); },
errorEq(TypeError,
'Type-class constraint violation\n' +
'\n' +
'mean :: Foldable f => f -> Maybe FiniteNumber\n' +
' ^^^^^^^^^^ ^\n' +
' 1\n' +
'\n' +
'1) "xxx" :: String\n' +
'\n' +
'‘mean’ requires ‘f’ to satisfy the Foldable type-class constraint; the value at position 1 does not.\n'));

throws(function() { S.mean([1, 2, 'xxx']); },
errorEq(TypeError,
'Type-variable constraint violation\n' +
'\n' +
'mean :: Foldable f => f -> Maybe FiniteNumber\n' +
' ^\n' +
' 1\n' +
'\n' +
'1) [1, 2, "xxx"] :: Array ???\n' +
'\n' +
'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));

throws(function() { S.mean([1, Infinity]); },
errorEq(TypeError,
'Invalid value\n' +
'\n' +
'mean :: Foldable f => f -> Maybe FiniteNumber\n' +
' ^^^^^^^^^^^^\n' +
' 1\n' +
'\n' +
'1) Infinity :: Number, ValidNumber\n' +
'\n' +
'The value at position 1 is not a member of ‘FiniteNumber’.\n'));
});

it('returns the mean of a non-empty array of numbers', function() {
eq(S.mean([1, 2, 3]), S.Just(2));
eq(S.mean([0.1, 0.3]), S.Just(0.2));
eq(S.mean([-0]), S.Just(0));
eq(S.mean([-0, 0]), S.Just(0));
});

it('returns nothing when applied to an empty array', function() {
eq(S.mean([]), S.Nothing());
});

it('can be applied to Maybes', function() {
eq(S.mean(S.Nothing()), S.Nothing());
eq(S.mean(S.Just(42)), S.Just(42));
});

it('can be applied to Eithers', function() {
eq(S.mean(S.Left('xxx')), S.Nothing());
eq(S.mean(S.Right(42)), S.Just(42));
});

});

0 comments on commit 6e97bb0

Please sign in to comment.