Skip to content

Commit

Permalink
Change predicate callbacks to allow empty return value
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelhkay committed Apr 30, 2024
1 parent ad2bdcb commit b118cd8
Showing 1 changed file with 58 additions and 36 deletions.
94 changes: 58 additions & 36 deletions specifications/xpath-functions-40/src/function-catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13581,8 +13581,8 @@ return error((), 'Duplicate IDs found: ' || string-join($ids, ', '))</eg>
<fos:signatures>
<fos:proto name="subsequence-where" return-type="item()*">
<fos:arg name="input" type="item()*" usage="transmission"/>
<fos:arg name="from" type="(function(item(), xs:integer) as xs:boolean)?" default="true#0"/>
<fos:arg name="to" type="(function(item(), xs:integer) as xs:boolean)?" default="false#0"/>
<fos:arg name="from" type="(function(item(), xs:integer) as xs:boolean?)?" default="true#0"/>
<fos:arg name="to" type="(function(item(), xs:integer) as xs:boolean?)?" default="false#0"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand Down Expand Up @@ -13612,6 +13612,8 @@ let $end := index-where($input, $to)[. ge $start][1]
otherwise (count($input) + 1)
return slice($input, $start, $end)</eg>






Expand All @@ -13636,6 +13638,9 @@ return slice($input, $start, $end)</eg>
element if it exists, or up to the end of the sequence otherwise, the simplest
solution is perhaps to write:</p>
<eg>slice($input, end:=index-where($input, fn { boolean(self::h2) })[1])</eg>

<p>A return value of <code>()</code> from the <code>$from</code> or <code>$to</code>
predicate is treated as <code>false</code>.</p>
</fos:notes>


Expand Down Expand Up @@ -13959,7 +13964,7 @@ return slice($input, $start, $end)</eg>
<fos:proto name="starts-with-subsequence" return-type="xs:boolean">
<fos:arg name="input" type="item()*" usage="transmission"/>
<fos:arg name="subsequence" type="item()*" usage="transmission"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean)?" default="fn:deep-equal#2"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2"/>
</fos:proto>
</fos:signatures>
<fos:properties arity="2">
Expand All @@ -13986,7 +13991,7 @@ every(for-each-pair($input, $subsequence, $compare))]]></eg>
<fos:notes>
<p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
or not symmetric.</p>
or not symmetric. A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
</fos:notes>

