Lambda.js are string based lambdas for Node.js and the browser, that allow strings such as
'x+1'
and 'x -> x+1'
to be used as functions.
This is a spin-off project of Functional's (a library for functional programming in JavaScript) to-function.js by Oliver Steele.
Most of the source code and documentation is written by Oliver Steele and
contributers, so all credit goes to them. This project is just here to avoid
using the full library when only lambdas are needed (they play very
well with JavaScript 1.6's every()
, filter()
, forEach()
etc). It also
detaches the lambda function from String.prototype
to avoid cluttering it
with non-standard functions.
The only exported function is lambda(expression)
which takes the "string
based lambda" as argument and turns that expression into a Function
that
returns the value of the expression:
var square = lambda('x*x');
console.log(square.toString());
/* =>
function anonymous(x) {
return x * x;
}
*/
If the string contains a ->
, this separates the parameters from the body:
lambda('x -> x + 1')(1); // => 2
lambda('x y -> x + 2*y')(1, 2); // => 5
lambda('x, y -> x + 2*y')(1, 2); // => 5
Otherwise, if the string contains a _
, this is the only parameter:
lambda('_ + 1')(1); // => 2
If the string begins or ends with an operator or relation, prepend or append a
parameter (The documentation refers to this type of string as a section
):
lambda('/2')(4); // => 2
lambda('2/')(4); // => 0.5
lambda('/')(2, 4); // => 0.5
Sections can end, but not begin with, -
. (This is to avoid interpreting e.g.
-2*x
as a section). On the other hand, a string that either begins or ends
with /
is a section, so an expression that begins or ends with a regular
expression literal needs an explicit parameter.
Otherwise, each variable name is an implicit parameter:
lambda('x + 1')(1); // => 2
lambda('x + 2*y')(1, 2); // => 5
lambda('y + 2*x')(1, 2); // => 5
Implicit parameter detection ignores strings literals, variable names that
start with capitals and identifiers that precede :
or follow .
:
['probable', 'possible'].map(lambda('"im" + root')); // => ["improbable", "impossible"]
lambda('Math.cos(angle)')(Math.PI); // => -1
lambda('point.x')({x:1, y:2}); // => 1
lambda('({x:1, y:2})[key]')('x'); // => 1
Implicit parameter detection mistakenly looks inside regular expression literals for variable names. It also doesn't know to ignore JavaScript keywords and bound variables. (The only way you can get these last two is with a function literal inside the string. This is outside the intended use case for string lambdas.)
Use _
(to define a unary function) or ->
, if the string contains anything
that looks like a free variable but shouldn't be used as a parameter, or to
specify parameters that are ordered differently from their first occurrence in
the string.
Chain ->
s to create a function in uncurried form:
lambda('x -> y -> x + 2*y')(1)(2); // => 5
lambda('x -> y -> z -> x + 2*y+3*z')(1)(2)(3) // => 14