Skip to content

[Initial feedback] Potential proposal for user-defined function #25

@springcomp

Description

@springcomp

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-ref

It 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(@)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions