This XQuery Module adds some useful higherorder functions, additional to the HigherOrder Functions provided by the official specification.
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:foldleft1
Signatures

hof:foldleft1($seq as item()+, $f as function(item()*, item()) as item()*) as item()*

Summary

Works the same as fn:foldleft, but does not need a seed, because the sequence must be nonempty.

Examples

hof:foldleft1(1 to 10, function($a, $b) { $a + $b }) returns 55 .
hof:foldleft1((), function($a, $b) { $a + $b }) throws XPTY0004 , because $seq has to be nonempty.

hof:until
Signatures

hof:until($pred as function(item()*) as xs:boolean, $f as function(item()*) as item()*, $start as item()*) as item()*

Summary

Applies the predicate function $pred to $start . If the result is false , $f is invoked with the start value – or, subsequently, with the result of this function – until the predicate function returns true() .

Examples

 Doubles a numeric value until a maximum is reached:
hof:until(
function($output) { $output ge 1000 },
function($input ) { 2 * $input },
1
)
 Calculates the squareroot of a number by iteratively improving an initial guess:
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)
 Returns
OK , as the predicate is evaluated first:
hof:until(
function($_) { true() },
function($_) { error() },
'OK'
)

hof:scanleft
Signatures

hof:scanleft($seq as item()*, $start as item()*, $f as function(item()*, item()) as item()*) as item()*

Summary

This function is similar to fn:foldleft, but it returns a list of successive reduced values from the left. It is equivalent to:
declare function hof:scanleft($seq, $acc, $f) {
if(empty($seq)) then $acc else (
$acc,
hof:scanleft(tail($seq), $f($acc, head($seq)), $f)
)
};

Examples

 Returns triangular numbers:
hof:scanleft(1 to 10, 0, function($a, $b) { $a + $b })

hof:takewhile
Signatures

hof:takewhile($seq as item()*, $pred as function(item()) as xs:boolean) as item()*

Summary

The function returns items of $seq as long as the predicate $pred is satisfied. It is equivalent to:
declare function hof:takewhile($seq, $pred) {
if(empty($seq) or not($pred(head($seq)))) then () else (
head($seq),
hof:takewhile(tail($seq), $pred)
)
};

Examples

 Computes at most 100 random integers, but stops if an integer is smaller than 10:
hof:takewhile(
(1 to 100) ! random:integer(50),
function($x) { $x >= 10 }
)

hof:takewhile
Introduced with Version 9.5.
Signatures

hof:dropwhile($seq as item()*, $pred as function(item()) as xs:boolean) as item()*

Summary

The function skips all items of $seq until the predicate $pred is not satisfied anymore. It is equivalent to:
declare function hof:dropwhile($seq, $pred) {
if($pred(head($seq))) then (
hof:dropwhile(tail($seq), $pred)
) else (
$seq
)
};

Examples

Returns the name of the first file that does not exist on disk:
hof:dropwhile(
(1 to 1000) ! (.  '.log'),
file:exists#1
)[1]

Sorting
hof:topkby
Signatures

hof:topkby($seq as item()*, $sortkey as function(item()) as item(), $k as xs:integer) as item()*

Summary

Returns the $k items in $seq that are greatest when sorted by the result of $f applied to the item. The function is a much more efficient implementation of the following scheme:
(for $x in $seq
order by $sortkey($x) descending
return $x
)[position() <= $k]

Examples

hof:topkby(1 to 1000, hof:id#1, 5) returns 1000 999 998 997 996
hof:topkby(1 to 1000, function($x) { $x }, 3) returns 1 2 3
hof:topkby(<x a='1' b='2' c='3'/>/@*, xs:integer#1, 2)/nodename() returns c b

hof:topkwith
Signatures

hof:topkwith($seq as item()*, $lt as function(item(), item()) as xs:boolean, $k as xs:integer) as item()*

Summary

Returns the $k items in $seq that are greatest when sorted in the order of the lessthan predicate $lt . The function is a general version of hof:topkby($seq, $sortkey, $k) .

Examples

hof:topkwith(1 to 1000, function($a, $b) { $a lt $b }, 5) returns 1000 999 998 997 996
hof:topkwith(5 to 5, function($a, $b) { abs($a) gt abs($b) }, 5) returns 0 1 1 2 2

IDs
hof:id
Signatures

hof:id($expr as item()*) as item()*

Summary

Returns its argument unchanged. This function isn't useful on its own, but can be used as argument to other higherorder functions.

Examples

hof:id(1 to 5) returns 1 2 3 4 5
 With higherorder functions:
let $sort := sort(?, (), hof:id#1)
let $reversesort := sort(?, (), function($x) { $x })
return (
$sort((1, 5, 3, 2, 4)),
'',
$reversesort((1, 5, 3, 2, 4))
)
returns: 1 2 3 4 5  5 4 3 2 1

hof:const
Signatures

hof:const($expr as item()*, $ignored 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 higherorder functions, e.g. when a function combining two values is expected and one only wants to retain the left one.

Examples

hof:const(42, 1337) returns 42 .
 With higherorder functions:
let $zipsum := function($f, $seq1, $seq2) {
sum(foreachpair($seq1, $seq2, $f))
}
let $sumall := $zipsum(function($a, $b) { $a + $b }, ?, ?)
let $sumleft := $zipsum(hof:const#2, ?, ?)
return (
$sumall((1, 1, 1, 1, 1), 1 to 5),
$sumleft((1, 1, 1, 1, 1), 1 to 5)
)
 Another usecase: When inserting a key into a map,
$f decides how to combine the new value with a possibly existing old one. hof:const here means ignoring the old value, so that's normal insertion.
let $insertwith := 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 := $insertwith(function($a, $b) { $a + $b }, ?, ?, ?)
let $ins := $insertwith(hof:const#2, ?, ?, ?)
return (
$add($map, 'foo', 2)('foo'),
$ins($map, 'foo', 42)('foo')
)
returns 3 42

Changelog
 Version 9.5
 Version 8.1
 Version 7.2
 Version 7.0