CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-ramda

A practical functional library for JavaScript programmers.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

math-logic.mddocs/

Math & Logic Functions

Ramda provides 58 functions for mathematical operations and logical reasoning. These include 13 math functions for numerical computations, 19 logic functions for conditional logic, and 26 relation functions for comparisons and boolean operations.

Mathematical Operations

Basic Arithmetic

// Addition (curried)
R.add(2, 3);           // => 5
R.add(7)(10);          // => 17

const increment = R.add(1);
increment(5);          // => 6

// Subtraction (a - b)  
R.subtract(10, 3);     // => 7
R.subtract(R.__, 5)(12); // => 7 (12 - 5)

const minus10 = R.subtract(R.__, 10);
minus10(25);           // => 15 (25 - 10)

// Multiplication
R.multiply(3, 4);      // => 12
const double = R.multiply(2);
double(8);             // => 16

// Division (a / b)
R.divide(10, 2);       // => 5  
const half = R.divide(R.__, 2);
half(20);              // => 10

const reciprocal = R.divide(1);
reciprocal(4);         // => 0.25 (1/4)

Advanced Math Operations

// Increment/Decrement
R.inc(5);              // => 6
R.dec(5);              // => 4

// Useful in transformations
R.map(R.inc, [1, 2, 3]); // => [2, 3, 4]

// Modulo operations
R.modulo(17, 3);       // => 2 (JavaScript-style: 17 % 3)
R.modulo(-17, 3);      // => -2 (preserves sign)

// Mathematical modulo (always positive)
R.mathMod(17, 5);      // => 2
R.mathMod(-17, 5);     // => 3 (mathematical modulo)

const isEven = R.pipe(R.modulo(R.__, 2), R.equals(0));
isEven(4);             // => true
isEven(5);             // => false

// Negation
R.negate(42);          // => -42
R.negate(-42);         // => 42

const invertSigns = R.map(R.negate);
invertSigns([1, -2, 3]); // => [-1, 2, -3]

Array Aggregations

// Sum array elements
R.sum([1, 2, 3, 4]);        // => 10
R.sum([]);                  // => 0

// Product of array elements  
R.product([2, 4, 6]);       // => 48
R.product([2, 4, 6, 0]);    // => 0
R.product([]);              // => 1

// Mean (average)
R.mean([2, 7, 9]);          // => 6
R.mean([1, 2, 3, 4, 5]);    // => 3
R.mean([]);                 // => NaN

// Median (middle value)
R.median([2, 9, 7]);        // => 7
R.median([7, 2, 10, 9]);    // => 8 (average of middle two)
R.median([]);               // => NaN

// Real-world example: statistical analysis
const analyzeScores = R.applySpec({
  count: R.length,
  total: R.sum,
  average: R.mean,
  median: R.median,
  range: R.converge(R.subtract, [
    R.apply(Math.max),
    R.apply(Math.min)
  ])
});

const scores = [85, 92, 78, 96, 88];
analyzeScores(scores);
// => {count: 5, total: 439, average: 87.8, median: 88, range: 18}

Comparison Functions

Basic Comparisons

// Greater than
R.gt(2, 1);            // => true
R.gt(1, 2);            // => false  
R.gt('z', 'a');        // => true (lexicographic)

const isPositive = R.gt(R.__, 0);
isPositive(5);         // => true
isPositive(-3);        // => false

// Greater than or equal
R.gte(2, 2);           // => true
R.gte(3, 2);           // => true
R.gte(1, 2);           // => false

// Less than  
R.lt(1, 2);            // => true
R.lt(2, 1);            // => false

const isBelowLimit = R.lt(R.__, 100);
isBelowLimit(75);      // => true

// Less than or equal
R.lte(2, 2);           // => true
R.lte(1, 2);           // => true
R.lte(3, 2);           // => false

// Min/Max
R.min(5, 3);           // => 3
R.max(5, 3);           // => 5

// With custom comparison function
R.minBy(R.length, 'cat', 'elephant'); // => 'cat'
R.maxBy(R.prop('age'), 
  {name: 'Alice', age: 30}, 
  {name: 'Bob', age: 25}
); // => {name: 'Alice', age: 30}

Equality and Identity

