Changes

Jump to navigation Jump to search
474 bytes added ,  14:17, 27 February 2020
no edit summary
The most general function type is <code>function(*)</code>. It's the type of all function items. The following query for example goes through a list of XQuery items and, if it is a function item, prints its arity:
<pre classsyntaxhighlight lang="brush:xquery">
for $item in (1, 'foo', fn:concat#3, function($a) { 42 * $a })
where $item instance of function(*)
return fn:function-arity($item)
</presyntaxhighlight>
''Result:'' <code>3 1</code>
The notation for specifying argument and return types is quite intuitive, as it closely resembles the function declaration. The XQuery function
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:char-at(
$str as xs:string,
fn:substring($str, $pos, 1)
};
</presyntaxhighlight>
for example has the type <code>function(xs:string, xs:integer) as xs:string</code>. It isn't possible to specify only the argument and not the result type or the other way round. A good place-holder to use when no restriction is wanted is <code>item()*</code>, as it matches any XQuery value.
Function types can also be nested. As an example we take <code>local:on-sequences</code>, which takes a function defined on single items and makes it work on sequences as well:
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:on-sequences(
$fun as function(item()) as item()*
fn:for-each($fun, ?)
};
</presyntaxhighlight>
We willl see later how <code>fn:for-each(...)</code> works. The type of <code>local:on-sequences(...)</code> on the other hand is easily constructed, if a bit long:
|
<ul><li>Square all numbers from 1 to 10:
<pre classsyntaxhighlight lang="brush:xquery">
fn:for-each(1 to 10, math:pow(?, 2))
</presyntaxhighlight>
''Result:'' <code>1 4 9 16 25 36 49 64 81 100</code>
</li>
<li>Apply a list of functions to a string:
<pre classsyntaxhighlight lang="brush:xquery">
let $fs := (
fn:upper-case#1,
)
return fn:for-each($fs, function($f) { $f('foobar') })
</presyntaxhighlight>
''Result:'' <code>FOOBAR bar 6</code>
</li>
<li>Process each item of a sequence with the arrow operator:
<pre classsyntaxhighlight lang="brush:xquery">
("one", "two", "three") => fn:for-each(fn:upper-case(?))
</presyntaxhighlight>
''Result:'' <code>ONE TWO THREE</code>
</li></ul>
| '''XQuery 1.0'''
|At the core, for-each is nothing else than a simple FLWOR expression:
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:for-each(
$seq as item()*,
return $fun($s)
};
</presyntaxhighlight>
|}
| '''Examples'''
|<ul><li>All even integers until 10:
<pre classsyntaxhighlight lang="brush:xquery">
fn:filter(1 to 10, function($x) { $x mod 2 eq 0 })
</presyntaxhighlight>
''Result:'' <code>2 4 6 8 10</code>
</li>
<li>Strings that start with an upper-case letter:
<pre classsyntaxhighlight lang="brush:xquery">
let $first-upper := function($str) {
let $first := fn:substring($str, 1, 1)
}
return fn:filter(('FooBar', 'foo', 'BAR'), $first-upper)
</presyntaxhighlight>
''Result:'' <code>FooBar BAR</code>
</li>
<li>Inefficient prime number generator:
<pre classsyntaxhighlight lang="brush:xquery">
let $is-prime := function($x) {
$x gt 1 and (every $y in 2 to ($x - 1) satisfies $x mod $y ne 0)
}
return filter(1 to 20, $is-prime)
</presyntaxhighlight>
''Result:'' <code>2 3 5 7 11 13 17 19</code>
</li></ul>
| '''Note'''
|<code>fn:filter</code> can be easily implemented with <code>fn:for-each</code>:
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:filter($seq, $pred) {
for-each(
)
};
</presyntaxhighlight>
|-
| '''XQuery 1.0'''
|At the core, for-each is nothing else than a filter expression:
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:filter(
$seq as item()*,
$seq[$pred(.)]
};
</presyntaxhighlight>
|}
| '''Examples'''
|<ul><li>Adding one to the numbers at odd positions:
<pre classsyntaxhighlight lang="brush:xquery">
fn:for-each-pair(
fn:for-each(1 to 10, function($x) { $x mod 2 }),
function($a, $b) { $a + $b }
)
</presyntaxhighlight>
''Result:'' <code>2 1 2 1 2</code>
</li>
<li>Line numbering:
<pre classsyntaxhighlight lang="brush:xquery">
let $number-words := function($str) {
fn:string-join(
}
return $number-words('how are you?')
</presyntaxhighlight>
''Result:''
<pre classsyntaxhighlight lang="brush:xquery">
1: how
2: are
3: you?
</presyntaxhighlight>
</li>
<li>Checking if a sequence is sorted:
<pre classsyntaxhighlight lang="brush:xquery">
let $is-sorted := function($seq) {
every $b in
$is-sorted((1, 2, 42, 4, 5))
)
</presyntaxhighlight>
''Result:'' <code>true false</code></li></ul>
|-
| '''XQuery 1.0'''
|<pre classsyntaxhighlight lang="brush:xquery">
declare function local:for-each-pair(
$seq1 as item()*,
return $fun($seq1[$pos], $seq2[$pos])
};
</presyntaxhighlight>
|}
Calculating the ''product'' of a sequence of integers for example is easy in <code>Java</code>:
<pre classsyntaxhighlight lang="brush:java">
public int product(int[] seq) {
int result = 1;
return result;
}
</presyntaxhighlight>
Nice and efficient implementations using folds will be given below.
|The ''left fold'' traverses the sequence from the left.
The query <code>fn:fold-left(1 to 5, 0, $f)</code> for example would be evaluated as:
<pre classsyntaxhighlight lang="brush:xquery">
$f($f($f($f($f(0, 1), 2), 3), 4), 5)
</presyntaxhighlight>
|-
| '''Examples'''
|<ul><li>Product of a sequence of integers:
<pre classsyntaxhighlight lang="brush:xquery">
fn:fold-left(1 to 5, 1,
function($result, $curr) { $result * $curr }
)
</presyntaxhighlight>
''Result:'' <code>120</code>
</li>
<li>Illustrating the evaluation order:
<pre classsyntaxhighlight lang="brush:xquery">
fn:fold-left(1 to 5, '$seed',
concat('$f(', ?, ', ', ?, ')')
)
</presyntaxhighlight>
''Result:'' <code>$f($f($f($f($f($seed, 1), 2), 3), 4), 5)</code>
</li>
<li>Building a decimal number from digits:
<pre classsyntaxhighlight lang="brush:xquery">
let $from-digits := fold-left(?, 0,
function($n, $d) { 10 * $n + $d }
$from-digits((4, 2))
)
</presyntaxhighlight>
''Result:'' <code>12345 42</code>
</li></ul>
| '''XQuery 1.0'''
|As folds are more general than ''FLWOR'' expressions, the implementation isn't as concise as the former ones:
<pre classsyntaxhighlight lang="brush:xquery">
declare function local:fold-left(
$seq as item()*,
)
};
</presyntaxhighlight>
|}
|The ''right fold'' <code>fn:fold-right($seq, $seed, $fun)</code> traverses the sequence from the right.
The query <code>fn:fold-right(1 to 5, 0, $f)</code> for example would be evaluated as:
<pre classsyntaxhighlight lang="brush:xquery">
$f(1, $f(2, $f(3, $f(4, $f(5, 0)))))
</presyntaxhighlight>
|-
| '''Examples'''
|<ul><li>Product of a sequence of integers:
<pre classsyntaxhighlight lang="brush:xquery">
fn:fold-right(1 to 5, 1,
function($curr, $result) { $result * $curr }
)
</presyntaxhighlight>
''Result:'' <code>120</code>
</li>
<li>Illustrating the evaluation order:
<pre classsyntaxhighlight lang="brush:xquery">
fn:fold-right(1 to 5, '$seed',
concat('$f(', ?, ', ', ?, ')')
)
</presyntaxhighlight>
''Result:'' <code>$f(1, $f(2, $f(3, $f(4, $f(5, $seed)))))</code>
</li>
<li>Reversing a sequence of items:
<pre classsyntaxhighlight lang="brush:xquery">
let $reverse := fn:fold-right(?, (),
function($item, $rev) {
)
return $reverse(1 to 10)
</presyntaxhighlight>
''Result:'' <code>10 9 8 7 6 5 4 3 2 1</code>
</li></ul>
|-
| '''XQuery 1.0'''
|<pre classsyntaxhighlight lang="brush:xquery">
declare function local:fold-right(
$seq as item()*,
)
};
</presyntaxhighlight>
Note that the order of the arguments of <code>$fun</code> are inverted compared to that in <code>fn:fold-left(...)</code>.
|}
Bureaucrats, editor, reviewer, Administrators
13,550

edits

Navigation menu