From 411427d7d34fd0b4790a1beba1b3fbb54a0f2993 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Sun, 23 Jun 2024 23:52:31 +0100 Subject: [PATCH 1/4] Rewrite of scan-left and scan-right --- .../src/function-catalog.xml | 89 ++++++++++--------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index 2f0750fdc..a14d4246d 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -31335,7 +31335,7 @@ path with an explicit file: scheme.

- + @@ -31344,11 +31344,16 @@ path with an explicit file: scheme.

focus-independent
-

Produces the complete (ordered) sequence of all partial results from every new value - the accumulator is assigned to during the evaluation of fn:fold-left.

+

Produces the complete (ordered) sequence of all intermediate + results of an evaluation of fn:fold-left.

-

The function is equivalent to the following implementation in XPath (return clause added in comments for completeness):

+

The result of the function is the value of the expression:

+ (1 to count($input)) ! + array{ slice($input, end := .) => fold-left($zero, $action) } + +
-

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is either the value of $zero or the result of a previous - application of $action, and the second - is any single item from the sequence $input.

+

See fn:fold-left: errors are raised in the same situations.

- - -

Note that each intermediate result is placed in a separate singleton array. - This is necessary because we cannot represent a sequence of results, some or all of which are - a sequence - that is "sequence of sequences" as just a single sequence. -

-
-
+

A practical implementation might be expected to evaluate the result + incrementally in a single pass of the input; the equivalent expression + given in the rules above is provided purely for formal specification + purposes.

+

Each intermediate result is placed in a separate array. The number of arrays + in the result is the same as the number of items in $input.

+

The fact that the function has the same signature as fn:fold-left + means that this function can conveniently be used to study the behavior of + an call on fn:fold-left with the same arguments, perhaps for + diagnostic purposes.

scan-left(1 to 5, 0, op('+')) - [ 0 ], [ 1 ], [ 3 ], [ 6 ], [ 10 ], [ 15 ] + [ 1 ], [ 3 ], [ 6 ], [ 10 ], [ 15 ] scan-left(1 to 3, 0, op('-')) - [ 0 ], [ -1 ], [ -3 ], [ -6 ] + [ -1 ], [ -3 ], [ -6 ] @@ -31418,7 +31421,7 @@ return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) }) Produce the factorials of all numbers from 0 to 5

scan-left(1 to 5, 1, op('*')) - [ 1 ], [ 1 ], [ 2 ], [ 6 ], [ 24 ], [ 120 ] + [ 1 ], [ 2 ], [ 6 ], [ 24 ], [ 120 ]
@@ -31432,7 +31435,7 @@ return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) }) - + @@ -31441,11 +31444,15 @@ return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) })focus-independent -

Produces the complete (ordered) sequence of all partial results from every new value - the accumulator is assigned to during the evaluation of fn:fold-right.

+

Produces the complete (ordered) sequence of all intermediate + results of an evaluation of fn:fold-right.

-

The function is equivalent to the following implementation in XPath (return clause in comments added for completeness):

+

The result of the function is the value of the expression:

+ + reverse(1 to count($input)) ! + array{ slice($input, start := .) => fold-right($zero, $action) } +
-

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is any item in the sequence $input, and the second is either - the value of $zero or the result of a previous application of - $action.

+

See fn:fold-left: errors are raised in the same situations.

- - -

Note that each intermediate result is placed in a separate singleton array. - This is necessary because we cannot represent a sequence of results, some or all of which are - a sequence - that is "sequence of sequences" as just a single sequence. -

-
-
-
+

A practical implementation might be expected to evaluate the result + incrementally in a single right-to-left pass of the input; the equivalent expression + given in the rules above is provided purely for formal specification + purposes.

+

Each intermediate result is placed in a separate array. The number of arrays + in the result is the same as the number of items in $input.

+

The fact that the function has the same signature as fn:fold-right + means that this function can conveniently be used to study the behavior of + an call on fn:fold-right with the same arguments, perhaps for + diagnostic purposes.

