// Copyright (c) 2014 Quildreen Motta
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation files
// (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software,
// and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/**
* Provides JS operators as curried functions.
*
* @module lib/index
*/
// -- Dependencies -----------------------------------------------------
var curry = require('core.lambda').curry
var flip = require('core.lambda').flip
// -- Aliases ----------------------------------------------------------
var internalToString = Function.call.bind(Object.prototype.toString)
// -- Helpers ----------------------------------------------------------
/*
* Tests if something is an object
*
* @summary α → Boolean
*/
function isObject(a) {
return Object(a) === a
}
// -- Arithmetic -------------------------------------------------------
/**
* Addition.
*
* @example
* add(2)(3) // => 2 + 3 => 5
*
* @method
* @summary Number → Number → Number
*/
exports.add = curry(2, add)
function add(a, b) {
return a + b
}
/**
* Subtraction.
*
* @example
* subtract(2)(3) // => 2 - 3 => -1
*
* @method
* @summary Number → Number → Number
*/
exports.subtract = curry(2, subtract)
function subtract(a, b) {
return a - b
}
/**
* Division.
*
* @example
* divide(4)(2) // => 4 / 2 => 2
*
* @method
* @summary Number → Number → Number
*/
exports.divide = curry(2, divide)
function divide(a, b) {
return a / b
}
/**
* Multiplication.
*
* @example
* multiply(2)(3) // => 2 * 3 => 6
*
* @method
* @summary Number → Number → Number
*/
exports.multiply = curry(2, multiply)
function multiply(a, b) {
return a * b
}
/**
* Modulus.
*
* @example
* modulus(3)(2) // => 3 % 2 => 1
*
* @method
* @summary Number → Number → Number
*/
exports.modulus = curry(2, modulus)
function modulus(a, b) {
return a % b
}
/**
* Negation.
*
* @example
* negate(1) // => -1
*
* @method
* @summary Number → Number
*/
exports.negate = negate
function negate(a) {
return -a
}
/**
* Increment.
*
* @example
* increment(1) // => 2
*
* @method
* @summary Number → Number
*/
exports.increment = exports.add(1)
/**
* Decrement.
*
* @example
* decrement(2) // => 1
*
* @method
* @summary Number → Number
*/
exports.decrement = flip(exports.subtract)(1)
// -- Logical ----------------------------------------------------------
/**
* Logical negation.
*
* @example
* not(false) // => !false => true
*
* @method
* @summary Boolean → Boolean
*/
exports.not = not
function not(a) {
return !a
}
/**
* Logical conjunction.
*
* @example
* and(true, false) // => true && false => false
* and(true, true) // => true && true => true
*
* @method
* @summary Boolean → Boolean → Boolean
*/
exports.and = curry(2, and)
function and(a, b) {
return a && b
}
/**
* Logical disjunction.
*
* @example
* or(true, false) // => true || false => true
* or(false, false) // => false || false => false
*
* @method
* @summary Boolean → Boolean → Boolean
*/
exports.or = curry(2, or)
function or(a, b) {
return a || b
}
// -- Bitwise ----------------------------------------------------------
/**
* Bitwise negation.
*
* @example
* bitNot(0b110) // => ~0b110 => -0b111
*
* @method
* @summary Int → Int
*/
exports.bitNot = bitNot
function bitNot(a) {
return ~a
}
/**
* Bitwise conjunction.
*
* @example
* bitAnd(0b110, 0b101) // => 0b110 & 0b101 => 0b100
*
* @method
* @summary Int → Int → Int
*/
exports.bitAnd = curry(2, bitAnd)
function bitAnd(a, b) {
return a & b
}
/**
* Bitwise disjunction.
*
* @example
* bitOr(0b110, 0b101) // => 0b110 | 0b101 => 0b111
*
* @method
* @summary Int → Int → Int
*/
exports.bitOr = curry(2, bitOr)
function bitOr(a, b) {
return a | b
}
/**
* Bitwise exclusive disjunction.
*
* @example
* bitXor(0b1000, 0b0110) // => 0b1000 ^ 0b0110 => 0b1110
* bitXor(0b110, 0b101) // => 0b110 ^ 0b101 => 0b011
*
* @method
* @summary Int → Int → Int
*/
exports.bitXor = curry(2, bitXor)
function bitXor(a, b) {
return a ^ b
}
/**
* Bitwise left shift.
*
* @example
* bitShiftLeft(0b10, 2) // => 0b10 << 2 => 0b1000
*
* @method
* @summary Int → Int → Int
*/
exports.bitShiftLeft = curry(2, bitShiftLeft)
function bitShiftLeft(a, b) {
return a << b
}
/**
* Sign-propagating bitwise right shift.
*
* @example
* bitShiftRight(0b1000, 2) // => 0b1000 >> 2 => 0b10
*
* @method
* @summary Int → Int → Int
*/
exports.bitShiftRight = curry(2, bitShiftRight)
function bitShiftRight(a, b) {
return a >> b
}
/**
* Zero-fill bitwise right shift.
*
* @example
* bitUnsignedShiftRight(-0b1001, 2) // => -0b1001 >>> 2 => 0b111111111111111111111111111101
*
* @method
* @summary Int → Int → Int
*/
exports.bitUnsignedShiftRight = curry(2, bitUnsignedShiftRight)
function bitUnsignedShiftRight(a, b) {
return a >>> b
}
// -- Relational -------------------------------------------------------
/**
* Strict equality.
*
* @example
* equal(1, '1') // => 1 === '1' => false
* equal(1, 1) // => 1 === 1 => true
*
* @method
* @summary α → α → Boolean
*/
exports.equal = curry(2, equal)
function equal(a, b) {
return a === b
}
/**
* Strict inequality.
*
* @example
* notEqual(1, '1') // => 1 !== '1' => true
* notEqual(1, 1) // => 1 !== 1 => false
*
* @method
* @summary α → α → Boolean
*/
exports.notEqual = curry(2, notEqual)
function notEqual(a, b) {
return a !== b
}
/**
* Greater than.
*
* @example
* greaterThan(2, 3) // => 2 > 3 => false
*
* @method
* @summary Number → Number → Boolean
*/
exports.greaterThan = curry(2, greaterThan)
function greaterThan(a, b) {
return a > b
}
/**
* Greater or equal to.
*
* @example
* greaterOrEqualTo(2, 2) // => 2 >= 2 => true
*
* @method
* @summary Number → Number → Boolean
*/
exports.greaterOrEqualTo = curry(2, greaterOrEqualTo)
function greaterOrEqualTo(a, b) {
return a >= b
}
/**
* Less than.
*
* @example
* lessThan(2, 3) // => 2 < 3 => true
*
* @method
* @summary Number → Number → Boolean
*/
exports.lessThan = curry(2, lessThan)
function lessThan(a, b) {
return a < b
}
/**
* Less or equal to.
*
* @example
* lessOrEqualTo(2, 3) // => 2 <= 3 => true
*
* @method
* @summary Number → Number → Boolean
*/
exports.lessOrEqualTo = curry(2, lessOrEqualTo)
function lessOrEqualTo(a, b) {
return a <= b
}
// -- Special ----------------------------------------------------------
/**
* Property accessor.
*
* @example
* get('foo', { foo: 1 }) // => ({ foo: 1 })['foo'] => 1
*
* @method
* @summary String → Object → α | Void
*/
exports.get = curry(2, get)
function get(key, object) {
return object[key]
}
/**
* Tests the existence of a property in an object.
*
* @example
* has('foo', { foo: 1 }) // => 'foo' in { foo: 1 } => true
*
* @method
* @summary String → Object → Boolean
*/
exports.has = curry(2, has)
function has(key, object) {
return key in object
}
/**
* Instance check.
*
* @example
* isInstance(Array, [1]) // => [1] instanceof Array => true
*
* @method
* @summary Function → Object → Boolean
*/
exports.isInstance = curry(2, isInstance)
function isInstance(constructor, a) {
return a instanceof constructor
}
/**
* Constructs new objects.
*
* @example
* create(Array, 'foo') // => new Array('foo') => ['foo']
*
* @method
* @summary (new(α₁, α₂, ..., αₙ) → β) → (α₁, α₂, ..., αₙ) → β
*/
exports.create = create
function create(constructor) {
return function() {
var a = Object.create(constructor.prototype)
var b = constructor.apply(a, arguments)
return isObject(b)? b
: /* otherwise */ a }
}
/**
* Returns the internal type of the object.
*
* @example
* typeOf('foo') // => typeof 'foo' => 'string'
*
* @method
* @summary α → String
*/
exports.typeOf = typeOf
function typeOf(a) {
return typeof a
}
/**
* Returns the internal `[[Class]]` of the object.
*
* @example
* classOf('foo') // => {}.toString.call('foo') => 'String'
*
* @method
* @summary α → String
*/
exports.classOf = classOf
function classOf(a) {
return a === undefined? 'Undefined'
: a === null? 'Null'
: /* otherwise */ internalToString(a).slice(8, -1)
}