Difference between revisions of "Higher-Order Functions Module"
m (Text replacement - "'''Signatures'''" to "'''Signature'''") |
|||
Line 13: | Line 13: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:fold-left1( | |<pre>hof:fold-left1( | ||
− | $ | + | $input as item()+, |
− | $ | + | $action as function(item()*, item()) as item()* |
− | |||
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
Line 33: | Line 32: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:until( | |<pre>hof:until( | ||
− | $ | + | $predicate as function(item()*) as xs:boolean, |
− | $ | + | $action as function(item()*) as item()*, |
− | $ | + | $zero as item()* |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Applies the predicate function {{Code|$ | + | |Applies the predicate function {{Code|$predicate}} to {{Code|$zero}}. If the result is {{Code|false}}, {{Code|$action}} is invoked with the start value – or, subsequently, with the result of this function – until the predicate function returns {{Code|true()}}. |
|- valign="top" | |- valign="top" | ||
| '''Examples''' | | '''Examples''' | ||
Line 78: | Line 77: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:scan-left( | |<pre>hof:scan-left( | ||
− | $ | + | $input as item()*, |
− | $ | + | $zero as item()*, |
− | $ | + | $action as function(item()*, item()) as item()* |
− | |||
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
Line 87: | Line 85: | ||
|This function is similar to [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but it returns a list of successive reduced values from the left. It is equivalent to: | |This function is similar to [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but it returns a list of successive reduced values from the left. It is equivalent to: | ||
<syntaxhighlight lang="xquery"> | <syntaxhighlight lang="xquery"> | ||
− | declare function hof:scan-left($ | + | declare function hof:scan-left($input, $acc, $action) { |
− | if(empty($ | + | if(empty($input)) then $acc else ( |
$acc, | $acc, | ||
− | hof:scan-left(tail($ | + | hof:scan-left(tail($input), $action($acc, head($input)), $action) |
) | ) | ||
}; | }; | ||
Line 109: | Line 107: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:take-while( | |<pre>hof:take-while( | ||
− | $ | + | $input as item()*, |
− | $ | + | $predicate as function(item()) |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |The function returns items of <code>$ | + | |The function returns items of <code>$input</code> as long as the <code>$predicate</code> is satisfied. It is equivalent to: |
<syntaxhighlight lang="xquery"> | <syntaxhighlight lang="xquery"> | ||
− | declare function hof:take-while($ | + | declare function hof:take-while($input, $predicate) { |
− | if(empty($ | + | if(empty($input) or not($predicate(head($input)))) then () else ( |
− | head($ | + | head($input), |
− | hof:take-while(tail($ | + | hof:take-while(tail($input), $predicate) |
) | ) | ||
}; | }; | ||
Line 141: | Line 139: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:drop-while( | |<pre>hof:drop-while( | ||
− | $ | + | $input as item()* |
− | $ | + | $predicate as function(item()*) as xs:boolean |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |The function skips all items of <code>$ | + | |The function skips all items of <code>$input</code> until the <code>$predicate</code> is not satisfied anymore. It is equivalent to: |
<syntaxhighlight lang="xquery"> | <syntaxhighlight lang="xquery"> | ||
− | declare function hof:drop-while($ | + | declare function hof:drop-while($input, $predicate) { |
− | if($ | + | if($predicate(head($input))) then ( |
− | hof:drop-while(tail($ | + | hof:drop-while(tail($input), $predicate) |
) else ( | ) else ( | ||
− | $ | + | $input |
) | ) | ||
}; | }; | ||
Line 175: | Line 173: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:top-k-by( | |<pre>hof:top-k-by( | ||
− | $ | + | $input as item()* |
− | $ | + | $key as function(item()) as item() |
− | $k | + | $k as xs:integer |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Returns the {{Code|$k}} items in {{Code|$ | + | |Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted by the result of {{Code|$key}} applied to the item. The function is a much more efficient implementation of the following scheme: |
<syntaxhighlight lang="xquery"> | <syntaxhighlight lang="xquery"> | ||
− | (for $ | + | (for $item in $input |
− | order by $ | + | order by $key($item) descending |
− | return $ | + | return $item |
)[position() <= $k] | )[position() <= $k] | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 202: | Line 200: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:top-k-with( | |<pre>hof:top-k-with( | ||
− | $ | + | $input as item()* |
− | $ | + | $comparator as function(item(), item()) as xs:boolean |
− | + | $k as xs:integer | |
− | $k | ||
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Returns the {{Code|$k}} items in {{Code|$ | + | |Returns the {{Code|$k}} items in {{Code|$input}} that are greatest when sorted in the order of the ''less-than'' predicate {{Code|$comparator}}. The function is a general version of {{Function||hof:top-k-by}}. |
|- valign="top" | |- valign="top" | ||
| '''Examples''' | | '''Examples''' | ||
Line 225: | Line 222: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:id( | |<pre>hof:id( | ||
− | $ | + | $input as item()* |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Returns its argument unchanged. This function isn’t useful on its own, but can be used as argument to other higher-order functions. | + | |Returns its argument unchanged. This function isn’t useful on its own, but can be used as an argument to other higher-order functions. |
|- valign="top" | |- valign="top" | ||
| '''Examples''' | | '''Examples''' | ||
Line 253: | Line 250: | ||
| width='120' | '''Signature''' | | width='120' | '''Signature''' | ||
|<pre>hof:const( | |<pre>hof:const( | ||
− | $ | + | $input as item()*, |
− | $ | + | $ignore as item()* |
) as item()*</pre> | ) as item()*</pre> | ||
|- valign="top" | |- valign="top" | ||
| '''Summary''' | | '''Summary''' | ||
− | |Returns its first argument unchanged and ignores the second. This function isn’t useful on its own, but can be used as argument to other higher-order functions, e.g. when a function combining two values is expected and one only wants to retain the left one. | + | |Returns its first argument unchanged and ignores the second. This function isn’t useful on its own, but can be used as argument to other higher-order functions, e.g., when a function combining two values is expected and one only wants to retain the left one. |
|- valign="top" | |- valign="top" | ||
| '''Examples''' | | '''Examples''' |
Revision as of 15:41, 9 March 2023
This XQuery Module adds some useful higher-order functions, additional to the Higher-Order Functions provided by the official specification.
Contents
Conventions
All functions in this module are assigned to the http://basex.org/modules/hof
namespace, which is statically bound to the hof
prefix.
Loops
hof:fold-left1
Signature | hof:fold-left1( $input as item()+, $action as function(item()*, item()) as item()* ) as item()* |
Summary | Works the same as fn:fold-left, but does not need a seed, because the sequence must be non-empty. |
Examples |
|
hof:until
Signature | hof:until( $predicate as function(item()*) as xs:boolean, $action as function(item()*) as item()*, $zero as item()* ) as item()* |
Summary | Applies the predicate function $predicate to $zero . If the result is false , $action is invoked with the start value – or, subsequently, with the result of this function – until the predicate function returns true() .
|
Examples |
<syntaxhighlight lang="xquery"> hof:until( function($output) { $output ge 1000 }, function($input ) { 2 * $input }, 1 ) </syntaxhighlight>
<syntaxhighlight lang="xquery"> let $sqrt := function($input as xs:double) as xs:double { hof:until( function($result) { abs($result * $result - $input) < 0.00001 }, function($guess) { ($guess + $input div $guess) div 2 }, $input ) } return $sqrt(25) </syntaxhighlight>
<syntaxhighlight lang="xquery"> hof:until( function($_) { true() }, function($_) { error() }, 'OK' ) </syntaxhighlight> |
hof:scan-left
Signature | hof:scan-left( $input as item()*, $zero as item()*, $action as function(item()*, item()) as item()* ) as item()* |
Summary | This function is similar to fn:fold-left, but it returns a list of successive reduced values from the left. It is equivalent to:
<syntaxhighlight lang="xquery"> declare function hof:scan-left($input, $acc, $action) { if(empty($input)) then $acc else ( $acc, hof:scan-left(tail($input), $action($acc, head($input)), $action) ) }; </syntaxhighlight> |
Examples |
<syntaxhighlight lang="xquery"> hof:scan-left(1 to 10, 0, function($a, $b) { $a + $b }) </syntaxhighlight> |
hof:take-while
Signature | hof:take-while( $input as item()*, $predicate as function(item()) ) as item()* |
Summary | The function returns items of $input as long as the $predicate is satisfied. It is equivalent to:
<syntaxhighlight lang="xquery"> declare function hof:take-while($input, $predicate) { if(empty($input) or not($predicate(head($input)))) then () else ( head($input), hof:take-while(tail($input), $predicate) ) }; </syntaxhighlight> |
Examples |
<syntaxhighlight lang="xquery"> hof:take-while( (1 to 100) ! random:integer(50), function($x) { $x >= 10 } ) </syntaxhighlight> |
hof:drop-while
Signature | hof:drop-while( $input as item()* $predicate as function(item()*) as xs:boolean ) as item()* |
Summary | The function skips all items of $input until the $predicate is not satisfied anymore. It is equivalent to:
<syntaxhighlight lang="xquery"> declare function hof:drop-while($input, $predicate) { if($predicate(head($input))) then ( hof:drop-while(tail($input), $predicate) ) else ( $input ) }; </syntaxhighlight> |
Examples | Returns the name of the first file that does not exist on disk:
<syntaxhighlight lang="xquery"> hof:drop-while( (1 to 1000) ! (. || '.log'), file:exists#1 )[1] </syntaxhighlight> |
Sorting
hof:top-k-by
Signature | hof:top-k-by( $input as item()* $key as function(item()) as item() $k as xs:integer ) as item()* |
Summary | Returns the $k items in $input that are greatest when sorted by the result of $key applied to the item. The function is a much more efficient implementation of the following scheme:
<syntaxhighlight lang="xquery"> (for $item in $input order by $key($item) descending return $item )[position() <= $k] </syntaxhighlight> |
Examples |
|
hof:top-k-with
Signature | hof:top-k-with( $input as item()* $comparator as function(item(), item()) as xs:boolean $k as xs:integer ) as item()* |
Summary | Returns the $k items in $input that are greatest when sorted in the order of the less-than predicate $comparator . The function is a general version of hof:top-k-by .
|
Examples |
|
IDs
hof:id
Signature | hof:id( $input as item()* ) as item()* |
Summary | Returns its argument unchanged. This function isn’t useful on its own, but can be used as an argument to other higher-order functions. |
Examples |
<syntaxhighlight lang="xquery"> let $sort := sort(?, (), hof:id#1) let $reverse-sort := sort(?, (), function($x) { -$x }) return ( $sort((1, 5, 3, 2, 4)), '|', $reverse-sort((1, 5, 3, 2, 4)) )
</syntaxhighlight>
returns: |
hof:const
Signature | hof:const( $input as item()*, $ignore as item()* ) as item()* |
Summary | Returns its first argument unchanged and ignores the second. This function isn’t useful on its own, but can be used as argument to other higher-order functions, e.g., when a function combining two values is expected and one only wants to retain the left one. |
Examples |
<syntaxhighlight lang="xquery"> let $zip-sum := function($f, $seq1, $seq2) { sum(for-each-pair($seq1, $seq2, $f)) } let $sum-all := $zip-sum(function($a, $b) { $a + $b }, ?, ?) let $sum-left := $zip-sum(hof:const#2, ?, ?) return ( $sum-all((1, 1, 1, 1, 1), 1 to 5), $sum-left((1, 1, 1, 1, 1), 1 to 5) ) </syntaxhighlight>
<syntaxhighlight lang="xquery"> let $insert-with := function($f, $map, $k, $v) { let $old := $map($k) let $new := if($old) then $f($v, $old) else $v return map:merge(($map, map:entry($k, $new))) } let $map := map { 'foo': 1 } let $add := $insert-with(function($a, $b) { $a + $b }, ?, ?, ?) let $ins := $insert-with(hof:const#2, ?, ?, ?) return ( $add($map, 'foo', 2)('foo'), $ins($map, 'foo', 42)('foo') )
</syntaxhighlight>
returns |
Changelog
- Version 9.5
- Added:
hof:drop-while
- Version 8.1
- Added:
hof:scan-left
,hof:take-while
- Version 7.2
- Added:
hof:top-k-by
,hof:top-k-with
- Removed: hof:iterate
- Version 7.0
- module added