diff --git a/specifications/xpath-functions-40/src/function-catalog.xml b/specifications/xpath-functions-40/src/function-catalog.xml index dce940113..a6e5d2216 100644 --- a/specifications/xpath-functions-40/src/function-catalog.xml +++ b/specifications/xpath-functions-40/src/function-catalog.xml @@ -33,6 +33,22 @@ + + +

This record type represents an item and its integer position within a sequence.

+
+ + +

The one-based position of the item within a containing sequence.

+
+
+ + +

The item itself.

+
+
+
+

This record type represents the components of a URI.

@@ -20856,7 +20872,7 @@ return map:of-pairs($ann) - + @@ -20870,18 +20886,22 @@ return map:of-pairs($ann) in turn, returning the concatenation of the resulting sequences in order.

-

The function calls $action($item, $pos) for each item in $input, - where $item is the item in question and $pos is its 1-based - ordinal position in $input. The final result is the sequence concatenation +

The function calls $action($item) for each item in $input, + where $item is the item in question. The final result is the sequence concatenation of the result of these calls, preserving order (provided that ordering mode is ordered).

-fold-left($input, (), fn($result, $next, $pos) { - $result, $action($next, $pos) +fold-left($input, (), fn($result, $next) { + $result, $action($next) }) + +

If evaluation of the action requires access to the position of the item + in the sequence, it is possible to call the function with numbered-items($input) + as the first argument.

+
@@ -20907,24 +20927,24 @@ fold-left($input, (), fn($result, $next, $pos) { for-each( - ('one', 'two', 'three'), - fn($item, $pos) { $pos || '. ' || $item } + numbered-items(('one', 'two', 'three'), + fn() { ?position || '. ' || ?item } ) "1. one", "2. two", "3. three" - + - + @@ -20939,13 +20959,13 @@ fold-left($input, (), fn($result, $next, $pos) {

The function returns a sequence containing those items from $input - for which $predicate($item, $pos) returns true, where $item - is the item in question, and $pos is its 1-based ordinal position within $input.

+ for which $predicate($item) returns true, where $item + is the item in question.

-fold-left($input, (), fn($result, $next, $pos) { - if ($predicate($next, $pos)) +fold-left($input, (), fn($result, $next) { + if ($predicate($next)) then ($result, $next) else $result }) @@ -20966,6 +20986,9 @@ fold-left($input, (), fn($result, $next, $pos) { the focus within the predicate is different from that outside; this means that the use of a context-sensitive function such as fn:lang#1 will give different results in the two cases.

+

If evaluation of the predicate requires access to the position of the item + in the sequence, it is possible to call the function with numbered-items($input) + as the first argument.

@@ -20990,9 +21013,9 @@ fold-left($input, (), fn($result, $next, $pos) { let $sequence := (1, 1, 2, 3, 4, 4, 5) return filter( - $sequence, - fn($item, $pos) { $item = $sequence[$pos - 1] } -) + numbered-items($sequence), + fn($nit) { $nit?item = $sequence[$nit?position - 1] } +) ? item 1, 4 @@ -21011,7 +21034,7 @@ return filter( - + @@ -21027,40 +21050,26 @@ return filter(

If $input is empty, the function returns $zero.

If $input contains a single item $item1, the function calls - $action($zero, $item1, 1).

+ $action($zero, $item1).

If $input contains a second item $item2, the function then calls - $action($zero1, $item2, 2), where $zero1 is the result after + $action($zero1, $item2), where $zero1 is the result after processing the first item.

This continues in the same way until the end of the $input sequence; the final result is the result of the last call on $action.

-declare %private function fold-left-2( +declare function fold-left( $input as item()*, $zero as item()*, $action as function(item()*, item()) as item()* ) as item()* { if (empty($input)) then $zero - else fold-left-2(tail($input), $action($zero, head($input)), $action) + else fold-left(tail($input), $action($zero, head($input)), $action) }; -declare function fold-left( - $input as item()*, - $zero as item()*, - $action as function(item()*, item(), xs:integer) as item()* -) as item()* { - let $numbered-input := for-each($input, fn($item, $pos) { - { 'item': $item, 'position': $pos } - }) - return fold-left-2($numbered-input, fn($zero, $pair) { - $action($zero, $pair?item, $pair?position) - }) -}; -(: Note: a practical implementation can optimize for the case where the - supplied $action function has arity 2 :)

As a consequence of the function signature and the function calling rules, a type error @@ -21073,9 +21082,7 @@ declare function fold-left(

This operation is often referred to in the functional programming literature as “folding” or “reducing” a sequence. It typically takes a function that operates on a pair of values, and applies it repeatedly, with an accumulated result as the first argument, and - the next item in the sequence as the second argument. Optionally the $action - function may take a third argument, which is set to the 1-based position of the current - item in the input sequence. The accumulated result is + the next item in the sequence as the second argument. The accumulated result is initially set to the value of the $zero argument, which is conventionally a 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 @@ -21186,9 +21193,9 @@ return fold-left($input, (), - +

The $predicate callback function may return an empty sequence (meaning false).

@@ -21199,7 +21206,7 @@ return fold-left($input, (), - + @@ -21215,18 +21222,17 @@ return fold-left($input, (),

If $input is empty, the function returns $zero.

-

Let $itemN be the last item in $input, and let $N - be its 1-based ordinal position in $input (that is, the size of $input). - The function starts by calling $action($itemN, $zero, $N).

-

If there is a previous item, $itemN-1, at position $N - 1, - the function then calls $action($itemN-1, $zeroN, $N - 1), where $zeroN is the result +

Let $itemN be the last item in $input. + The function starts by calling $action($itemN, $zero).

+

If there is a previous item $prev, + the function then calls $action($prev, $zeroN), where $zeroN is the result of the previous call.

This continues in the same way until the start of the $input sequence is reached; the final result is the result of the last call on $action.

-declare %private function fold-right-2( +declare %private function fold-right( $input as item()*, $zero as item()*, $action as function(item(), item()*) as item()* @@ -21236,21 +21242,7 @@ declare %private function fold-right-2( else $action(head($input), fold-right-2(tail($input), $zero, $action) }; -declare function fold-right ( - $input as item()*, - $zero as item()*, - $action as function(item()*, item(), xs:integer) as item()* -) as item()* { - let $numbered-input := for-each($input, fn($item, $pos) { - { 'item': $item, 'position': $pos } - }) - return fold-right-2($numbered-input, fn($zero, $pair) { - $action($pair?item, $zero, $pair?position) - }) -}; -(: Note: a practical implementation can optimize for the case where the - supplied $action function has arity 2 :)

As a consequence of the function signature and the function calling rules, a type error @@ -21272,9 +21264,7 @@ 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.

+ @@ -22429,7 +22419,45 @@ declare function transitive-closure (

New in 4.0

- + + + + + + + +

Returns a sequence of numbered-item records + corresponding to the items in a sequence.

+

The function returns a sequence of maps, one for each item in the input, + retaining order, in which each map has an entry with key "item" + containing the item, and an entry with key "position" containing its one-based position.

+ +for $item at $position in $input +return { 'item': $item, 'position': $position } + + + + + numbered-items(( "a", "b", "c" )) + +{"item": "a", "position": 1}, +{"item": "b", "position": 2}, +{"item": "c", "position": 3} + + + numbered-items(10 to 12) + +{"item": 10, "position": 1}, +{"item": 11, "position": 2}, +{"item": 12, "position": 3} + + + + +

New in 4.0

+
+
+ @@ -31268,7 +31296,7 @@ tail(fold-left( - @@ -31288,8 +31316,8 @@ tail(fold-left( -fold-left($input, true(), fn($result, $item, $pos) { - $result and $predicate($item, $pos) +fold-left($input, true(), fn($result, $item) { + $result and $predicate($item) }) @@ -31300,9 +31328,9 @@ fold-left($input, true(), fn($result, $item, $pos) {

If the second argument is omitted or an empty sequence, the predicate defaults to fn:boolean#1, which takes the effective boolean value of each item.

-

It is possible for the supplied $predicate to be a function whose arity is less than two. - The coercion rules mean that the additional parameters are effectively ignored. Frequently a predicate - function will only consider the item itself, and disregard its position in the sequence.

+

If evaluation of the predicate requires access to the position of the item + in the sequence, it is possible to call the function with numbered-items($input) + as the first argument.

The predicate is required to return either true, false, or an empty sequence (which is treated as false). A predicate such as fn{self::h1} results in a type error because it returns a node, not a boolean.

@@ -31355,15 +31383,15 @@ fold-left($input, true(), fn($result, $item, $pos) { The effective boolean value of NaN is false. - every(1 to 5, fn($num, $pos) { $num = $pos }) + every(numbered-items(1 to 5), fn{ ?item = ?position }) true()
Morgawr
Sea giant
-return every($dl/*, fn($elem, $pos) { - name($elem) = ( - if (($pos mod 2)) then "dt" else "dd" +return every(numbered-item($dl/*), fn { + name(?item) = ( + if ((?position mod 2)) then "dt" else "dd" ) })]]>
true() @@ -31758,7 +31786,7 @@ fn($item) { - + @@ -31778,8 +31806,8 @@ fn($item) { -fold-left($input, (), fn($indices, $item, $pos) { - $indices, if ($predicate($item, $pos)) { $pos } +fold-left($input, (), fn($indices, $item) { + $indices, if ($predicate($item)) { $pos } }) @@ -31807,19 +31835,19 @@ fold-left($input, (), fn($indices, $item, $pos) {
2 } + numbered-items(( 1, 8, 2, 7, 3 )), + fn { ?item < 5 and ?position > 2 } )]]> 3, 5 - +
@@ -32114,7 +32142,7 @@ return $item - @@ -32127,12 +32155,12 @@ return $item

Returns true if at least one item in the input sequence matches a supplied predicate.

-

The function returns true if (and only if) there is an item $item at position $pos +

The function returns true if (and only if) there is an item $item in the input sequence such that $predicate($item, $pos) returns true.

-fold-left($input, false(), fn($result, $item, $pos) { - $result or $predicate($item, $pos) +fold-left($input, false(), fn($result, $item) { + $result or $predicate($item) }) @@ -32143,9 +32171,9 @@ fold-left($input, false(), fn($result, $item, $pos) {

If the second argument is omitted or an empty sequence, the predicate defaults to fn:boolean#1, which takes the effective boolean value of each item.

-

It is possible for the supplied $predicate to be a function whose arity is less than two. - The coercion rules mean that the additional parameters are effectively ignored. Frequently a predicate - function will only consider the item itself, and disregard its position in the sequence.

+

If evaluation of the predicate requires access to the position of the item + in the sequence, it is possible to call the function with numbered-items($input) + as the first argument.

The predicate is required to return either true, false, or an empty sequence (which is treated as false). A predicate such as fn{self::h1} results in a type error because it returns a node, not a boolean.

@@ -32197,7 +32225,8 @@ fold-left($input, false(), fn($result, $item, $pos) { The effective boolean value in each case is false. - some(reverse(1 to 5), fn($num, $pos) { $num = $pos }) + some(numbered-items(reverse(1 to 5)), + fn { ?item = ?position }) true() @@ -33446,7 +33475,7 @@ path with an explicit file: scheme.

- + @@ -33472,10 +33501,10 @@ path with an explicit file: scheme.

-fold-left($input, (), fn($partitions, $next, $pos) { - if (empty($partitions) or $split-when(foot($partitions)?*, $next, $pos)) - then ($partitions, [ $next ]) - else (trunk($partitions), array { foot($partitions)?*, $next }) +fold-left(numbered-items($input), (), fn($partitions, $next) { + if (empty($partitions) or $split-when(foot($partitions)?*, $next?item, $next?position)) + then ($partitions, [ $next?item ]) + else (trunk($partitions), array { foot($partitions)?*, $next?item }) }) diff --git a/specifications/xpath-functions-40/src/xpath-functions.xml b/specifications/xpath-functions-40/src/xpath-functions.xml index 40e591837..2fe57da30 100644 --- a/specifications/xpath-functions-40/src/xpath-functions.xml +++ b/specifications/xpath-functions-40/src/xpath-functions.xml @@ -7507,6 +7507,44 @@ return + + + Numbered lists +

It is a common requirement to process the items in a sequence + (or the members in an array) with knowledge of their position + in the sequence or the array. Some languages such as Javascript + therefore provide higher-order functions that supply position + information in a callback to a user-supplied argument function.

+ +

Rather than complicate each higher-order function with an additional + position argument to satisfy this requirement, this library instead + provides a function fn:numbered-list that returns + the items in a sequence along with the position of each item.

+ +

TODO: Similarly, + array:numbered-list does the same for arrays, and + map:numbered-list does the same for maps.

+ +

For example, suppose the requirement is to establish that all + even-numbered elements in a given sequence have an + attribute @date. This can be solved using the expression:

+ + every(numbered-items($input), + fn{ if (?position mod 2 = 1) then true() else exists(?item/@date) }) + +

The numbered-items function converts the sequence of items + supplied in the argument to a sequence of (integer, item) pairs + delivered as instances of record(position as xs:integer, value as item()). +

+ + + + + + + + +
Basic higher-order functions