From 175da4b1aaf825b3165965d5b811f7f82411c2f9 Mon Sep 17 00:00:00 2001 From: David Chambers Date: Sun, 10 Apr 2016 22:23:48 -0700 Subject: [PATCH] list: add S.concat --- index.js | 25 ++++++++++++-- test/index.js | 92 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 13 deletions(-) diff --git a/index.js b/index.js index fb8ac0a8..e2d88d00 100644 --- a/index.js +++ b/index.js @@ -471,7 +471,7 @@ //. functions. //. //. ```javascript - //. > S.C(R.concat, 'foo', 'bar') + //. > S.C(S.concat, 'foo', 'bar') //. 'barfoo' //. //. > R.filter(S.C(R.gt, 0), [-1, -2, 3, -4, 4, 2]) @@ -1968,6 +1968,27 @@ //. ### List + //# concat :: Semigroup a => a -> a -> a + //. + //. Concatenates two (homogeneous) arrays, two strings, or two values of any + //. other type which satisfies the [Semigroup][] specification. + //. + //. ```javascript + //. > S.concat([1, 2, 3], [4, 5, 6]) + //. [1, 2, 3, 4, 5, 6] + //. + //. > S.concat('foo', 'bar') + //. 'foobar' + //. + //. > S.concat(S.Just('foo'), S.Just('bar')) + //. S.Just('foobar') + //. ``` + var concat = S.concat = + def('concat', + {a: [Semigroup]}, + [a, a, a], + function(x, y) { return x.concat(y); }); + //# slice :: Integer -> Integer -> [a] -> Maybe [a] //. //. Returns Just a list containing the elements from the supplied list @@ -2965,7 +2986,7 @@ def('unlines', {}, [$.Array($.String), $.String], - compose(R.join(''), R.map(R.concat(_, '\n')))); + compose(R.join(''), R.map(concat(_, '\n')))); return S; diff --git a/test/index.js b/test/index.js index a65c7b75..fb19ee48 100644 --- a/test/index.js +++ b/test/index.js @@ -384,14 +384,14 @@ describe('combinator', function() { }); it('C(f, x, y) is equivalent to f(y)(x)', function() { - eq(S.C(R.concat, 'foo', 'bar'), 'barfoo'); - eq(R.map(S.C(R.concat, '!'), ['BAM', 'POW', 'KA-POW']), ['BAM!', 'POW!', 'KA-POW!']); + eq(S.C(S.concat, 'foo', 'bar'), 'barfoo'); + eq(R.map(S.C(S.concat, '!'), ['BAM', 'POW', 'KA-POW']), ['BAM!', 'POW!', 'KA-POW!']); }); it('is curried', function() { - eq(S.C(R.concat).length, 2); - eq(S.C(R.concat)('foo').length, 1); - eq(S.C(R.concat)('foo')('bar'), 'barfoo'); + eq(S.C(S.concat).length, 2); + eq(S.C(S.concat)('foo').length, 1); + eq(S.C(S.concat)('foo')('bar'), 'barfoo'); }); }); @@ -3207,6 +3207,76 @@ describe('logic', function() { describe('list', function() { + describe('concat', function() { + + it('is a binary function', function() { + eq(typeof S.concat, 'function'); + eq(S.concat.length, 2); + }); + + it('type checks its arguments', function() { + throws(function() { S.concat(/XXX/); }, + errorEq(TypeError, + 'Type-class constraint violation\n' + + '\n' + + 'concat :: Semigroup a => a -> a -> a\n' + + ' ^^^^^^^^^^^ ^\n' + + ' 1\n' + + '\n' + + '1) /XXX/ :: RegExp\n' + + '\n' + + '‘concat’ requires ‘a’ to satisfy the Semigroup type-class constraint; the value at position 1 does not.\n')); + + throws(function() { S.concat('abc', [1, 2, 3]); }, + errorEq(TypeError, + 'Type-variable constraint violation\n' + + '\n' + + 'concat :: Semigroup a => a -> a -> a\n' + + ' ^ ^\n' + + ' 1 2\n' + + '\n' + + '1) "abc" :: String\n' + + '\n' + + '2) [1, 2, 3] :: Array Number, Array FiniteNumber, Array NonZeroFiniteNumber, Array Integer, Array ValidNumber\n' + + '\n' + + 'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n')); + }); + + it('can be applied to homogeneous arrays', function() { + eq(S.concat([], []), []); + eq(S.concat([1, 2, 3], []), [1, 2, 3]); + eq(S.concat([], [4, 5, 6]), [4, 5, 6]); + eq(S.concat([1, 2, 3], [4, 5, 6]), [1, 2, 3, 4, 5, 6]); + }); + + it('can be applied to strings', function() { + eq(S.concat('', ''), ''); + eq(S.concat('foo', ''), 'foo'); + eq(S.concat('', 'bar'), 'bar'); + eq(S.concat('foo', 'bar'), 'foobar'); + }); + + it('can be applied to maybes', function() { + eq(S.concat(S.Nothing(), S.Nothing()), S.Nothing()); + eq(S.concat(S.Just('foo'), S.Nothing()), S.Just('foo')); + eq(S.concat(S.Nothing(), S.Just('bar')), S.Just('bar')); + eq(S.concat(S.Just('foo'), S.Just('bar')), S.Just('foobar')); + }); + + it('can be applied to eithers', function() { + eq(S.concat(S.Left('abc'), S.Left('def')), S.Left('abcdef')); + eq(S.concat(S.Right([1, 2, 3]), S.Left('def')), S.Right([1, 2, 3])); + eq(S.concat(S.Left('abc'), S.Right([4, 5, 6])), S.Right([4, 5, 6])); + eq(S.concat(S.Right([1, 2, 3]), S.Right([4, 5, 6])), S.Right([1, 2, 3, 4, 5, 6])); + }); + + it('is curried', function() { + eq(S.concat([1, 2, 3]).length, 1); + eq(S.concat([1, 2, 3])([4, 5, 6]), [1, 2, 3, 4, 5, 6]); + }); + + }); + describe('at', function() { it('is a binary function', function() { @@ -4649,7 +4719,7 @@ describe('number', function() { '‘min’ requires ‘a’ to satisfy the Ord type-class constraint; the value at position 1 does not.\n')); }); - it('may be applied to (valid) numbers', function() { + it('can be applied to (valid) numbers', function() { eq(S.min(10, 2), 2); eq(S.min(2, 10), 2); eq(S.min(0.1, 0.01), 0.01); @@ -4658,12 +4728,12 @@ describe('number', function() { eq(S.min(-Infinity, Infinity), -Infinity); }); - it('may be applied to (valid) dates', function() { + it('can be applied to (valid) dates', function() { eq(S.min(new Date(10), new Date(2)), new Date(2)); eq(S.min(new Date(2), new Date(10)), new Date(2)); }); - it('may be applied to strings', function() { + it('can be applied to strings', function() { eq(S.min('abc', 'xyz'), 'abc'); eq(S.min('xyz', 'abc'), 'abc'); eq(S.min('10', '2'), '10'); @@ -4724,7 +4794,7 @@ describe('number', function() { '‘max’ requires ‘a’ to satisfy the Ord type-class constraint; the value at position 1 does not.\n')); }); - it('may be applied to (valid) numbers', function() { + it('can be applied to (valid) numbers', function() { eq(S.max(10, 2), 10); eq(S.max(2, 10), 10); eq(S.max(0.1, 0.01), 0.1); @@ -4733,12 +4803,12 @@ describe('number', function() { eq(S.max(-Infinity, Infinity), Infinity); }); - it('may be applied to (valid) dates', function() { + it('can be applied to (valid) dates', function() { eq(S.max(new Date(10), new Date(2)), new Date(10)); eq(S.max(new Date(2), new Date(10)), new Date(10)); }); - it('may be applied to strings', function() { + it('can be applied to strings', function() { eq(S.max('abc', 'xyz'), 'xyz'); eq(S.max('xyz', 'abc'), 'xyz'); eq(S.max('10', '2'), '2');