+ @@ -31496,8 +31501,8 @@ let $scan-right := function( - scan-right(1 to 3, 0, op('-')) - [ 2 ], [ -1 ], [ 3 ], [ 0 ] + scan-right(1 to 5, 0, op('-')) + [ 5 ], [ -1 ], [ 4 ], [ -2 ], [ 3 ] From 4f01b0a8b219dc46e7d1b09f0737a8fe32b71e6e Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Mon, 24 Jun 2024 15:31:01 +0100 Subject: [PATCH 2/4] Updated proposal in the light of comments and discussion --- .../src/function-catalog.xml | 239 ++++++++---------- 1 file changed, 99 insertions(+), 140 deletions(-) diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index a14d4246d..efba3dd1f 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -19367,7 +19367,7 @@ return filter( - + @@ -19383,29 +19383,17 @@ return filter(

The function is equivalent to the following implementation in XQuery:

+ else fold-left(tail($input), + $action($zero, head($input)), + $action) +}]]>
@@ -19424,8 +19412,7 @@ declare function fold-left( value (such as zero in the case of addition, one in the case of multiplication, or a zero-length string in the case of string concatenation) that causes the function to return the value of the other argument unchanged.

-

The value of the third argument of $action corresponds to the position - of the item in the input sequence. It is initally set to 1.

+ @@ -19436,7 +19423,8 @@ declare function fold-left( fn($a, $b) { $a + $b } ) 15 - This returns the sum of the items in the sequence + This returns the sum of the items in the sequence. The result is computed + as ((((0+1)+2)+3)+4)+5). @@ -19515,7 +19503,7 @@ declare function fold-left( { 1: 2, 2: 4, 3: 6, 4: 8, 5: 10 } - + - + - + deterministic context-independent - focus-independent - + focus-independent special-streaming-rules @@ -19556,27 +19543,17 @@ return fold-left($input, (),

The function is equivalent to the following implementation in XQuery:

@@ -19599,9 +19576,6 @@ declare function fold-right(

In cases where the function performs an associative operation on its two arguments (such as addition or multiplication), fn:fold-right produces the same result as fn:fold-left.

-

The value of the third argument of $action corresponds to the position - of the item in the input sequence. Thus, in contrast to fn:fold-left, - it is initally set to the number of items in the input sequence.

@@ -19612,7 +19586,8 @@ declare function fold-right( fn($a, $b) { $a + $b } ) 15 - This returns the sum of the items in the sequence + This returns the sum of the items in the sequence. + The result is computed as (0+(1+(2+(3+(4+5))))). @@ -19635,7 +19610,7 @@ declare function fold-right( "$f(1, $f(2, $f(3, $f(4, $f(5, $zero)))))" - + - +
@@ -31335,7 +31310,7 @@ path with an explicit file: scheme.

- + @@ -31344,89 +31319,79 @@ path with an explicit file: scheme.

focus-independent
-

Produces the complete (ordered) sequence of all intermediate - results of an evaluation of fn:fold-left.

+

Produces a sequence containing intermediate results of an evaluation of fn:fold-left.

-

The result of the function is the value of the expression:

- (1 to count($input)) ! - array{ slice($input, end := .) => fold-left($zero, $action) } +

The function is equivalent to the following implementation in XQuery:

- +) as item()* { + array{$zero}, + if (exists($input)) { + scan-left( + tail($input), + $action($zero, head($input)), + $action + ) + } +};]]> + +

The result is a sequence of arrays representing intermediate results. The first array + holds the value of $zero. Subsequent arrays, one per item in $input, + represent the result of applying fn:fold-left (with the same values for + $zero and $action) to the subsequence of $input + ending at that item.

+ +
-

See fn:fold-left: errors are raised in the same situations.

+

As a consequence of the function signature and the function calling rules, a type error + occurs if the supplied function $action cannot be applied to two arguments, where + the first argument is either the value of $zero or the result of a previous + application of $action, and the second + is any single item from the sequence $input.

-

A practical implementation might be expected to evaluate the result - incrementally in a single pass of the input; the equivalent expression - given in the rules above is provided purely for formal specification - purposes.

-

Each intermediate result is placed in a separate array. The number of arrays - in the result is the same as the number of items in $input.

+

The number of arrays + in the result is the same as the number of items in $input plus one.

The fact that the function has the same signature as fn:fold-left means that this function can conveniently be used to study the behavior of - an call on fn:fold-left with the same arguments, perhaps for - diagnostic purposes.

+ a call on fn:fold-left with the same arguments, perhaps for + diagnostic purposes. It can also be used to produce the running totals of + a computation.

scan-left(1 to 5, 0, op('+')) - [ 1 ], [ 3 ], [ 6 ], [ 10 ], [ 15 ] + [ 0 ], [ 1 ], [ 3 ], [ 6 ], [ 10 ], [ 15 ] - scan-left(1 to 3, 0, op('-')) - [ -1 ], [ -3 ], [ -6 ] + scan-left(1 to 5, 0, op('-')) + [ 0 ], [ -1 ], [ -3 ], [ -6 ], [ -10 ], [ -15 ] - + -

Produce the intermediate results of mapping each number in a sequence to its doubled value. - This example shows the necessity to place each intermediate result (sequence) into a singleton array - otherwise - the sequence of sequences (intermediate results) would not be possible to express as a single sequence - without losing completely the intermediate results.

- let $double := fn($x) { 2 * $x } -return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) }) - [ () ], [ 2 ], [ (2, 4) ], [ (2, 4, 6) ] ] + scan-left(1 to 5, 1, op('*')) + [ 1 ], [ 1 ], [ 2 ], [ 6 ], [ 24 ], [ 120 ] -
+ -

