Package com.singularsys.extensions.chained
total= [1..10] . map(x=>x^2) . sqrt() . fold([x,y]=>x+y)
. by default, is
created using the
ChainingOpPfmc
and functions in the middle and end of the chain
implement ChainedFunctionI which defines an
apply(Evaluator ev, Node node, Object arg)
A number of adapter classes are
provided to allow the higher order functions in the
com.singularsys.extensions.lambda package
and general Jep functions to be used in a chain.
These come in two flavours,
Chained functions that support the chained notation
and Chainable functions that can either be used in chain or as a regular function.
All the adapters implement ChainedFunctionI.
Chained adapters:
ChainedUnaryFunction- converts anUnaryFunctionChainedBinaryFunction- converts aBinaryFunctionChainedBinaryFunctionSwapped- converts aBinaryFunctionwith the arguments swappedChainedNaryFunction- converts anNaryFunctionChainedGeneralFunction- converts a generalPostfixMathCommandI
ChainableUnaryFunction- converts anUnaryFunctionChainableBinaryFunction- converts aBinaryFunctionChainableBinaryFunctionSwapped- converts aBinaryFunctionwith the arguments swappedChainableGeneralFunction- converts a generalPostfixMathCommandI
These are typically used in conjunction with the higher order functions
in the com.singularsys.extensions.lambda
package, but can be used with any Jep function.
Typically each non-terminal function in a chain will return a list.
Simple set up
TheChainedOperatorTable 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 ChainedFunctionSet adds the various higher order functions
and the StandardListProcessor converts results to the standard Jep list format.
var cot = new ChainedOperatorTable("=>", "..", "->", true);
var cp = new ConfigurableParserWithRange("..");
lp = new StandardListProcessor();
FunctionSet lfs = new ChainedFunctionSet();
jep = new Jep(cot, cp, lp, lfs);
ChainableFunctionSet to use chainable versions of the function.
Chained set up
A simple set up is
// Create a Jep instance using the standard parser
// and standard list processor from the lambda package.
jep = new Jep(new StandardConfigurableParser(),
new StandardListProcessor());
// Gets the operator table, here its the standard operator table
var ot = (OperatorTable2) jep.getOperatorTable();
// adds the lambda operator, allowing the x=>x^2 notation
Operator lambdaOp = new Operator("=>", new LambdaFunGenerator(), Operator.BINARY);
ot.insertOperator(lambdaOp, ot.getAssign());
// Change the dot operator so that it behaves as function composition
ot.getDot().setPFMC(new ChainingOpPfmc());
// Adds intermediate functions:
// map, filter are both binary functions that are converted to
// unary chained functions using the ChainedBinaryFunction adapter.
jep.getFunctionTable().addFunction("map",
new ChainedBinaryFunction(new Map()));
jep.getFunctionTable().addFunction("filter",
new ChainedBinaryFunction(new Filter()));
// Add a vectorised version of the sqrt function
// which is applied to each element of the list in the chain.
jep.getFunctionTable().addFunction("sqrt",
new ChainedUnaryFunction(
new ExternalMap(new SquareRoot())));
// Terminal functions
// fold, and reduce
jep.getFunctionTable().addFunction("fold",
new ChainedBinaryFunction(new Fold()));
jep.getFunctionTable().addFunction("reduce",
new ChainedNaryFunction(new Reduce()));
// Construct a terminal sum function
// using the TerminalNaryBinaryFunction adapter to convert
// the Add Jep function to a unary function that sums a list of values,
// Finally use the ChainedUnaryFunction adapter to allow it to be used in the chain.
jep.getFunctionTable().addFunction("sum",
new ChainedUnaryFunction(
new TerminalNaryBinaryFunction(
new Add(), 0.0)));
jep.reinitializeComponents();
Which allows the expression
[1,2,3,4,5] . filter(x=>x%2==0) . map(x=>x^2) . reduce(1,[x,y]=>x*y);
[1,4,9] . sqrt() . sum();
A more complete set of function is provided in the ChainedFunctionSet component.
Also see
Chained Documentation
for more details and examples.
Chainable setup
To allow the same functions to be used in a chain or as regular functions,
the chainable adapters can be used. There use
the AlternateFunctions
and OverloadedFunctionByStructure
classes from the com.singularsys.jep.misc.overloadedfunctions
package to allow two different functions to be used depending on
number of argument or structure of the parse tree.
ChainableUnaryFunction
ChainableBinaryFunction
ChainableBinaryFunctionSwapped
take a single Unary or Binary function when used
in a a chain a ChainedUnaryFunction or ChainedBinaryFunction is used,
otherwise the original function is used.
For Nary function or a general PostfixMathCommand
the ChainableGeneralFunction
takes a ChainedFunctionI and a PostfixMathCommandI
and a predicate that tests the structure of the parse tree to determine which function to use.
A simple chainable set up is
// Modify the StandardOperatorTable2
var ot = new StandardOperatorTable2();
// Adds the range operator, allowing the [1..10] notation
Operator rangeOp = new RangeOperator("..", "[", "]", new Range(), Operator.BINARY + Operator.NOT_IN_PARSER);
ot.insertOperator(OperatorTable2.SpecialOperators.RANGE, rangeOp, ot.getAssign());
// adds the lambda operator, allowing the x=>x^2 notation
Operator lambdaOp = new Operator("=>", new LambdaFunGenerator(), Operator.BINARY);
ot.insertOperator(lambdaOp, ot.getAssign());
// Modify the dot operator so that it behaves as function composition
// when the second argument is a ChainedFunctionI, and regular dot product otherwise.
OverloadedOperator.extendOperator(
ot,
ot.getDot(),
new ChainingOpPfmc(),
n -> n.jjtGetChild(1).getPFMC() instanceof ChainedFunctionI);
// Modify the standard parser to allow the range operator
var cp = new StandardConfigurableParser();
// Add a new symbol token for ".."
var stm = cp.getSymbolTokenMatcher();
stm.add(new SymbolToken(".."));
// Remove the existing list and array access matchers and replace with a
// new ListOrRangeGrammarMatcher matcher that allows both lists and ranges,
// and an array access matcher that allows the same syntax as before.
// This ensure the ListOrRangeGrammarMatcher is tested before the array access matcher
var g = cp.getGrammarMatchers();
g.removeIf(m -> m instanceof ListGrammarMatcher);
g.removeIf(m -> m instanceof ArrayAccessGrammarMatcher);
cp.addGrammarMatcher(
new ListOrRangeGrammarMatcher(
cp.getSymbolToken("["), cp.getSymbolToken("]"),
cp.getSymbolToken(","), cp.getSymbolToken(".."), rangeOp));
cp.addArrayAccessMatcher("[", "]");
// Create a Jep instance using the modified parser and operator table,
// and the standard list processor from the lambda package.
jep = new Jep(cp,ot,
new StandardListProcessor());
// Adds intermediate functions:
jep.getFunctionTable().addFunction("map",
new ChainableBinaryFunction(new Map()));
jep.getFunctionTable().addFunction("filter",
new ChainableBinaryFunction(new Filter()));
jep.addFunction("sqrt",
new ChainableUnaryFunction(
new ExternalMap(new SquareRoot())));
// Adds terminal functions
jep.getFunctionTable().addFunction("fold",
new ChainableBinaryFunction(new Fold()));
jep.getFunctionTable().addFunction("reduce",
new ChainableGeneralFunction(
new ChainedNaryFunction(new Reduce()),
new Reduce(),
n -> n.jjtGetNumChildren() ==2 ));
jep.getFunctionTable().addFunction("sum",
new ChainableUnaryFunction(
new TerminalNaryBinaryFunction(new Add(), 0.0)));
jep.reinitializeComponents();
Which allows expressions like:
[1..5] . filter(x=>x%2==1) . map(x=>x^2) . reduce(1,[x,y]=>x*y);
[1,4,9] . sqrt() . sum();
reduce(1,[x,y]=>x*y , map(x=>x^2, filter(x=>x%2==1, [1..5])));
sum( sqrt([1,4,9] ));
A more complete set of function is provided in the ChainableFunctionSet component.
-
ClassDescriptionConverts a
BinaryFunctionso it can be used in a chain or directly as binary function.Converts aBinaryFunctionso it can be used in a chain or directly as binary function.Adds chainable list processing functions.Converts aNaryFunctionso it can be used in a chain or directly as Nary function.Converts aUnaryFunctionso it can be used in a chain or directly as unary function.Converts aBinaryFunctionso it can be used in a chain.Converts aBinaryFunctionso it can be used in a chain.An extension to theDefinefunction that allows chained functions to be created.Specifies functions than can be used in a chain.Adds chained list processing functions.Converts a generalPostfixMathCommandIso it can be used in a chain.Converts aNaryFunctionso it can be used in a chain.An OperatorTable for chained and chainable syntax.Keys to identify the lambda operators.Converts aUnaryFunctionso that it can be used in a chain.An PFMC which allows a method chaining syntax.An implementation of theChainingOpPfmcthat records calls toChainedFunctionI.apply(Evaluator, Node, Object)to theMonitoringEvaluator.A rule which transforms a chain of functions into a nested function calls.