// Deep equality (R.equals)
R.equals(1, 1);                    // => true
R.equals([1, 2], [1, 2]);          // => true
R.equals({a: 1}, {a: 1});          // => true
R.equals(NaN, NaN);                // => true

// Handles circular references
const a = {}; a.self = a;
const b = {}; b.self = b;  
R.equals(a, b);                    // => true

// Reference equality (identical memory location)
R.identical(1, 1);                 // => true
R.identical([], []);               // => false (different objects)
R.identical(NaN, NaN);             // => true
R.identical(0, -0);                // => false

const obj = {};
R.identical(obj, obj);             // => true

// Property equality
R.eqProps('name', 
  {name: 'John', age: 30}, 
  {name: 'John', age: 25}
);                                 // => true

// Equality by transformation
R.eqBy(Math.abs, 5, -5);          // => true
R.eqBy(R.length, 'cat', 'dog');   // => true

Range and Boundary Operations

// Clamp value to range
R.clamp(1, 10, 15);        // => 10 (clamped to max)
R.clamp(1, 10, -5);        // => 1 (clamped to min)  
R.clamp(1, 10, 5);         // => 5 (within range)

const clampPercent = R.clamp(0, 100);
clampPercent(150);         // => 100
clampPercent(-10);         // => 0

// Property-based comparisons
const users = [
  {name: 'Alice', score: 85},
  {name: 'Bob', score: 92},
  {name: 'Carol', score: 78}
];

const highScorer = R.reduce(R.maxBy(R.prop('score')), users[0], users);
// => {name: 'Bob', score: 92}

Logic Functions

Basic Boolean Operations

// Logical AND (short-circuited)
R.and(true, true);         // => true
R.and(true, false);        // => false
R.and(false, 'anything');  // => false
R.and('truthy', 'value');  // => 'value'

// Logical OR (short-circuited)  
R.or(true, false);         // => true
R.or(false, 'default');    // => 'default'
R.or('first', 'second');   // => 'first'

// Logical NOT
R.not(true);               // => false
R.not(false);              // => true
R.not('truthy');           // => false
R.not('');                 // => true
R.not(0);                  // => true

// XOR (exclusive or)
R.xor(true, false);        // => true
R.xor(true, true);         // => false
R.xor(false, false);       // => false

// Create negated function (complement)
const isEven = x => x % 2 === 0;
const isOdd = R.complement(isEven);
isOdd(3);                  // => true
isOdd(4);                  // => false

// Use in filtering
const nonEmptyStrings = R.filter(R.complement(R.isEmpty), ['', 'hello', '', 'world']);
// => ['hello', 'world']

// Real-world example: feature flags
const hasFeature = R.both(
  R.prop('enabled'),
  R.pipe(R.prop('userLevel'), R.gte(R.__, 'premium'))
);

Predicate Combinators

// Both predicates must be true
const isAdultUser = R.both(
  R.propSatisfies(R.gte(R.__, 18), 'age'),
  R.propEq(true, 'active')
);

const user1 = {age: 25, active: true};
const user2 = {age: 16, active: true};

isAdultUser(user1);        // => true
isAdultUser(user2);        // => false

// Either predicate can be true
const isSpecialUser = R.either(
  R.propEq('admin', 'role'),
  R.propSatisfies(R.gt(R.__, 1000), 'points')
);

const admin = {role: 'admin', points: 100};
const vip = {role: 'user', points: 1500}; 
const regular = {role: 'user', points: 50};

isSpecialUser(admin);      // => true (is admin)
isSpecialUser(vip);        // => true (high points)
isSpecialUser(regular);    // => false

// All predicates must pass
const isValidProduct = R.allPass([
  R.has('name'),
  R.has('price'),  
  R.propSatisfies(R.gt(R.__, 0), 'price'),
  R.propSatisfies(R.complement(R.isEmpty), 'name')
]);

// Any predicate can pass
const isSearchable = R.anyPass([
  R.has('title'),
  R.has('description'), 
  R.has('tags')
]);

// Complement (logical NOT for predicates)
const isNotEmpty = R.complement(R.isEmpty);
const isNotNil = R.complement(R.isNil);

isNotEmpty([1, 2, 3]);     // => true
isNotNil('value');         // => true