Produce the factorials of all numbers from 0 to 5

- scan-left(1 to 5, 1, op('*')) - [ 1 ], [ 2 ], [ 6 ], [ 24 ], [ 120 ] + scan-left(1 to 3, (), fn($seq, $it) { $seq , fn(.*2) }) + [ ], [ 2 ], [ 2, 4 ], [ 2, 4, 6 ] -
+
- Proposed for 4.0 + New in 4.0
@@ -31435,7 +31400,7 @@ return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) }) - + @@ -31444,52 +31409,46 @@ return scan-left(1 to 3, (), fn($seq, $it) { $seq , $double($it) })focus-independent -

Produces the complete (ordered) sequence of all intermediate - results of an evaluation of fn:fold-right.

+

Produces a sequence containing intermediate results of an evaluation of fn:fold-right.

-

The result of the function is the value of the expression:

+

The function is equivalent to the following implementation in XQuery:

- reverse(1 to count($input)) ! - array{ slice($input, start := .) => fold-right($zero, $action) } - +}]]> + +

The result is a sequence of arrays representing intermediate results. The last array + holds the value of $zero. Subsequent arrays, one per item in $input, + represent the result of applying fn:fold-right (with the same values for + $zero and $action) to the subsequence of $input + starting at that item.

-

See fn:fold-left: errors are raised in the same situations.

+

As a consequence of the function signature and the function calling rules, a type error + occurs if the supplied function $action cannot be applied to two arguments, where + the first argument is any item in the sequence $input, and the second is either + the value of $zero or the result of a previous application of + $action.

-

A practical implementation might be expected to evaluate the result - incrementally in a single right-to-left pass of the input; the equivalent expression - given in the rules above is provided purely for formal specification - purposes.

-

Each intermediate result is placed in a separate array. The number of arrays - in the result is the same as the number of items in $input.

+

The number of arrays + in the result is the same as the number of items in $input plus one.

The fact that the function has the same signature as fn:fold-right means that this function can conveniently be used to study the behavior of - an call on fn:fold-right with the same arguments, perhaps for - diagnostic purposes.

+ a call on fn:fold-right with the same arguments, perhaps for + diagnostic purposes. It can also be used to produce the running totals of + a computation.

