Package com.singularsys.extensions.lambda
Anonymous lambda functions and higher order functions.
Anonymous functions can be defined using the syntax x=>x^2 or [x,y]=>x+y
and assigned to variable Square = x=>x^2.
Various higher order functions take these as arguments. The
standard set of functions define in LambdaFunctionSet include:
applyapplies the function once. For exampleapply([x,y]=>x^y,5,2)defineturns a lambda function into a regular function.define("sq",x=>x^2); sq(5).iterategenerate a sequence:iterate(2, n=>n+2, n=>n<100)mapapplies the function to each element of a list and returns a list. For examplemap(x=>x^2,[1,2,3,4,5])produces a set of squares.sortsorts a sequence. For examplesort([x,y]=>x - y,[3,2,7,6,8])filterapplies a filter to a list, returns the elements which meet a condition:filter(x=>x%2==0,[1,2,3,4,5])mergemerge two sequences element by element:merge([x,y]=>x^y,[1,2,3,4,5],[2,2,2,2,2])whiletakes elements from a sequence while a condition is true. For examplewhile(x=>x<5,[1,2,3,4,5,6,7,8,9,10])foldcombines the elements of a sequence. It takes a two argument lambda function, an applies it to first two elements of the sequence, it then applies the function to the result and the third element. A sum of elements is simplyfold([x,y]=>x+y,[1,2,3,4,5]).foldOrcombines the elements of a sequence, with a default value for an empty list:foldOr([x,y]=>x+y,-1,[1,2,3,4,5])foldOr([x,y]=>x+y,-1,[]).reducecombines the elements of a sequence, with an initial identity value:reduce([x,y]=>x*y,1,[1,2,3,4,5]).
Some functions act on sequences but do not take lambda functions as arguments. These include:
firstfinds the first element of a list.first([1,2,3])firstOrfinds the first element of a list or return a default value.firstOr(-1,[1,2,3])lastfinds the last element of a list.last([1,2,3])limitlimits the number of elements in a list.limit(3,[1,2,3,4,5])skipskips the first n elements in a list.skip(3,[1,2,3,4,5])minandmaxfind the minimum and maximum element of a list and a couple of classes to build
Each of these function is created using
one of the classes in this package.
For example map is created using the LambdaMap class, and fold is created using the Fold class.
Other classes ExternalMap, ExternalFilter and ExternalSort
allow maps and filter and sorting algorithms to be constructed from an
UnaryFunction
and Comparator instances.
TerminalFunction and TerminalNaryBinaryFunction
are used to create aggregator functions from
NaryBinaryFunction
and PostfixMathCommand which take a variable number of arguments.
These will take a list and produce a single value.
The LambdaFunGenerator PostfixMathCommand is used to implement
the lambda functions definition operator =>
which allows lambda functions to be defined with the syntax x=>x^2
for unary function, [x,y]=>x^y for binary functions, []=>7
for nullary function. For vector and matrix arguments pattern matching
can be used to refer to individual elements. For example
[[x1,x2],[y1,y2]] => x1*y1+x2*y2 for a dot product operator.
[[x1,x2],[y1,y2]] => x1*y1+x2*y2
On evaluation this creates a LambdaFunction PostfixMathCommand
which is itself evaluated as necessary by the higher order functions.
The package also defines a range function LambdaRange, operator
parsed using the ListOrRangeGrammarMatcher
to allow the syntax [1..10] to generate a sequence of numbers from 1 to 10.
The SendTo PostfixMathCommand is used to implement the 5 -> x
operator which allows the result of an expression to be sent to a variable or function on the right hand side.
This can be used inside lambda functions.
To allow different implementation for Lists passed between
the higher order functions, the ListProcessor interface is used
in many classes to read the input and create output lists.
There are three implementations of this interface:
StandardListProcessor which uses the standard Jep list implementation.
MatrixListProcessor where lists are represented as
VectorI objects.
PaddingListProcessor
can create VectorI and produce MatrixI arguments with all rows the same length.
StreamListProcessor which uses Java Streams to process the lists.
Simple setup
TheLambdaOperatorTable creates a set of
operators for lambda functions, and the range operator.
The ConfigurableParserWithRange adds support for parsing the range
operator syntax [1..10].
The LambdaFunctionSet adds the various higher order functions
and the
StandardListProcessor converts results to the standard Jep list format.
var lot = new LambdaOperatorTable("=>","..","->",true);
ConfigurableParser cp = new ConfigurableParserWithRange("..");
lp = new StandardListProcessor();
FunctionSet lfs = new LambdaFunctionSet();
jep = new Jep(lot, cp, lp, lfs);
Setup
To setup first the operators for range, and lambda functions should be added. The ternary cond ? x : y
is also useful to add.
OperatorTable2 optab = new StandardOperatorTable2();
Operator rangeOp = new RangeOperator("..", "[", "]", new Range(), Operator.BINARY+Operator.NOT_IN_PARSER);
optab.insertOperator(new OperatorKey(){}, rangeOp, optab.getAssign());
TernaryOperator ternOp = new TernaryOperator("cond", "?", ":",
new TernaryConditional(),
Operator.TERNARY+Operator.NARY+Operator.LEFT);
optab.insertOperator(new OperatorKey(){}, ternOp,optab.getAssign());
Operator sendTo = new Operator("->", new SendTo(), Operator.BINARY + Operator.LEFT);
optab.insertOperator(sendTo, optab.getAssign());
Operator lambdaOp = new Operator("=>", new LambdaFunGenerator(), Operator.BINARY);
optab.insertOperator(new OperatorKey(){}, lambdaOp, optab.getAssign());
The lambdaOperator should be added with a precedence just less than the assignment operator and greater than all other operators.
To use the range operator a modified configurable parser must be use. This adds a new symbol (.. by default)
to the parser and adds a new GrammarMatcher. If .. is used then
care needs is needed that notation is not confuse with the dots in numbers or the . operator used for dot products.
ConfigurableParser cp = new ConfigurableParser();
cp.addHashComments();
cp.addSlashComments();
cp.addSingleQuoteStrings();
cp.addDoubleQuoteStrings();
cp.addWhiteSpace();
cp.addTokenMatcher( // enhanced regexp ensuring <code>1..2</code> is not parsed as <code>1. .2</code>
new NumberTokenMatcher("((\\d+\\.\\d+)|(\\d+\\.(?!\\.))|(\\.\\d+)|(\\d+))(?:[eE][+-]?\\d+)?"));
// Adds .. to list of symbols, symbol token matcher must appear before the operator token matcher
cp.addSymbols("(",")","[","]",",","..");
cp.setImplicitMultiplicationSymbols("(","[");
cp.addOperatorTokenMatcher();
cp.addIdentifiers();
cp.addSemiColonTerminator();
cp.addWhiteSpaceCommentFilter();
cp.addBracketMatcher("(",")");
cp.addFunctionMatcher("(",")",",");
// Don't use the standard list matcher, use the ListOrRangeGrammarMatcher instead
//cp.addListMatcher("[","]",",");
cp.addGrammarMatcher(
new ListOrRangeGrammarMatcher(
cp.getSymbolToken("["),
cp.getSymbolToken("]"),
cp.getSymbolToken(","),
cp.getSymbolToken(".."),
rangeOp));
cp.addArrayAccessMatcher("[","]");
Finally the Jep instance can be created and the higher order functions added.
Jep jep = new Jep(optab,cp, new StandardListProcessor());
jep.getFunctionTable().addFunction("map",new Map());
jep.getFunctionTable().addFunction("fold",new Fold());
jep.getFunctionTable().addFunction("filter",new Filter());
jep.getFunctionTable().addFunction("sort",new Sort());
jep.getFunctionTable().addFunction("apply",new Apply());
jep.getFunctionTable().addFunction("merge",new Merge());
jep.getFunctionTable().addFunction("iterate",new Iterate());
jep.getFunctionTable().addFunction("define",new Define());
jep.addFunction("dsort", new ExternalSort(
(a,b)-> {
double da = ((Number) a).doubleValue();
double db = ((Number) b).doubleValue();
return Double.compare(da, db);
}));
jep.addFunction("first", new First());
jep.addFunction("firstOr", new FirstOr());
jep.addFunction("last", new Last());
jep.addFunction("count", new LambdaCount());
jep.addFunction("limit", new Limit());
jep.addFunction("skip", new Skip());
jep.addFunction("toInt",
new ExternalMap(
UnaryFunction.instanceOf(x -> ((Number) x).intValue())));
jep.reinitializeComponents();
- Since:
- Jep 4.0 / Extensions 2.1
- See Also:
-
ClassDescriptionAccumulate values in a sequence returning a sequence of intermediate values.Tests a predicate against sequence.Concatenates two lists, or append a single element.Apply a lambda function to a single argument.Defines a lambda function as a regular function.Limit the list returning only the first n elements.Turns a unary function taking scalar arguments into a function that takes a list and returns a list with function applied to each element.Turns a unary function taking scalar arguments into a function that takes a list and returns a list with function applied to each element.A function that sorts a list using a provided comparator.A Field aware version of the
LambdaRangefunction which returns an increasing sequence of all the items between the end points inclusive.Filter a list using a lambda function returning only those elements which meet a criteria.Finds the first element in a listfirst([1..100])Finds the first element that matches a predicate or return a default value.Finds the first element in a list, or returns the default value if the list is empty.Flatten a list of lists to produce a single list of all elementsFold or reduce a list using a lambda function to reduce the list down to a single argument.Fold or reduce a list using a lambda function to reduce the list down to a single argument.Generate a sequence using iterationiterate(first_value, iteration_lambda_function, limit_lambda_function)For example the following generate the even number from 4 to 20.Count the number of elements in a listPostfixMathCommand representing a lambda functions.Adds list processing and higher order functions.Jep Function that generates aLambdaFunction.Apply a lambda function to a list of arguments returning a listAn OperatorTable that defines the lambda definition operatorx => x^2, the optional range operator[1..5], the optinal send to operatorx^2 -> y, and optional ternary operatorcode ? x : y.Keys to identify the lambda operators.A function which returns an increasing sequence of all the items between the end points inclusive.Finds the last element in a list.Limit the list returning only the first n elements.Defines some utility methods use by higher order functions for processing lists of data, where the actual types used by Jep may differ.A list processor which accepts and producesVectorIarguments.An Iterable over the columns of aMatrixI.An Iterable over the rows of aMatrixI.Joins two sequences together, element by element.An Iterable backed by aVectorI.An Iterator over aVectorIReduce a list, using an identity value and a lambda function defining the reduction operation.An assignment operator so we can do3+4 -> xThis function implements the CallbackEvaluationI interface so that it handles setting the value of a variable.Represents the signature of a lambda function Either a single variablex, a list of variables[x,y,z]a pattern(u,v)or a list containing variables and patterns[(x1,x2),y].Inner elementsA Signature representing a list of signaturesOuter, top-level elementsA Signature representing a pattern{u,v}.A signature representing a single variable inside a list or pattern, e.g.A signature representing a single variable.Remove the first n elements from a list.Sort a list using a lambda function.Default implementation of a ListProcessor.A terminal function constructed from anPostfixMathCommand.A terminal function constructed from anNaryBinaryFunction.Filter a list returning elements while a condition is true and skipping the rest.