Luka.js
// Produces unary functions.
function unary(operation) {
return Object.freeze(function (x) {
return operation(x);
});
}
// Produces binary functions.
function binary(operation) {
return Object.freeze(function (x, y) {
return operation(x, y);
});
}
// Produces functions that fold a set into a summary value.
function foldable(operation) {
return Object.freeze(function (...xs) {
return xs.reduce(
(total, x) => operation(total, x),
);
});
}
// "op" acts as namespace for arithmetic functions.
// Its null prototype prevents namespace pollution
// from inherited objects.
const op = Object.create(null);
// Unary Operations
op.neg = unary((x) => 0 - x);
// Binary Operations
op.add = foldable((x, y) => x + y);
op.sub = foldable((x, y) => x - y);
op.mul = foldable((x, y) => x * y);
op.div = foldable((x, y) => x / y);
op.exp = binary((x, y) => Math.pow(x, y));
op.rem = binary((x, y) => x % y);
// Make exported namespace immutable.
export default Object.freeze(op);
Tools:
Array.prototype.reduce()
Object.create()
Object.freeze()
Project:
A binary operation is a rule combining two elements of a set to
create a third. In arithmetic the most common way to represent
binary operations is infix notation, where the operator sits
between its two operands. But infix notation is ambiguous. It's
unclear whether 1 + 2 * 3
evaluates
(1 + 2) * 3
or 1 + (2 * 3)
, so
mathematicians use a set of conventions, the order of operations,
to resolve this confusion.
The order of operations, however, is no fixed thing. It's unclear whether unary negation precedes exponentiation, whether implied multiplication precedes explicit division. Almost every programming language has their own precedence table. Each is subtly — or drastically — different from the other.
I created the JavaScript library
Luka.js
to sidestep this confusion over binary operations. Luka.js
provides functional replacements for a handful of arithmetic
operators:
[+, -, *, /, **, %]
. Unlike its operators, JavaScript
functions are straightforward. They are parenthesized and strictly
applied, meaning they evaluate inward to outward precisely when
they are called. The ambiguous 1 + 2 * 3
becomes the
explicit add(1, mul(2, 3))
. Also: JavaScript
functions can have variable arity. While +
can input
only two arguments, add
can input
1
through n
arguments.
Notes:
-
The entire Luka.js API is contained within a null-inheriting, immutable object literal. The object keeps the API simple. All functions are kept within a single, unchangeable namespace. No pollution from the prototypal chain can obscure them.
-
JavaScript functions are also objects. By default, properties — even other functions — can be attached to a function object at anytime during the life of a program, potentially changing its output. My
unary
,binary
, andfoldable
factory functions produce immutable function objects to prevent this behavior from altering my API.