Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions