or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

function-functions.mdindex.mdlist-functions.mdmath-logic.mdobject-functions.mdstring-type.md

math-logic.mddocs/

0

# Math & Logic Functions

1

2

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.

3

4

## Mathematical Operations

5

6

### Basic Arithmetic

7

8

```javascript { .api }

9

// Addition (curried)

10

R.add(2, 3); // => 5

11

R.add(7)(10); // => 17

12

13

const increment = R.add(1);

14

increment(5); // => 6

15

16

// Subtraction (a - b)

17

R.subtract(10, 3); // => 7

18

R.subtract(R.__, 5)(12); // => 7 (12 - 5)

19

20

const minus10 = R.subtract(R.__, 10);

21

minus10(25); // => 15 (25 - 10)

22

23

// Multiplication

24

R.multiply(3, 4); // => 12

25

const double = R.multiply(2);

26

double(8); // => 16

27

28

// Division (a / b)

29

R.divide(10, 2); // => 5

30

const half = R.divide(R.__, 2);

31

half(20); // => 10

32

33

const reciprocal = R.divide(1);

34

reciprocal(4); // => 0.25 (1/4)

35

```

36

37

### Advanced Math Operations

38

39

```javascript { .api }

40

// Increment/Decrement

41

R.inc(5); // => 6

42

R.dec(5); // => 4

43

44

// Useful in transformations

45

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

46

47

// Modulo operations

48

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

49

R.modulo(-17, 3); // => -2 (preserves sign)

50

51

// Mathematical modulo (always positive)

52

R.mathMod(17, 5); // => 2

53

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

54

55

const isEven = R.pipe(R.modulo(R.__, 2), R.equals(0));

56

isEven(4); // => true

57

isEven(5); // => false

58

59

// Negation

60

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

61

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

62

63

const invertSigns = R.map(R.negate);

64

invertSigns([1, -2, 3]); // => [-1, 2, -3]

65

```

66

67

### Array Aggregations

68

69

```javascript { .api }

70

// Sum array elements

71

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

72

R.sum([]); // => 0

73

74

// Product of array elements

75

R.product([2, 4, 6]); // => 48

76

R.product([2, 4, 6, 0]); // => 0

77

R.product([]); // => 1

78

79

// Mean (average)

80

R.mean([2, 7, 9]); // => 6

81

R.mean([1, 2, 3, 4, 5]); // => 3

82

R.mean([]); // => NaN

83

84

// Median (middle value)

85

R.median([2, 9, 7]); // => 7

86

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

87

R.median([]); // => NaN

88

89

// Real-world example: statistical analysis

90

const analyzeScores = R.applySpec({

91

count: R.length,

92

total: R.sum,

93

average: R.mean,

94

median: R.median,

95

range: R.converge(R.subtract, [

96

R.apply(Math.max),

97

R.apply(Math.min)

98

])

99

});

100

101

const scores = [85, 92, 78, 96, 88];

102

analyzeScores(scores);

103

// => {count: 5, total: 439, average: 87.8, median: 88, range: 18}

104

```

105

106

## Comparison Functions

107

108

### Basic Comparisons

109

110

```javascript { .api }

111

// Greater than

112

R.gt(2, 1); // => true

113

R.gt(1, 2); // => false

114

R.gt('z', 'a'); // => true (lexicographic)

115

116

const isPositive = R.gt(R.__, 0);

117

isPositive(5); // => true

118

isPositive(-3); // => false

119

120

// Greater than or equal

121

R.gte(2, 2); // => true

122

R.gte(3, 2); // => true

123

R.gte(1, 2); // => false

124

125

// Less than

126

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

127

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

128

129

const isBelowLimit = R.lt(R.__, 100);

130

isBelowLimit(75); // => true

131

132

// Less than or equal

133

R.lte(2, 2); // => true

134

R.lte(1, 2); // => true

135

R.lte(3, 2); // => false

136

137

// Min/Max

138

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

139

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

140

141

// With custom comparison function

142

R.minBy(R.length, 'cat', 'elephant'); // => 'cat'

143

R.maxBy(R.prop('age'),

144

{name: 'Alice', age: 30},

145

{name: 'Bob', age: 25}

146

); // => {name: 'Alice', age: 30}

147

```

148

149

### Equality and Identity

150

151

