funcrithmetic
v0.0.3
Published
Monadic wrapper for doing arithmetic operations in JavaScript
Downloads
8
Maintainers
Readme
funcrithmetic
Monadic wrapper for doing arithmetic operations in JavaScript
Goal
The main goal of funcrithmetic
is to facilitate writing conventional arithmetic equations in a more straightforward way:
const goldenSection = (Math.sqrt(5) + 1) / 2
// vs.
const goldenSection = FR.of(5)
.sqr()
.add(1)
.div(2)
.valueOf()
// => 1.618033988749895
The module aims to expose arithmetic operators in an easy-to-use fashion as well as acting as a Maybe Monad. If the term "Maybe Monad" throws you off, or the terms "Applicative" and "Functor" mean nothing to you, don't worry. You don't need to care all that much about these extra capabilities. The module can be used without ever touching this part of the API.
It is however worth noting that because funcrithmetic
is a "Maybe Monad", it guards you against non-number values, including undefined
and null
(more on this later).
Usage
To use funcrithmetic
, an "entry point" for the arithmetic equation is picked - in this case the 5
- and the subsequent operators are chained in the desired order. The more complicated the equation is, the more the simplicity of the chain notation becomes apparent:
const truncatedPentagon = Math.sqrt((5 - Math.sqrt(5)) / 2)
// vs.
const truncatedPentagon = FR.of(5)
.sqrt()
.subFrom(5)
.div(2)
.sqrt()
.valueOf()
// => 1.1755705045849463
Notice the FR.of
in the beginning of the expression? This is how values are "lifted" into the wrapper in order to get access to the arithmetic methods on it. Similarly the .valueOf()
unwraps the value again:
const wrappedFive = FR.of(5)
// => FR(5)
const wrappedTwentyFive = wrappedFive.sqr()
// => FR(25)
const wrappedTwenty = wrappedTwentyFive.sub(5)
// => FR(20)
const twenty = wrappedTwenty.valueOf()
// => 20
That's basically it.
.of(x)
: lifts a value into the wrapper..valueOf()
: unwraps the value again.
The exposed arithmetic methods on the wrapped value are:
.add(x)
: addsx
to the value..dec()
: decreases the value by1
..div(x)
: divides the value byx
..inc()
: increases the value by1
..exp(x)
: exponentiates the value byx
..mul(x)
: multiplies the value byx
..neg()
: negates the value..sub(x)
: subtractsx
from the value..subFrom(x)
: subtracts the value fromx
..sqr()
: squares the value..sqrt()
: calculates the square root of the value.
Guarding against non-numbers
In order to be able to chain methods as long as you want without worrying about e.g. undefined
or NaN
, funcrithmetic
guards against any non-number values internally:
FR.of('foo').add(2).valueOf()
// => undefined
FR.of(2).add('foo').valueOf()
// => undefined
FR.of(2).div(0).valueOf()
// => undefined
FR.of(-4).sqrt().valueOf()
// => undefined
Note that funcrithmetic
regards Infinity
and NaN
as non-numbers. This is why FR.of(2).div(0).valueOf()
doesn't yield Infinity
and FR.of(-4).sqrt().valueOf()
doesn't yield NaN
.
Advanced usage
Because funcrithmetic
is monadic, some extra methods are exist on the wrapper:
.map(f)
: takes any functionf
and applies it to the value..chain(f)
: takes any functionf
that returns afuncrithmetic
wrapper and applies it to the value..ap(fr)
: applies a wrapper to another wrapper that holds a function.
Using .map
:
const res = FR.of(64).map(x => Math.sqrt(x) * 2 + 5).valueOf()
// => 21
Using .chain
:
const res = FR.of(10).chain(x => FR.of(x * x)).valueOf()
// => 100
Using .ap
:
const add = a => b => a + b
const res = FR.of(add)
.ap(FR.of(3).sqr())
.ap(FR.of(4).sqr())
.sqrt()
.valueOf()
// => 5
Note that the function has to be curried in order to apply the wrappers one by one.
Installation
The module is distributed via npm:
npm install funcrithmetic
And can be imported as a ES2015 module or CommonJS module depending on you setup:
import FR from 'funcrithmetic'
const FR = require('funcrithmetic')
Development
Run tests on watch mode:
npm run dev
Run tests and ensure proper code formatting:
npm test
Automatically format the source code including tests:
npm run prettier