<fos:examples>
Expand Down Expand Up @@ -14075,7 +14080,7 @@ return starts-with-subsequence(
<fos:proto name="ends-with-subsequence" return-type="xs:boolean">
<fos:arg name="input" type="item()*" usage="transmission"/>
<fos:arg name="subsequence" type="item()*" usage="transmission"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean)?" default="fn:deep-equal#2"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2"/>
</fos:proto>
</fos:signatures>
<fos:properties arity="2">
Expand All @@ -14101,6 +14106,7 @@ return starts-with-subsequence(
<p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
or not symmetric.</p>
<p>A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
</fos:notes>

<fos:examples>
Expand Down Expand Up @@ -14189,7 +14195,7 @@ return ends-with-subsequence(
<fos:proto name="contains-subsequence" return-type="xs:boolean">
<fos:arg name="input" type="item()*" usage="transmission"/>
<fos:arg name="subsequence" type="item()*" usage="transmission"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean)?" default="fn:deep-equal#2"/>
<fos:arg name="compare" type="(function(item(), item()) as xs:boolean?)?" default="fn:deep-equal#2"/>
</fos:proto>
</fos:signatures>
<fos:properties arity="2">
Expand Down Expand Up @@ -14220,6 +14226,7 @@ some $i in 0 to count($input) - count($subsequence) satisfies (
<p>There is no requirement that the <code>$compare</code> function should have the traditional qualities
of equality comparison. The result is well-defined, for example, even if <code>$compare</code> is not transitive
or not symmetric.</p>
<p>A return value of <code>()</code> from the function is treated as <code>false</code>.</p>
</fos:notes>

<fos:examples>
Expand Down Expand Up @@ -14582,7 +14589,8 @@ return for-each(1 to 10, $mapping otherwise void#0)</eg></fos:expression>
or <code>false</code> to indicate that two items are or are not
equal, overriding the normal rules that would apply to those items;
or it can return an empty sequence, to indicate that the normal
rules should be followed.
rules should be followed. Note that returning <code>()</code>
is <emph>not</emph> equivalent to returning <code>false</code>.
</fos:meaning>
<fos:type>function(item(), item()) as xs:boolean?</fos:type>
<fos:default>fn:void#0</fos:default>
Expand Down Expand Up @@ -18826,7 +18834,7 @@ return $action($item, $pos)
<fos:signatures>
<fos:proto name="filter" return-type="item()*">
<fos:arg name="input" type="item()*" usage="navigation"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean" usage="inspection"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean?" usage="inspection"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -18851,14 +18859,14 @@ return $item
<fos:errors>
<p>As a consequence of the function signature and the function calling rules, a type error
occurs if the supplied <code>$predicate</code> function returns anything other than a single
<code>xs:boolean</code> item; there is no conversion to an effective boolean
value.</p>
<code>xs:boolean</code> item or an empty sequence; there is no conversion to an effective boolean
value, but an empty sequence is interpreted as false.</p>
</fos:errors>
<fos:notes>
<p>If <code>$predicate</code> is an arity-1 function,
the function call <code>fn:filter($input, $predicate)</code> has a very similar effect to the
expression <code>$input[$predicate(.)]</code>. There are some differences, however. In the case of
<code>fn:filter</code>, the function <code>$F</code> is required to return a boolean;
<code>fn:filter</code>, the function <code>$F</code> is required to return an optional boolean;
there is no special treatment for numeric predicate values, and no conversion to an
effective boolean value. Also, with a filter expression <code>$input[$predicate(.)]</code>,
the focus within the predicate is different from that outside; this means that the use of a
Expand All @@ -18871,6 +18879,12 @@ return $item
<fos:expression>filter(1 to 10, fn($a) { $a mod 2 = 0 })</fos:expression>
<fos:result>(2, 4, 6, 8, 10)</fos:result>
</fos:test>
<fos:test>
<fos:expression><eg><![CDATA[filter(parse-xml('<doc><a id="2"/><a/>')//a, fn{@id eq "2"})]]></eg></fos:expression>
<fos:result><![CDATA[<a id="2"/>]]></fos:result>
<fos:postamble>The function returns <code>()</code> when there is no <code>@id</code> attribute;
this is treated as false.</fos:postamble>
</fos:test>
</fos:example>
<fos:example>
<fos:test>
Expand All @@ -18890,7 +18904,8 @@ return filter(
</fos:example>
</fos:examples>
<fos:history>
<fos:version version="4.0">Changed in 4.0: Positional parameter added to predicate function.</fos:version>
<fos:version version="4.0">Changed in 4.0:
Positional parameter added to predicate function. Return type of predicate changed to boolean?</fos:version>
</fos:history>
</fos:function>
<fos:function name="fold-left" prefix="fn">
Expand Down Expand Up @@ -19530,7 +19545,7 @@ chain((1, 2, 3, 4), $product3)
<fos:signatures>
<fos:proto name="while-do" return-type="item()*">
<fos:arg name="input" type="item()*"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean" example="false#0"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean?" example="false#0"/>
<fos:arg name="action" type="function(item()*, xs:integer) as item()*"/>
</fos:proto>
</fos:signatures>
Expand All @@ -19552,7 +19567,7 @@ chain((1, 2, 3, 4), $product3)
</item>
<item>
<p><code>$predicate($input, $pos)</code> is evaluated. If the result is
<code>false</code>, the function returns the value of <code>$input</code>.</p>
<code>false</code> or <code>()</code>, the function returns the value of <code>$input</code>.</p>
</item>
<item>
<p>Otherwise, <code>$action($input, $pos)</code> is evaluated, the resulting value is
Expand Down Expand Up @@ -19678,7 +19693,7 @@ return $result?numbers
<fos:proto name="do-until" return-type="item()*">
<fos:arg name="input" type="item()*"/>
<fos:arg name="action" type="function(item()*, xs:integer) as item()*"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean?"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -19704,8 +19719,9 @@ return $result?numbers
<item>
<p><code>$predicate($input, $pos)</code> is evaluated. If the result is
<code>true</code>, the function returns the value of <code>$input</code>.
Otherwise , the process repeats from step 2 with <code>$pos</code> incremented by
Otherwise, the process repeats from step 2 with <code>$pos</code> incremented by
<code>1</code>.</p>
<p>When the predicate returns an empty sequence, this is treated as <code>false</code>.</p>
</item>
</olist>
<p>More formally, the function is equivalent to the following implementation in XQuery:</p>
Expand Down Expand Up @@ -21214,7 +21230,7 @@ map:for-each($map, fn($key, $value) { $key })
<fos:signatures>
<fos:proto name="keys-where" return-type="xs:anyAtomicType*">
<fos:arg name="map" type="map(*)" usage="inspection"/>
<fos:arg name="predicate" type="(function(xs:anyAtomicType, item()*) as xs:boolean)"/>
<fos:arg name="predicate" type="function(xs:anyAtomicType, item()*) as xs:boolean?"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -21231,7 +21247,8 @@ map:for-each($map, fn($key, $value) { $key })
<code>$predicate</code> function takes the key and the value of the corresponding
map entry as an argument, and the result is a sequence containing the keys of those
entries for which the predicate function returns <code>true</code> in <termref
def="implementation-dependent">implementation-dependent</termref> order.</p>
def="implementation-dependent">implementation-dependent</termref> order.
A return value of <code>()</code> is treated as <code>false</code>.</p>
<p>More formally, the function returns the value of the expression:</p>
<eg><![CDATA[
map:for-each($map, fn($key, $value) {
Expand Down Expand Up @@ -22032,7 +22049,7 @@ return <box>{
<fos:signatures>
<fos:proto name="filter" return-type="map(*)">
<fos:arg name="map" type="map(*)" usage="inspection"/>
<fos:arg name="predicate" type="function(xs:anyAtomicType, item()*) as xs:boolean"
<fos:arg name="predicate" type="function(xs:anyAtomicType, item()*) as xs:boolean?"
usage="inspection"/>
</fos:proto>
</fos:signatures>
Expand All @@ -22048,7 +22065,8 @@ return <box>{
<p>The function <code>map:filter</code> takes any <termref def="dt-map"
>map</termref> as its <code>$map</code> argument and applies the supplied function
to each entry in the map; the result is a new map containing those entries for which
the function returns <code>true</code>.</p>
the function returns <code>true</code>. A return value of <code>()</code> from the
predicate is treated as <code>false</code>.</p>

<p>The function supplied as <code>$predicate</code> takes two arguments. It is called
supplying the key of the map entry as the first argument, and the associated value as
Expand Down Expand Up @@ -25870,7 +25888,7 @@ array:index-of(
<fos:signatures>
<fos:proto name="index-where" return-type="xs:integer*">
<fos:arg name="array" type="array(*)"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean?"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -25885,9 +25903,11 @@ array:index-of(

<p>The result of the function is a sequence of integers, in monotonic ascending order, representing
the 1-based positions in the input array of those members for which the supplied predicate function
returns <code>true</code>.</p>
<p>More formally, the function returns the result of the expression:</p>
<eg>index-of($array => array:for-each($predicate) => array:values(), true())</eg>
returns <code>true</code>. A return value of <code>()</code> is treated as <code>false</code>.</p>
<p>More formally, the function returns the result of the XQuery expression:</p>
<eg>for member $m at $pos in $array
return $pos[$predicate($m, $pos)]</eg>
<!--<eg>index-of($array => array:for-each($predicate) => array:values(), true())</eg>-->
</fos:rules>

<fos:examples>
Expand Down Expand Up @@ -26469,7 +26489,7 @@ return [ $action($member, $pos) ]
<fos:signatures>
<fos:proto name="filter" return-type="array(*)">
<fos:arg name="array" type="array(*)" usage="inspection"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean" usage="inspection"/>
<fos:arg name="predicate" type="function(item()*, xs:integer) as xs:boolean?" usage="inspection"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -26480,23 +26500,24 @@ return [ $action($member, $pos) ]
</fos:properties>
<fos:summary>
<p>Returns an array containing those members of the <code>$array</code> for which
<code>$predicate</code> returns <code>true</code>.</p>
<code>$predicate</code> returns <code>true</code>. A return value of <code>()</code>
is treated as <code>false</code>.</p>
</fos:summary>
<fos:rules>
<p>Informally, the function returns an array containing those members of the input
array that satisfy the supplied predicate.</p>
<p>More formally, the function returns the result of the expression:</p>
<eg><![CDATA[
array:of-members(
for member $member in $array
for member $member at $pos in $array
where $predicate($member, $pos)
return $member
)]]></eg>
</fos:rules>
<fos:errors>
<p>As a consequence of the function signature and the function calling rules, a type error occurs if the supplied
function <code>$function</code> returns anything other than a single <code>xs:boolean</code> item; there is no conversion
to an effective boolean value.</p>
function <code>$function</code> returns anything other than a single <code>xs:boolean</code> item
or an empty sequence; there is no conversion to an effective boolean value.</p>
</fos:errors>
<fos:examples>
<fos:example>
Expand Down Expand Up @@ -28391,7 +28412,7 @@ tail(fold-left(
<fos:signatures>
<fos:proto name="every" return-type="xs:boolean">
<fos:arg name="input" type="item()*"/>
<fos:arg name="predicate" type="(function(item(), xs:integer) as xs:boolean)?"
<fos:arg name="predicate" type="(function(item(), xs:integer) as xs:boolean?)?"
default="fn:boolean#1" example="fn:boolean#1"/>
</fos:proto>
</fos:signatures>
Expand All @@ -28411,7 +28432,7 @@ every $boolean in (
return $predicate($item, $pos)
) satisfies $boolean
]]></eg>

<p>A return value of <code>()</code> from the predicate is treated as false.</p>
</fos:rules>
<fos:errors>
<p>An error is raised if the <code>$predicate</code> function raises an error. In particular,
Expand Down Expand Up @@ -28786,7 +28807,7 @@ function($item) {
<fos:signatures>
<fos:proto name="index-where" return-type="xs:integer*">
<fos:arg name="input" type="item()*"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean?"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -28801,7 +28822,8 @@ function($item) {

<p>The result of the function is a sequence of integers, in monotonic ascending order, representing
the 1-based positions in the input sequence of those items for which the supplied predicate function
returns <code>true</code>.</p>
returns <code>true</code>. A return value of <code>()</code> from the predicate function
is treated as <code>false</code>.</p>
<p>More formally, the function is equivalent to the following expression in XQuery:</p>
<eg>
for $item at $pos in $input
Expand Down Expand Up @@ -29016,7 +29038,7 @@ head(index-where($input, $predicate)) ! subsequence($input, . + 1)
<fos:signatures>
<fos:proto name="take-while" return-type="item()*">
<fos:arg name="input" type="item()*"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean"/>
<fos:arg name="predicate" type="function(item(), xs:integer) as xs:boolean?"/>
</fos:proto>
</fos:signatures>
<fos:properties>
Expand All @@ -29036,7 +29058,7 @@ return $it
]]></eg>
<p>That is, it returns all items in the sequence prior to the first one where the result of
calling the supplied <code>$predicate</code> function, with the current item and its position
as arguments, returns the value <code>false</code>.</p>
as arguments, returns the value <code>false</code> or <code>()</code>.</p>
</fos:rules>

<fos:notes>
Expand Down Expand Up @@ -29380,7 +29402,7 @@ subsequence($input, 1, head(index-where($input, $predicate)) + 1)
<fos:signatures>
<fos:proto name="some" return-type="xs:boolean">
<fos:arg name="input" type="item()*"/>
<fos:arg name="predicate" type="(function(item(), xs:integer) as xs:boolean)?"
<fos:arg name="predicate" type="(function(item(), xs:integer) as xs:boolean?)?"
default="fn:boolean#1" example="fn:boolean#1"/>
</fos:proto>
</fos:signatures>
Expand Down

0 comments on commit b118cd8

Please sign in to comment.