Re: Formal equivalents using fold-left

> We can probably get a long way if we treat fn:for-each as primitive,

Actually, *fn:for-each* can be expressed as a *fold*. *Folds*  and
*fn:numbered-items* could be the only primitives.
Here is a code example, where $forEach is defined in 6 lines. Watch how
much is accomplished in this pure XPath 3 code:

*let $numberedItems := function($input as item()*)*
*    { for-each-pair(1 to count($input), $input, function($n,$it){[$n,
$it]})},*

*$forEach := function($input as item()*, *
*                         $action as function(item(), xs:integer) as
item()*)*
*    {*
*      fold-left($numberedItems($input), (), function($accum as item()*,
$current as item())*
*                            { ($accum, $action($current(2), $current(1)))}*
*               )*
*    }*
*  return*
*    (*
*      $forEach(1 to 5, function($x) {2 * $x}),*
*      $forEach(("Paris", "London", "Washington"), function($city, $pos)
{$city || '-' || (2  * $pos)})*
*    )*

This could be even more simpler if we had the Record in XPath - then
fn:numberedItems would return a sequence of records and not of arrays.

Here is a screenshot executing this with BaseX:

[image: image.png]

Look how much we accomplish with just a few lines of code.

Thanks,
Dimitre.



On Wed, Mar 12, 2025 at 4:42 AM Michael Kay <mike@saxonica.com> wrote:

> We can probably get a long way if we treat fn:for-each as primitive,
> then we have for example
>
> declare fn:filter($input, $predicate) {
>    fn:for-each($input, fn($item, $pos) { if ($predicate($item, $pos)) {
> $item } })
> }
>
> and then we can define for-each using head-tail recursion.
>
> That's analogous to what we've done with maps where we treat iterate-map()
> as the primitive accessor.
>
> Michael Kay
>
>
> On 12 Mar 2025, at 11:15, Michael Kay <mike@saxonica.com> wrote:
>
> As with everything else in the specification, the formal equivalents are
> designed to provide a contract between implementators and users, which both
> parties should be capable of understanding.
>
> The ideal is that everything should be defined directly or indirectly in
> terms of primitives in the data model. We should avoid the "formal
> equivalents" becoming circular, and we should try to avoid reliance of
> constructs that don't themselves have a formal equivalent - which includes
> things like the "!" operator and FLWOR expressions. In an ideal world we
> would define a core language and everything else would be defined in terms
> of that core.
>
> With the array functions I did actually check that all the formal
> equivalents passed the tests and had no dependencies on array operations
> other than the primitives in the data model. For sequence functions we're
> not there yet.
>
> Michael Kay
>
> On 12 Mar 2025, at 10:36, Christian Grün <cg@basex.org> wrote:
>
> > In most case it's easy enough, for example fn:filter becomes
> >
> > fold-left($input ! {'item': ., 'pos': position()},
> >          (),
> >          fn($result, $pair) {
> >            if ($predicate($pair?item, $pair?pos))
> >            then ($result, $pair?item)
> >            else $result
> >          })
>
> …and the function call would need to be followed by an ?item lookup.
>
> One question may be who is supposed to be the recipient of the equivalent
> code. If we want to address users, I think that we should focus on
> simplicity. For fn:filter, a FLWOR expression may be much easier to digest:
>
>   for $item at $pos in $input
>   where $predicate($item, $pos)
>   return $item
>
> Next, many functions (including fn:index-of or fn:avg) don’t seem to have
> a formal counterpart. Maybe it’s not required in all cases? Folds are a
> good example: For advanced users, it is obvious what it does, and there
> will be no need to digest the equivalent code. For others, the main
> challenge is to understand the very principle, and tutorials will probably
> be more helpful than a concise recursive function.
>
>
>
>

Received on Wednesday, 12 March 2025 16:01:29 UTC