Skip to content

Commit

Permalink
Merge pull request #1233 from Arithmeticus/xqfo-chain
Browse files Browse the repository at this point in the history
517 Major edits to fn:chain, clarification only
  • Loading branch information
ndw authored Jun 5, 2024
2 parents 474fd37 + 735fb20 commit 1fcff20
Showing 1 changed file with 60 additions and 82 deletions.
142 changes: 60 additions & 82 deletions specifications/xpath-functions-40/src/function-catalog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19423,41 +19423,46 @@ return fold-right(
<fos:property>focus-independent</fos:property>
</fos:properties>
<fos:summary>
<p>
Applies from left to right on an initial argument a chain of functions provided in a sequence.
</p>
<p>Applies a sequence of functions starting with an initial
input.</p>
</fos:summary>
<fos:rules>
<p>Informally, the function behaves as follows:</p>
<olist>
<item>
<p>
If <code>$functions</code> is empty, then <code>$input</code> is returned. Else,
</p>
</item>
<item>
<p>
The first function in <code>$functions</code> is applied on the provided
<code>$input</code>.
</p>
</item>
<item>
<p>
Then the next function in <code>$functions</code> (if such exists), is applied on the result,
and so on...
</p>
</item>
<item>
<p>
Finally the last function in <code>$functions</code> is applied on the latest-result obtained so far,
and the result of this final function application is the result of calling <code>fn:chain($input, $functions)</code> .
</p>
</item>
</olist>
<p>More formally, the function is equivalent to the following implementation in XPath:</p>
<eg>
<fos:rules>
<p>Informally, the function behaves as follows:</p>
<olist>
<item>
<p>If <code>$functions</code> is empty, then <code>$input</code> is returned,
otherwise let <code>$f</code> be the first member of <code>$functions</code>.</p>
</item>
<item>
<p>Let <code>$current-output</code> be the result of <code>fn:apply($f,
$input-array)</code> where <code>$input-array</code> is constructed according
to the following rules. <olist>
<item>
<p>If <code>$f</code> has arity 1, let <code>$input-array</code> be an array
containing <code>$input</code> as a single member.</p>
</item>
<item>
<p>Otherwise (<code>$f</code> has arity not equal to 1) if <code>$input</code> is
not an array then let <code>$input-array</code> be an array containing each
item of <code>$input</code> as a separate member. </p>
</item>
<item>
<p>Otherwise (<code>$f</code> has arity not equal to 1<code> and $input</code> is
already an array) let <code>$input-array</code> be <code>$input</code> itself.</p>
</item>
</olist>
</p>
</item>
<item>
<p>Repeat the process from step 1, passing <code>$current-output</code> as
<code>$input</code> and <code>fn:tail($functions)</code> as
<code>$functions</code>.</p>
</item>
</olist>
<p>More formally, the function is equivalent to the following implementation in XPath:</p>
<eg>
<![CDATA[let $chain := (
let $apply := fn($x, $f) {
let $apply := function($x, $f) {
fn:apply($f,
if (function-arity($f) eq 1) then [ $x ]
else if ($x instance of array(*)) then $x
Expand All @@ -19468,58 +19473,31 @@ return fold-right(
fold-left($functions, $input, $apply)
}
)]]>
</eg>
</fos:rules>
</eg>
</fos:rules>
<fos:errors>
<p>A type error is raised <errorref class="AP" code="0001" type="type"
/> if the current result does not match the arity
and the type(s) of the argument(s) of the next function in the chain,
that is, it is a sequence or an array of <code>M</code> items/members and <code>M ne function-arity(current-function)</code>
or <errorref class="RG" code="0006" type="type"/>
if the items /members of the current result cannot be coerced to the required types of the arguments of the next function.</p>
<p>An error <errorref class="AP" code="0001" type="type"/> is raised if the arity of any
function <code>$f</code> in <code>$functions</code> is different from the number of
members in the array that is passed to <code>fn:apply</code>.</p>
<p>An error <errorref class="RG" code="0006" type="type"/> is raised if any item supplied as
a function argument cannot be coerced to the required type.</p>
</fos:errors>

<fos:notes>
<olist>
<item>
<p>
Contrary to the right-to-left evaluation of function-composition as defined in Math, here the functions in
<code>$functions</code> are evaluated in their order from left-to-right (the first function is evaluated first,
then the second,..., and the last function is evaluated last).
</p>
</item>
<item>
<p>
It is not a requirement that every function in <code>$functions</code> must have arity of one.
In fact, each of these functions can have any arity.
</p>
</item>
<item>
<p>
For a function with arity <code>N</code>, greater than <code>1</code>,
the result produced by the application of the previous function must be either a sequence
with <code>N</code> items, or, if some of the parameters of the function could be sequences themselves,
then an array with<code>N</code> members, and each of these <code>N</code> members is passed
by the implementation in the function call as the corresponding argument of this function.
</p>
</item>
<item>
<p>
A consequence of the provided rules is that a type error occurs if the current result does not match the arity
and the type(s) of the argument(s) of the next function in the chain,
that is, it is a sequence or an array of <code>M</code> items/members and <code>M ne function-arity(current-function)</code>
or the items /members of the current result cannot be coerced to the required types of the arguments of the next function.
</p>
</item>
<item>
<p>
In very simple cases, when it may be possible to use short and meaningful static expressions, one could consider
using chaining provided via the arrow operators.
In all such cases one should carefully consider the fact that any such desicion could result in longer and less-understandable
expressions, would involve one or more operators (not needed if <code>fn:chain</code> is used), and the loss of reusability.
</p>
</item>
</olist>
<fos:notes>
<olist>
<item>
<p>Functions are applied in sequence order, not right-to-left (as might be expected in
mathematical composition).</p>
</item>
<item>
<p>It is not a requirement that every function in <code>$functions</code> must have
arity of one. Any function may have any arity. </p>
</item>
<item>
<p>Using <code>fn:chain</code> may result in more readable XPath expressions than
chaining expressions using arrow operators.</p>
</item>
</olist>
</fos:notes>
<fos:examples>
<fos:variable name="incr" id="chain-variable-incr"
Expand Down

0 comments on commit 1fcff20

Please sign in to comment.