Package com.singularsys.extensions.lambda


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:

  • apply applies the function once. For example apply([x,y]=>x^y,5,2)
  • define turns a lambda function into a regular function. define("sq",x=>x^2); sq(5).
  • iterate generate a sequence: iterate(2, n=>n+2, n=>n<100)
  • map applies the function to each element of a list and returns a list. For example map(x=>x^2,[1,2,3,4,5]) produces a set of squares.
  • sort sorts a sequence. For example sort([x,y]=>x - y,[3,2,7,6,8])
  • filter applies a filter to a list, returns the elements which meet a condition: filter(x=>x%2==0,[1,2,3,4,5])
  • merge merge two sequences element by element: merge([x,y]=>x^y,[1,2,3,4,5],[2,2,2,2,2])
  • while takes elements from a sequence while a condition is true. For example while(x=>x<5,[1,2,3,4,5,6,7,8,9,10])
  • fold combines 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 simply fold([x,y]=>x+y,[1,2,3,4,5]).
  • foldOr combines 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,[]).
  • reduce combines 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:

  • first finds the first element of a list. first([1,2,3])
  • firstOr finds the first element of a list or return a default value. firstOr(-1,[1,2,3])
  • last finds the last element of a list. last([1,2,3])
  • limit limits the number of elements in a list. limit(3,[1,2,3,4,5])
  • skip skips the first n elements in a list. skip(3,[1,2,3,4,5])
  • min and max find 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

The LambdaOperatorTable 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("=&gt;", 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:
  • Class
    Description
    Accumulate 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 LambdaRange function 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 list first([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 elements
    Fold 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 iteration iterate(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 list
    PostfixMathCommand representing a lambda functions.
    Adds list processing and higher order functions.
    Jep Function that generates a LambdaFunction.
    Apply a lambda function to a list of arguments returning a list
    An OperatorTable that defines the lambda definition operator x => x^2, the optional range operator [1..5], the optinal send to operator x^2 -> y, and optional ternary operator code ? 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 produces VectorI arguments.
    An Iterable over the columns of a MatrixI.
    An Iterable over the rows of a MatrixI.
    Joins two sequences together, element by element.
    A list processor which accepts and produces VectorI arguments and can produce MatrixI arguments with all rows the same length.
    An Iterable backed by a VectorI.
    An Iterator over a VectorI
    Reduce a list, using an identity value and a lambda function defining the reduction operation.
    An assignment operator so we can do 3+4 -> x This 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 variable x, a list of variables [x,y,z] a pattern (u,v) or a list containing variables and patterns [(x1,x2),y].
    Inner elements
    A Signature representing a list of signatures
    Outer, top-level elements
    A 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 an PostfixMathCommand.
    A terminal function constructed from an NaryBinaryFunction.
    Filter a list returning elements while a condition is true and skipping the rest.