@@ -31501,13 +31460,13 @@ let $scan-right := function( - scan-right(1 to 5, 0, op('-')) - [ 5 ], [ -1 ], [ 4 ], [ -2 ], [ 3 ] + scan-right(1 to 3, 0, op('-')) + [ 2 ], [ -1 ], [ 3 ], [ 0 ] - Proposed for 4.0 + New in 4.0 From 2b68b96c221fa807290cad4ea2df3c8fbb84bf30 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Tue, 25 Jun 2024 21:17:41 +0100 Subject: [PATCH 3/4] Rebased; minor edits --- .../xpath-functions-40/src/function-catalog.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index efba3dd1f..13c9b5753 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -19236,7 +19236,7 @@ return map:keys($ann) || ': ' || string-join(map:values($ann), ', ')
-

Applies the function item $action to every item from the sequence $input +

Applies the function item $action to every item from the sequence $input in turn, returning the concatenation of the resulting sequences in order.

@@ -19386,7 +19386,7 @@ return filter( declare function fold-left( $input as item()*, $zero as item()*, - $action as fn(item()*, item()) as item()*, + $action as fn(item()*, item()) as item()* ) as item()* { if (empty($input)) then $zero @@ -19546,8 +19546,8 @@ return fold-left($input, (), declare function fold-right( $input as item()*, $zero as item()*, - $action as fn(item(), item()*) as item()*) - as item()* { + $action as fn(item(), item()*) as item()* +) as item()* { if (empty($input)) then $zero else $action( @@ -31429,7 +31429,7 @@ declare function scan-right( }]]>

The result is a sequence of arrays representing intermediate results. The last array - holds the value of $zero. Subsequent arrays, one per item in $input, + holds the value of $zero. Previous arrays, one per item in $input, represent the result of applying fn:fold-right (with the same values for $zero and $action) to the subsequence of $input starting at that item.

From 99f2ca17b6af862361b267815a5662a0f2000837 Mon Sep 17 00:00:00 2001 From: Michael Kay Date: Thu, 27 Jun 2024 08:59:21 +0100 Subject: [PATCH 4/4] Reinstate arity-3 callbacks for fold and scan functions --- .../src/function-catalog.xml | 143 ++++++++++++------ 1 file changed, 99 insertions(+), 44 deletions(-) diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index 13c9b5753..ef8c07bfe 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -19367,7 +19367,7 @@ return filter( - + @@ -19381,27 +19381,40 @@ return filter( repeatedly to each item in turn, together with an accumulated result value.

-

The function is equivalent to the following implementation in XQuery:

+

When the supplied $action has an arity of two or less, + the function is equivalent to the following implementation in XQuery:

+ +

The case where $action has an arity of three can be handled by first building a sequence + of (position, item) pairs, and then calling the arity-2 function on this sequence:

+ +

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is either the value of $zero or the result of a previous - application of $action, and the second - is any single item from the sequence $input.

+ occurs if the supplied function $action cannot be applied to the supplied arguments.

This operation is often referred to in the functional programming literature as @@ -19503,7 +19516,7 @@ declare function fold-left( { 1: 2, 2: 4, 3: 6, 4: 8, 5: 10 } - + - + - + @@ -19541,9 +19554,10 @@ return fold-left($input, (), repeatedly to each item in turn, together with an accumulated result value.

-

The function is equivalent to the following implementation in XQuery:

+

When the supplied $action has an arity of two or less, + the function is equivalent to the following implementation in XQuery:

+ +

The case where $action has an arity of three can be handled by first building a sequence + of (position, item) pairs, and then calling the arity-2 function on this sequence:

+ + +

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is any item in the sequence $input, and the second is either - the value of $zero or the result of a previous application of - $action.

+ occurs if the supplied function $action cannot be applied to the supplied arguments.

@@ -19610,7 +19637,7 @@ declare function fold-right( "$f(1, $f(2, $f(3, $f(4, $f(5, $zero)))))" - + - + @@ -21496,7 +21523,7 @@ return fold-left($MAPS, {}, of the corresponding values, retaining their order in the input sequence.

The effect of the function is equivalent to the expression:

- map:pairs($week) => map:build(fn { ?key }, fn { ?value }, $combine) + map:build($input, fn { ?key }, fn { ?value }, $combine)
@@ -26992,7 +27019,8 @@ return array:filter( array.

-

The function is equivalent to the following expression:

+

The function is equivalent to the following expression, which converts the array to a sequence and then + invokes fn:fold-left:

-

The function is equivalent to the following expression:

+

The function is equivalent to the following expression, which converts the array to a sequence and then + invokes fn:fold-right:

file: scheme.

- + @@ -31322,17 +31351,18 @@ path with an explicit file: scheme.

Produces a sequence containing intermediate results of an evaluation of fn:fold-left.

-

The function is equivalent to the following implementation in XQuery:

+

In the case where the supplied $action has an arity of two or less, + the function is equivalent to the following implementation in XQuery:

+

The case where $action has an arity of three can be handled by first building a sequence + of (position, item) pairs, and then calling the arity-2 function on this sequence:

+ + +

The result is a sequence of arrays representing intermediate results. The first array holds the value of $zero. Subsequent arrays, one per item in $input, represent the result of applying fn:fold-left (with the same values for @@ -31350,10 +31395,7 @@ declare function scan-left(

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is either the value of $zero or the result of a previous - application of $action, and the second - is any single item from the sequence $input.

+ occurs if the supplied function $action cannot be applied to the supplied arguments.

The number of arrays @@ -31400,7 +31442,7 @@ declare function scan-left( - + @@ -31412,10 +31454,11 @@ declare function scan-left(

Produces a sequence containing intermediate results of an evaluation of fn:fold-right.

-

The function is equivalent to the following implementation in XQuery:

+

In the case where the supplied $action has an arity of two or less, + the function is equivalent to the following implementation in XQuery:

+}]]>
+ +

The case where $action has an arity of three can be handled by first building a sequence + of (position, item) pairs, and then calling the arity-2 function on this sequence:

+ +

The result is a sequence of arrays representing intermediate results. The last array holds the value of $zero. Previous arrays, one per item in $input, @@ -31436,10 +31494,7 @@ declare function scan-right(

As a consequence of the function signature and the function calling rules, a type error - occurs if the supplied function $action cannot be applied to two arguments, where - the first argument is any item in the sequence $input, and the second is either - the value of $zero or the result of a previous application of - $action.

+ occurs if the supplied function $action cannot be applied to the supplied arguments.

The number of arrays