Changes

Jump to navigation Jump to search
1,418 bytes added ,  15:40, 27 February 2020
no edit summary
This module [[Module Library|XQuery Module]] adds some useful higher-order functions, additional to the [[Higher-Order Functions|higher-order]] [[Querying#Functions|XQuery functions]] that were left out of provided by the official spec. All functions are introduced with the <code>hof:</code> prefix, which is linked to the statically declared <code>http://basex.org/modules/hof</code> namespacespecification.
=FunctionsConventions=
All functions in this module are assigned to the <code><nowiki>http://basex.org/modules/hof</nowiki></code> namespace, which is statically bound to the {{Code|hof}} prefix.<br/> =Loops= ==hof:idfold-left1== {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:id</b>fold-left1|$seq as item()+, $expr f as function(item()*, item()) as item()*</code>|item()*}}
|-
| valign='top' | '''Summary'''|Returns its argument unchanged. This function isn't useful on its ownWorks the same as [[Higher-Order Functions#fn:fold-left|fn:fold-left]], but can does not need a seed, because the sequence must be used as argument to other highernon-order functionsempty.
|-
| valign='top' | '''Examples'''
|
* <code>{{Code|hof:idfold-left1(1 to 5)</code> returns <code>1 2 3 4 5</code>* With higher-order functions:<pre class="brush:xquery">let $sort-by := 10, function($fa, $seqb) { for $x in a + $seq order by $f($xb }) return $x }} returns {{Code|55}}.let $sort * {{Code|hof:= $sortfold-byleft1((hof:id#1, ?), $reverse-sort := $sort-by(function($xa, $b) { -$x a + $b }, ?)return ( $sort((1}} throws {{Code|XPTY0004}}, 5, 3, 2, 4)), 'because {{Code|', $reverseseq}} has to be non-sort((1, 5, 3, 2, 4)))</pre>returns: <code>1 2 3 4 5 | 5 4 3 2 1</code>empty.
|}
==hof:constuntil== {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:const</b>(until|$expr pred as function(item()*) as xs:boolean, $ignored f as function(item()*) as item()*</code>, $start as item()*|item()*}}
|-
| valign='top' | '''Summary'''|Returns its first argument unchanged and irgores Applies the secondpredicate function {{Code|$pred}} to {{Code|$start}}. This function isn't useful on its ownIf the result is {{Code|false}}, {{Code|$f}} is invoked with the start value – or, but can be used as argument to other higher-order functionssubsequently, e.g. when a with the result of this function combining two values is expected and one only wants to retain – until the left onepredicate function returns {{Code|true()}}.
|-
| valign='top' | '''Examples'''
|
* <code>hof:const(42, 1337)</code> returns <code>42</code>.* With higher-order functionsDoubles a numeric value until a maximum is reached:<pre classsyntaxhighlight lang="brush:xquery">let $zip-sum hof:= until( function($f, $seq1, $seq2output) { sum(map-pairs($foutput ge 1000 }, $seq1, $seq2)) }let $sum-all := $zip-sum(function($a, $binput ) { 2 * $a + $b input }, ?, ?), $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)
)
</presyntaxhighlight>* Another useCalculates the square-case: When inserting a key into root of a map, <code>$f</code> descides how to combine the new value with a possibly existing old one. <code>hofnumber by iteratively improving an initial guess:const</code> here means ignoring the old value, so that's normal insertion.<pre classsyntaxhighlight lang="brush:xquery">let $insert-with sqrt := function($f, $map, $k, $vinput as xs:double) as xs:double { let $old hof:= $mapuntil($k), $new := if function($oldresult) then { abs($f(result * $v, result - $oldinput) else $v< 0.00001 }, return map:newfunction($guess) { ($map, map{ guess + $k := input div $new guess) div 2 })), $input })let $map := map{ 'foo' := 1 }let return $add := $insert-with(functionsqrt($a, $b25) </syntaxhighlight>* Returns {{$a + $bCode|OK}}, ?, ?, ?),as the predicate is evaluated first: $insert :<syntaxhighlight lang= $insert-with("xquery">hof:const#2, ?, ?, ?)return until( $addfunction($map, 'foo', 2_){ true('foo')}, $insertfunction($map, 'foo', 42_){ error() }, 'fooOK')
)
</pre>returns <code>3 42</codesyntaxhighlight>
|}
==hof:foldscan-left1left== {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:foldscan-left1</b>(left|$f seq as function(item()*, $start as item()) *, $f as function(item()*, $seq as item()+) as item()*</code>|item()*}}
|-
| valign='top' | '''Summary'''|Works the same as This function is similar to [[Higher-Order_FunctionsOrder 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">declare function hof:scan-left($fseq, $seedacc, $f) { if(empty($seq)|fn) then $acc else ( $acc, hof:foldscan-left(tail($seq), $f, ($seedacc, head($seq)]]), but doesn't need a seed, because the sequence must be non-empty.$f) )};</syntaxhighlight>
|-
| valign='top' | '''Errors'''|''XPTY0004'' if <code>$seq</code> is empty|-| valign='top' | '''Examples'''
|
* Returns triangular numbers:<codesyntaxhighlight lang="xquery">hof:foldscan-left1left(function($a, $b) { $a + $b }, 1 to 10)</code> returns <code>55</code>.* <code>hof:fold-left1(, 0, function($a, $b) { $a + $b }, ())</codesyntaxhighlight> throws <code>XPTY0004</code>, because <code>$seq</code> has to be non-empty.
|}
==hof:untiltake-while== {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:until</b>(take-while|$pred seq as function(item()*) as xs:boolean, $f pred as function(item()*) as item()*, $start as item()*) as xs:boolean|item()*</code>}}
|-
| valign='top' | '''Summary'''|Applies the The function returns items of <code>$f</code> to the initial value <code>$startseq</code> until as long as the predicate <code>$pred</code> applied is satisfied. It is equivalent to the result returns :<codesyntaxhighlight lang="xquery">truedeclare function hof:take-while($seq, $pred) { if(empty($seq)or not($pred(head($seq)))) then () else ( head($seq), hof:take-while(tail($seq), $pred) )};</codesyntaxhighlight>.
|-
| valign='top' | '''Examples'''
|
* <code>hof:until(function($x) { $x ge 1000 }, function($y) { 2 * $y }Computes at most 100 random integers, 1)</code> returns <code>1024</code>.* Calculating the square-root of a number by iteratively improving but stops if an initial guessinteger is smaller than 10:<pre classsyntaxhighlight lang="brush:xquery">let $sqrt hof:= functiontake-while($x as xs:double) as xs:double { hof:until( function($res1 to 100) { abs! random:integer($res * $res - $x50) < 0.00001 }, function($guessx) { ($guess + $x div $guess) div 2 >= 10 }, $x )}return $sqrt(25)</pre>returns <code>5.000000000053722</codesyntaxhighlight>.
|}
 
