-
Notifications
You must be signed in to change notification settings - Fork 3
Description
I’m investigating user-defined lambda-like functions as discussed here.
Is this something of interest to discuss here?
User-defined functions
JMESPath already supports expression-type which are, conceptually, anonymous functions without arguments.
I have toyed with the idea of extending exprefs to support named arguments.
An updated grammar that works looks like this:
expression-type = "&" expression / "<" arguments ">" "=>" expression
arguments = variable-ref *( "," variable-refIt requires a new token => which is even not absolutely necessary. Parsing involves a new entry in the nud() function to match on token < (less-than-sign).
Reduce function
As expression-type are only supported as function arguments, a reduce()
function could work like this:
reduce(array $array, any $seed, expr [any, any]->any)
Example:
[1, 3, 5, 7]reduce(@, `1`, <$acc, $cur> => $acc × $cur)
The reduce() function knows how to iterate over its first array argument
and repeatedly create bindings for both function arguments $acc and $cur.
Funnily enough, the lambda function does not support natively the @ current node.
An argument can be made that it could be similar to the $cur argument. In that case,
a choice must be made as to which "context" is specified when evaluating the expref.
Reusing user-defined functions
I then investigated what reusing user-defined functions could look like.
This requires a mechanism to store or hold functions, possibly by name,
as well as a way to call those functions with appropriate parameters.
By taking advantage of the hopefully upcoming let-expression design, one
could bind the anonymous function to a variable reference. Then, syntax for
calling the function using this variable must be extended and supported in
the grammar.
In the following expression:
let $concat = <$lhs, $rhs> => join('-', [$lhs, $rhs])
in $concat('4', '2')
$concat is bound to the <$lhs, $rhs> => join('-', [$lhs, $rhs]) lambda expression-type. Then, $concat('4', '2') invokes the function indirectly using the $concat variable reference.
The following grammar changes is required:
function-expression = ( unquoted-string / variable-ref ) no-args / one-or-more-args ) Again, implementation is quite easy.
Funnily enough, having also implemented arithmetic-expression grammar rules, I was then able to implement the recursive Fibonacci sequence using the following expression:
let $fib = <$n> => (
($n == `0` && `0`) ||
(($n == `1` && `1`) ||
( $fib($n - `1`) + $fib($n - `2`) )
)
) in
$fib(@)