```javascript { .api }

152

// Deep equality (R.equals)

153

R.equals(1, 1); // => true

154

R.equals([1, 2], [1, 2]); // => true

155

R.equals({a: 1}, {a: 1}); // => true

156

R.equals(NaN, NaN); // => true

157

158

// Handles circular references

159

const a = {}; a.self = a;

160

const b = {}; b.self = b;

161

R.equals(a, b); // => true

162

163

// Reference equality (identical memory location)

164

R.identical(1, 1); // => true

165

R.identical([], []); // => false (different objects)

166

R.identical(NaN, NaN); // => true

167

R.identical(0, -0); // => false

168

169

const obj = {};

170

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

171

172

// Property equality

173

R.eqProps('name',

174

{name: 'John', age: 30},

175

{name: 'John', age: 25}

176

); // => true

177

178

// Equality by transformation

179

R.eqBy(Math.abs, 5, -5); // => true

180

R.eqBy(R.length, 'cat', 'dog'); // => true

181

```

182

183

### Range and Boundary Operations

184

185

```javascript { .api }

186

// Clamp value to range

187

R.clamp(1, 10, 15); // => 10 (clamped to max)

188

R.clamp(1, 10, -5); // => 1 (clamped to min)

189

R.clamp(1, 10, 5); // => 5 (within range)

190

191

const clampPercent = R.clamp(0, 100);

192

clampPercent(150); // => 100

193

clampPercent(-10); // => 0

194

195

// Property-based comparisons

196

const users = [

197

{name: 'Alice', score: 85},

198

{name: 'Bob', score: 92},

199

{name: 'Carol', score: 78}

200

];

201

202

const highScorer = R.reduce(R.maxBy(R.prop('score')), users[0], users);

203

// => {name: 'Bob', score: 92}

204

```

205

206

## Logic Functions

207

208

### Basic Boolean Operations

209

210

```javascript { .api }

211

// Logical AND (short-circuited)

212

R.and(true, true); // => true

213

R.and(true, false); // => false

214

R.and(false, 'anything'); // => false

215

R.and('truthy', 'value'); // => 'value'

216

217

// Logical OR (short-circuited)

218

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

219

R.or(false, 'default'); // => 'default'

220

R.or('first', 'second'); // => 'first'

221

222

// Logical NOT

223

R.not(true); // => false

224

R.not(false); // => true

225

R.not('truthy'); // => false

226

R.not(''); // => true

227

R.not(0); // => true

228

229

// XOR (exclusive or)

230

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

231

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

232

R.xor(false, false); // => false

233

234

// Create negated function (complement)

235

const isEven = x => x % 2 === 0;

236

const isOdd = R.complement(isEven);

237

isOdd(3); // => true

238

isOdd(4); // => false

239

240

// Use in filtering

241

const nonEmptyStrings = R.filter(R.complement(R.isEmpty), ['', 'hello', '', 'world']);

242

// => ['hello', 'world']

243

244

// Real-world example: feature flags

245

const hasFeature = R.both(

246

R.prop('enabled'),

247

R.pipe(R.prop('userLevel'), R.gte(R.__, 'premium'))

248

);

249

```

250

251

### Predicate Combinators

252

253

```javascript { .api }

254

// Both predicates must be true

255

const isAdultUser = R.both(

256

R.propSatisfies(R.gte(R.__, 18), 'age'),

257

R.propEq(true, 'active')

258

);

259

260

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

261

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

262

263

isAdultUser(user1); // => true

264

isAdultUser(user2); // => false

265

266

// Either predicate can be true

267

const isSpecialUser = R.either(

268

R.propEq('admin', 'role'),

269

R.propSatisfies(R.gt(R.__, 1000), 'points')

270

);

271

272

const admin = {role: 'admin', points: 100};

273

const vip = {role: 'user', points: 1500};

274

const regular = {role: 'user', points: 50};

275

276

isSpecialUser(admin); // => true (is admin)

277

isSpecialUser(vip); // => true (high points)

278

isSpecialUser(regular); // => false

279

280

// All predicates must pass

281

const isValidProduct = R.allPass([

282

R.has('name'),

283

R.has('price'),

284

R.propSatisfies(R.gt(R.__, 0), 'price'),

285

R.propSatisfies(R.complement(R.isEmpty), 'name')

286

]);

287

288

// Any predicate can pass

289

const isSearchable = R.anyPass([

290

R.has('title'),

291

R.has('description'),

292

R.has('tags')

293

]);

294

295

// Complement (logical NOT for predicates)

296

const isNotEmpty = R.complement(R.isEmpty);

297

const isNotNil = R.complement(R.isNil);

298

299

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

300

isNotNil('value'); // => true

301

```

