diff --git a/ramda.js b/ramda.js index 3c9eb44cc..d61728c51 100644 --- a/ramda.js +++ b/ramda.js @@ -229,23 +229,23 @@ }; } - var _; // This is intentionally left `undefined`. + var __; // This is intentionally left `undefined`. try { - Object.defineProperty(R, '_', {writable: false, value: _}); + Object.defineProperty(R, '__', {writable: false, value: __}); } catch (e) { - R._ = _; + R.__ = __; } /** - * Converts a function into something like an infix operation, meaning that - * when called with a single argument, that argument is applied to the - * second position, sort of a curry-right. This allows for more natural - * processing of functions which are really binary operators. + * Uses a placeholder to convert a binary function into something like an infix operation. + * When called with an `undefined` placeholder (e.g. `R.__`) the second argument is applied to the + * second position, and it returns a function waiting for its first argument. + * This can allow for more natural processing of functions which are really binary operators. * * @func * @memberOf R * @category Functions - * @param {function} fn The operation to adjust + * @param {function} fn The binary operation to adjust * @return {function} A new function that acts somewhat like an infix operator. * @example * @@ -254,20 +254,28 @@ * }); * * div(6, 3); //=> 2 - * div(6, _)(3); //=> 2 // note: `_` here is just an `undefined` value. You could use `void 0` instead - * div(3)(6); //=> 2 + * div(6)(3); //=> 2 + * div(__, 3)(6); //=> 2 // note: `__` here is just an `undefined` value. You could use `void 0` instead + * div(__)(3, 6); //=> 2 + * div(__)(3)(6); //=> 2 */ var op = R.op = function op(fn) { var length = fn.length; - if (length < 2) {throw new Error('Expected binary function.');} - var left = curry(fn), right = curry(R.flip(fn)); + if (length !== 2) {throw new Error('Expected binary function.');} - return function(a, b) { + return function _op(a, b) { switch (arguments.length) { case 0: throw noArgsException(); - case 1: return right(a); - case 2: return (b === R._) ? left(a) : left.apply(null, arguments); - default: return left.apply(null, arguments); + case 1: + if (a === __) { + return R.flip(_op); + } + return R.lPartial(fn, a); + default: + if (a === __) { + return R.rPartial(fn, b); + } + return fn(a, b); } }; }; @@ -4284,16 +4292,17 @@ * @param {number} a The first value. * @param {number} b The second value. * @return {number} The result of `a - b`. - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.subtract(10, 8); //=> 2 * - * var minus5 = R.subtract(5); + * var minus5 = R.subtract(__, 5); // '__' stands for any `undefined` value * minus5(17); //=> 12 * * // note: In this example, `_` is just an `undefined` value. You could use `void 0` instead - * var complementaryAngle = R.subtract(90, _); + * var complementaryAngle = R.subtract(90); * complementaryAngle(30); //=> 60 * complementaryAngle(72); //=> 18 */ @@ -4302,8 +4311,6 @@ /** * Divides two numbers. Equivalent to `a / b`. - * While at times the curried version of `divide` might be useful, - * probably the curried version of `divideBy` will be more useful. * * @func * @memberOf R @@ -4312,16 +4319,17 @@ * @param {number} a The first value. * @param {number} b The second value. * @return {number} The result of `a / b`. - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.divide(71, 100); //=> 0.71 * - * // note: In this example, `_` is just an `undefined` value. You could use `void 0` instead - * var half = R.divide(2); + * // note: In this example, `__` is just an `undefined` value. You could use `void 0` instead + * var half = R.divide(__, 2); * half(42); //=> 21 * - * var reciprocal = R.divide(1, _); + * var reciprocal = R.divide(1); * reciprocal(4); //=> 0.25 */ R.divide = op(function _divide(a, b) { return a / b; }); @@ -4339,7 +4347,8 @@ * @param {number} a The value to the divide. * @param {number} b The pseudo-modulus * @return {number} The result of `b % a`. - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @see R.mathMod * @example * @@ -4348,7 +4357,7 @@ * R.modulo(-17, 3); //=> -2 * R.modulo(17, -3); //=> 2 * - * var isOdd = R.modulo(2); + * var isOdd = R.modulo(__, 2); * isOdd(42); //=> 0 * isOdd(21); //=> 1 */ @@ -4383,6 +4392,8 @@ * @param {number} p the modulus. * @return {number} The result of `b mod a`. * @see R.moduloBy + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.mathMod(-17, 5); //=> 3 @@ -4392,12 +4403,12 @@ * R.mathMod(17.2, 5); //=> NaN * R.mathMod(17, 5.3); //=> NaN * - * var clock = R.mathMod(12); + * var clock = R.mathMod(__, 12); * clock(15); //=> 3 * clock(24); //=> 0 * * // note: In this example, `_` is just an `undefined` value. You could use `void 0` instead - * var seventeenMod = R.mathMod(17, _); + * var seventeenMod = R.mathMod(17); * seventeenMod(3); //=> 2 * seventeenMod(4); //=> 1 * seventeenMod(10); //=> 7 @@ -4409,7 +4420,6 @@ }); - /** * Adds together all the elements of a list. * @@ -4454,14 +4464,15 @@ * @param {Number} a * @param {Number} b * @return {Boolean} a < b - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.lt(2, 6); //=> true * R.lt(2, 0); //=> false * R.lt(2, 2); //=> false - * R.lt(5)(10); //=> false // default currying is right-sectioned - * R.lt(5, _)(10); //=> true // left-sectioned currying + * R.lt(5)(10); //=> true + * R.lt(__, 5)(10); //=> false // right-sectioned currying */ R.lt = op(function _lt(a, b) { return a < b; }); @@ -4476,12 +4487,16 @@ * @param {Number} a * @param {Number} b * @return {Boolean} a <= b - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.lte(2, 6); //=> true * R.lte(2, 0); //=> false * R.lte(2, 2); //=> true + * R.lte(__, 2)(1); //=> true + * R.lte(2)(10); //=> true + * R.lte(__)(5, 4) // => true */ R.lte = op(function _lte(a, b) { return a <= b; }); @@ -4496,12 +4511,16 @@ * @param {Number} a * @param {Number} b * @return {Boolean} a > b - * @note Operator: this is right-curried by default, but can be called via sections + * @note Operator: Since this is a non-commutative infix operator converted to prefix, it can + * be curried right by explicitly passing `undefined` for its first argument. * @example * * R.gt(2, 6); //=> false * R.gt(2, 0); //=> true * R.gt(2, 2); //=> false + * R.gt(__, 2)(10); //=> true + * R.gt(2)(10); //=> false + * R.lte(__)(4, 5) // => true */ R.gt = op(function _gt(a, b) { return a > b; }); @@ -4522,6 +4541,9 @@ * R.gte(2, 6); //=> false * R.gte(2, 0); //=> true * R.gte(2, 2); //=> true + * R.gte(__, 6)(2); //=> false + * R.gte(2)(0); //=> true + * R.gte(__)(1, 2); //=> true */ R.gte = op(function _gte(a, b) { return a >= b; }); diff --git a/test/test.math.js b/test/test.math.js index b12dd8914..a0402515d 100644 --- a/test/test.math.js +++ b/test/test.math.js @@ -1,6 +1,5 @@ var assert = require('assert'); var R = require('..'); -var _ = void 0; describe('add', function() { it('adds together two numbers', function() { @@ -37,13 +36,13 @@ describe('subtract', function() { assert.equal(15, R.subtract(22, 7)); }); - it('is automatically right-curried', function() { - var ninesCompl = R.subtract(9, void 0); + it('is curried', function() { + var ninesCompl = R.subtract(9); assert.equal(3, ninesCompl(6)); }); - it('allows for left sections too', function() { - var minus5 = R.subtract(5); + it('behaves right curried when passed `undefined` for its first argument', function() { + var minus5 = R.subtract(void 0, 5); assert.equal(12, minus5(17)); }); @@ -58,13 +57,13 @@ describe('divide', function() { assert.equal(4, R.divide(28, 7)); }); - it('is automatically right-curried', function() { - var into28 = R.divide(28, _); + it('is curried', function() { + var into28 = R.divide(28); assert.equal(4, into28(7)); }); - it('allows for left sections too', function() { - var half = R.divide(2); + it('behaves right curried when passed `undefined` for its first argument', function() { + var half = R.divide(void 0, 2); assert.equal(20, half(40)); }); @@ -81,16 +80,16 @@ describe('modulo', function() { assert.equal(R.modulo(100, 17), 15); }); - it('is automatically right-curried', function() { - var hundredMod = R.modulo(100, _); + it('is curried', function() { + var hundredMod = R.modulo(100); assert.equal(typeof hundredMod, 'function'); assert.equal(hundredMod(2), 0); assert.equal(hundredMod(3), 1); assert.equal(hundredMod(17), 15); }); - it('allows for left sections too', function() { - var isOdd = R.modulo(2); + it('behaves right curried when passed `undefined` for its first argument', function() { + var isOdd = R.modulo(void 0, 2); assert.equal(typeof isOdd, 'function'); assert.equal(isOdd(3), 1); assert.equal(isOdd(198), 0); @@ -128,14 +127,14 @@ describe('mathMod', function() { assert.equal(isNaN(R.mathMod(17, 5.5)), true); }); - it('is automatically right-curried', function() { - var f = R.mathMod(29, _); + it('is curried', function() { + var f = R.mathMod(29); assert.equal(f(6), 5); }); - it('allows for left sections too', function() { - var mod5 = R.modulo(5); + it('behaves right curried when passed `undefined` for its first argument', function() { + var mod5 = R.modulo(void 0, 5); assert.equal(mod5(12), 2); assert.equal(mod5(8), 3); }); @@ -164,7 +163,7 @@ describe('product', function() { }); describe('lt', function() { - var _ = void 0; + var __ = void 0; it('reports whether one item is less than another', function() { assert(R.lt(3, 5)); assert(!R.lt(6, 4)); @@ -173,27 +172,27 @@ describe('lt', function() { assert(!R.lt('abcd', 'abc')); }); - it('is automatically right-curried', function() { - var lt5 = R.lt(5); - assert(!lt5(10)); - assert(!lt5(5)); - assert(lt5(3)); - }); - - it('allows for left sections too', function() { - var gt5 = R.lt(5, _); + it('is curried', function() { + var gt5 = R.lt(5); assert(gt5(10)); assert(!gt5(5)); assert(!gt5(3)); }); + it('behaves right curried when passed `undefined` for its first argument', function() { + var lt5 = R.lt(__, 5); + assert(!lt5(10)); + assert(!lt5(5)); + assert(lt5(3)); + }); + it('throws when given no arguments', function() { assert.throws(R.lt, TypeError); }); }); describe('lte', function() { - var _ = void 0; + var __ = void 0; it('reports whether one item is less than another', function() { assert(R.lte(3, 5)); assert(!R.lte(6, 4)); @@ -202,18 +201,18 @@ describe('lte', function() { assert(!R.lte('abcd', 'abc')); }); - it('is automatically right-curried', function() { - var noMoreThan20 = R.lte(20); - assert(noMoreThan20(10)); - assert(noMoreThan20(20)); - assert(!noMoreThan20(25)); + it('is curried', function() { + var gte20 = R.lte(20); + assert(!gte20(10)); + assert(gte20(20)); + assert(gte20(25)); }); - it('allows for left sections too', function() { - var atLeast20 = R.lte(20, _); - assert(!atLeast20(10)); - assert(atLeast20(20)); - assert(atLeast20(25)); + it('behaves right curried when passed `undefined` for its first argument', function() { + var upTo20 = R.lte(__, 20); + assert(upTo20(10)); + assert(upTo20(20)); + assert(!upTo20(25)); }); it('throws when given no arguments', function() { @@ -222,6 +221,7 @@ describe('lte', function() { }); describe('gt', function() { + var __ = void 0; it('reports whether one item is less than another', function() { assert(!R.gt(3, 5)); assert(R.gt(6, 4)); @@ -230,20 +230,20 @@ describe('gt', function() { assert(R.gt('abcd', 'abc')); }); - it('is automatically right-curried', function() { - var gt20 = R.gt(20); + it('is curried', function() { + var lt20 = R.gt(20); + assert(lt20(10)); + assert(!lt20(20)); + assert(!lt20(25)); + }); + + it('behaves right curried when passed `undefined` for its first argument', function() { + var gt20 = R.gt(__, 20); assert(!gt20(10)); assert(!gt20(20)); assert(gt20(25)); }); - it('allows for left sections too', function() { - var upto20 = R.gt(20, _); - assert(upto20(10)); - assert(!upto20(20)); - assert(!upto20(25)); - }); - it('throws when given no arguments', function() { assert.throws(R.gt, TypeError); }); @@ -258,20 +258,21 @@ describe('gte', function() { assert(R.gte('abcd', 'abc')); }); - it('is automatically right-curried', function() { - var gte20 = R.gte(20); + it('is curried', function() { + var lte20 = R.gte(20); + assert(lte20(10)); + assert(lte20(20)); + assert(!lte20(25)); + }); + + it('behaves right curried when passed `undefined` for its first argument', function() { + var __ = void 0; + var gte20 = R.gte(__, 20); assert(!gte20(10)); assert(gte20(20)); assert(gte20(25)); }); - it('allows for left sections too', function() { - var upto20 = R.gte(20, _); - assert(upto20(10)); - assert(upto20(20)); - assert(!upto20(25)); - }); - it('throws when given no arguments', function() { assert.throws(R.gte, TypeError); });