=Sorting=
==hof:top-k-by==
 {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:top-k-by</b>(|$seq as item()*, $sort-key as function(item()) as item(), $k as xs:integer) as |item()*</code>}}
|-
| valign='top' | '''Summary'''|Returns the <code>{{Code|$k</code> }} items in <code>{{Code|$seq</code> }} that are greatest when sorted by the result of <code>{{Code|$f</code> }} applied to the item. The function is a much more efficient implementation of the following scheme:<pre classsyntaxhighlight lang="brush:xquery">( for $x in $seq order by $sort-key($x) descending return $x
)[position() <= $k]
</presyntaxhighlight>
|-
| valign='top' | 'Examples''Errors'|* {{Code|hof:top-k-by(1 to 1000, hof:id#1, 5)}} returns {{Code|1000 999 998 997 996}}* {{Code|hof:top-k-by(1 to 1000, function($x) { -$x }, 3)}} returns {{Code|1 2 3}}* <code>hof:top-k-by(<x a='1'|b='2'XPTY0004c='3' if <code/>$sort/@*, xs:integer#1, 2)/node-keyname()</code> doesnreturns {{Code|c b}}|} ==hof:top-k-with== {| width='100%'t return exactly one item
|-
| valignwidth='120' | '''Signatures'''|{{Func|hof:top-k-with|$seq as item()*, $lt as function(item(), item()) as xs:boolean, $k as xs:integer|item()*}}|-| '' 'Summary'''|Returns the {{Code|$k}} items in {{Code|$seq}} that are greatest when sorted in the order of the ''less-than'' predicate {{Code|$lt}}. The function is a general version of {{Code|hof:top-k-by($seq, $sort-key, $k)}}.|-| '''Examples'''
|
* <code>{{Code|hof:top-k-bywith(1 to 1000, hof:id#1function($a, $b) { $a lt $b }, 5)</code> }} returns <code>{{Code|1000 999 998 997 996</code>}}* <code>{{Code|hof:top-k-bywith(1 -5 to 10005, function($xa, $b) { -abs($a) gt abs($x b) }, 35)</code> }} returns <code>{{Code|0 1 -1 2 3</code>-2}}|} =IDs= ==hof:id== {| width='100%'|-| width='120' | '''Signatures'''* <code>|{{Func|hof:topid|$expr as item()*|item()*}}|-| '''Summary'''|Returns its argument unchanged. This function isn't useful on its own, but can be used as argument to other higher-korder functions.|-by(<x a=| ''1' b=Examples'2' c='|* {{Code|hof:id(1 to 5)}} returns {{Code|1 2 3'/4 5}}* With higher-order functions:<syntaxhighlight lang="xquery">/@*let $sort := sort(?, (), xshof:integerid#1)let $reverse-sort := sort(?, (), function($x) { -$x })return ( $sort((1, 5, 3, 2, 4)/node), '|', $reverse-namesort((1, 5, 3, 2, 4)))</codesyntaxhighlight> returns : <code>c b1 2 3 4 5 | 5 4 3 2 1</code>
|}
==hof:top-k-withconst== {|width='100%'
|-
| valign='top' width='90120' | '''Signatures'''|<code><b>{{Func|hof:top-k-with</b>(const|$seq expr as item()*, $lt ignored as function(item(), item()) as xs:boolean, $k as xs:integer) as *|item()*</code>}}
|-
| valign='top' | '''Summary'''|Returns its first argument unchanged and ignores the <code>$k</code> items in <code>$seq</code> that are greatest when sorted in the order of the second. This function isn''lesst useful on its own, but can be used as argument to other higher-than'' predicate <code>$lt</code>order functions, e.g. The when a function combining two values is a general version of <code>hof:top-k-by($seq, $sort-key, $k)</code>expected and one only wants to retain the left one.
|-
| valign='top' | '''Examples'''
|
* {{Code|hof:const(42, 1337)}} returns {{Code|42}}.* With higher-order functions:<codesyntaxhighlight lang="xquery">hoflet $zip-sum :top= function($f, $seq1, $seq2) { sum(for-keach-withpair(1 to 1000$seq1, $seq2, $f))}let $sum-all := $zip-sum(function($a, $b) { $a lt + $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))</code> returns <code>1000 999 998 997 996</codesyntaxhighlight>* Another use-case: When inserting a key into a map, {{Code|$f}} decides how to combine the new value with a possibly existing old one. {{Code|hof:const}} here means ignoring the old value, so that's normal insertion.<codesyntaxhighlight lang="xquery">hoflet $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:top-entry($k, $new)))}let $map := map { 'foo': 1 }let $add := $insert-with(-5 to 5, function($a, $b) { abs($a) gt abs(+ $b) }, 5?, ?, ?)</code> returns <code>0 1 let $ins := $insert-1 with(hof:const#2 -, ?, ?, ?)return ( $add($map, 'foo', 2)('foo'), $ins($map, 'foo', 42)('foo'))</codesyntaxhighlight>returns {{Code|3 42}}
|}
=Recent ChangesChangelog;Version 8.1 * Added: [[#hof:scan-left|hof:scan-left]], [[#hof:take-while|hof:take-while]] ;Version 7.2 * Added: [[#hof:top-k-by|hof:top-k-by]], [[#hof:top-k-with|hof:top-k-with]]* Removed: hof:iterate
* removed <code>hof:iterate</code>* added <code>hof:top-k-by</code> and <code>hof:top-k-with</code>;Version 7.0
[[Category:XQuery]]* module added
Bureaucrats, editor, reviewer, Administrators
13,550

edits

Navigation menu