302

303

### Conditional Logic

304

305

```javascript { .api }

306

// If-then-else logic

307

const processValue = R.ifElse(

308

R.is(Number), // condition

309

R.multiply(2), // if true: double it

310

R.always('Not a number') // if false: return message

311

);

312

313

processValue(5); // => 10

314

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

315

316

// Multi-condition logic with cond

317

const categorizeScore = R.cond([

318

[R.gte(R.__, 90), R.always('A')],

319

[R.gte(R.__, 80), R.always('B')],

320

[R.gte(R.__, 70), R.always('C')],

321

[R.gte(R.__, 60), R.always('D')],

322

[R.T, R.always('F')] // default case

323

]);

324

325

categorizeScore(95); // => 'A'

326

categorizeScore(75); // => 'C'

327

categorizeScore(45); // => 'F'

328

329

// When/Unless - conditional transformations

330

const processPositive = R.when(

331

R.gt(R.__, 0), // condition: is positive

332

R.multiply(10) // transformation: multiply by 10

333

);

334

335

processPositive(5); // => 50

336

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

337

338

const avoidNegative = R.unless(

339

R.gt(R.__, 0), // condition: is positive

340

R.always(0) // transformation: set to 0

341

);

342

343

avoidNegative(5); // => 5 (unchanged)

344

avoidNegative(-3); // => 0

345

```

346

347

### Default Values and Fallbacks

348

349

```javascript { .api }

350

// Default value for null/undefined/NaN

351

R.defaultTo(42, null); // => 42

352

R.defaultTo(42, undefined); // => 42

353

R.defaultTo(42, NaN); // => 42

354

R.defaultTo(42, 5); // => 5

355

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

356

357

// Safe property access with defaults

358

const getUserName = R.pipe(

359

R.prop('user'),

360

R.prop('name'),

361

R.defaultTo('Anonymous')

362

);

363

364

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

365

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

366

getUserName({}); // => 'Anonymous'

367

368

// Chain of fallbacks

369

const getDisplayName = R.pipe(

370

R.anyPass([R.prop('displayName'), R.prop('username'), R.prop('email')]),

371

R.defaultTo('User')

372

);

373

```

374

375

### Validation and Testing

376

377

```javascript { .api }

378

// Test conditions on data

379

const isValidEmail = R.allPass([

380

R.is(String),

381

R.test(/@/),

382

R.test(/\./),

383

R.complement(R.isEmpty)

384

]);

385

386

isValidEmail('user@example.com'); // => true

387

isValidEmail('invalid-email'); // => false

388

389

// Property validation

390

R.propSatisfies(R.gt(R.__, 0), 'age', {age: 25}); // => true

391

R.propSatisfies(R.is(String), 'name', {name: 'John'}); // => true

392

393

// Path validation for nested objects

394

R.pathSatisfies(R.is(Number), ['profile', 'age'], {

395

profile: {age: 30}

396

}); // => true

397

398

// Complex validation example

399

const validateUser = R.where({

400

email: isValidEmail,

401

age: R.both(R.is(Number), R.gte(R.__, 13)),

402

name: R.both(R.is(String), R.complement(R.isEmpty)),

403

terms: R.equals(true)

404

});

405

406

const user = {

407

email: 'user@example.com',

408

age: 25,

409

name: 'John Doe',

410

terms: true

411

};

412

413

validateUser(user); // => true

414

```

415

416

### Loop-Like Operations

417

418

```javascript { .api }

419

// Until condition is met

420

const collatz = R.until(

421

R.equals(1), // stop when value equals 1

422

R.ifElse(

423

R.modulo(R.__, 2), // if odd

424

R.pipe(R.multiply(3), R.add(1)), // 3n + 1

425

R.divide(R.__, 2) // else n/2

426

)

427

);

428

429

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

430

431

// Iterative application

432

const approach = R.until(

433

R.lt(R.__, 0.001), // stop when difference < 0.001

434

R.multiply(0.9) // multiply by 0.9 each iteration

435

);

436

437

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

438

```

439

440

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.