Conditional Logic

// If-then-else logic
const processValue = R.ifElse(
  R.is(Number),              // condition
  R.multiply(2),             // if true: double it
  R.always('Not a number')   // if false: return message
);

processValue(5);           // => 10
processValue('hello');     // => 'Not a number'

// Multi-condition logic with cond
const categorizeScore = R.cond([
  [R.gte(R.__, 90), R.always('A')],
  [R.gte(R.__, 80), R.always('B')], 
  [R.gte(R.__, 70), R.always('C')],
  [R.gte(R.__, 60), R.always('D')],
  [R.T, R.always('F')]               // default case
]);

categorizeScore(95);       // => 'A'
categorizeScore(75);       // => 'C'
categorizeScore(45);       // => 'F'

// When/Unless - conditional transformations
const processPositive = R.when(
  R.gt(R.__, 0),             // condition: is positive
  R.multiply(10)             // transformation: multiply by 10
);

processPositive(5);        // => 50
processPositive(-3);       // => -3 (unchanged)

const avoidNegative = R.unless(
  R.gt(R.__, 0),             // condition: is positive
  R.always(0)                // transformation: set to 0
);

avoidNegative(5);          // => 5 (unchanged)
avoidNegative(-3);         // => 0

Default Values and Fallbacks

// Default value for null/undefined/NaN
R.defaultTo(42, null);         // => 42
R.defaultTo(42, undefined);    // => 42
R.defaultTo(42, NaN);          // => 42
R.defaultTo(42, 5);            // => 5
R.defaultTo(42, false);        // => false (not null/undefined/NaN)

// Safe property access with defaults
const getUserName = R.pipe(
  R.prop('user'),
  R.prop('name'),
  R.defaultTo('Anonymous')
);

getUserName({user: {name: 'Alice'}}); // => 'Alice'
getUserName({user: {}});              // => 'Anonymous'
getUserName({});                      // => 'Anonymous'

// Chain of fallbacks  
const getDisplayName = R.pipe(
  R.anyPass([R.prop('displayName'), R.prop('username'), R.prop('email')]),
  R.defaultTo('User')
);

Validation and Testing

// Test conditions on data
const isValidEmail = R.allPass([
  R.is(String),
  R.test(/@/),
  R.test(/\./),
  R.complement(R.isEmpty)
]);

isValidEmail('user@example.com');  // => true
isValidEmail('invalid-email');     // => false

// Property validation
R.propSatisfies(R.gt(R.__, 0), 'age', {age: 25});     // => true
R.propSatisfies(R.is(String), 'name', {name: 'John'}); // => true

// Path validation for nested objects
R.pathSatisfies(R.is(Number), ['profile', 'age'], {
  profile: {age: 30}
});                                // => true

// Complex validation example
const validateUser = R.where({
  email: isValidEmail,
  age: R.both(R.is(Number), R.gte(R.__, 13)),
  name: R.both(R.is(String), R.complement(R.isEmpty)),
  terms: R.equals(true)
});

const user = {
  email: 'user@example.com',
  age: 25, 
  name: 'John Doe',
  terms: true
};

validateUser(user);            // => true

Loop-Like Operations

// Until condition is met
const collatz = R.until(
  R.equals(1),                 // stop when value equals 1
  R.ifElse(
    R.modulo(R.__, 2),         // if odd
    R.pipe(R.multiply(3), R.add(1)), // 3n + 1
    R.divide(R.__, 2)          // else n/2
  )
);

collatz(7);                    // => 1 (goes through: 7→22→11→34→17→52→26→13→40→20→10→5→16→8→4→2→1)

// Iterative application
const approach = R.until(
  R.lt(R.__, 0.001),          // stop when difference < 0.001
  R.multiply(0.9)              // multiply by 0.9 each iteration  
);

approach(10);                  // => 0.0008748... (approaches 0)

These math and logic functions provide the building blocks for complex calculations, data validation, conditional processing, and algorithmic operations within Ramda's functional programming paradigm.

Install with Tessl CLI

npx tessl i tessl/npm-ramda

docs

function-functions.md

index.md

list-functions.md

math-logic.md

object-functions.md

string-type.md

tile.json