# Higher-Order Functions Module

(Redirected from Hof Module)
Jump to navigation Jump to search

This XQuery Module adds some useful higher-order functions, additional to the Higher-Order 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:fold-left1

 Signatures `hof:fold-left1(\$seq as item()+, \$f 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:fold-left1(1 to 10, function(\$a, \$b) { \$a + \$b })` returns `55`. `hof:fold-left1((), function(\$a, \$b) { \$a + \$b })` throws `XPTY0004`, because `\$seq` has to be non-empty.

## 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 square root 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:scan-left

 Signatures `hof:scan-left(\$seq as item()*, \$start as item()*, \$f 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: ```declare function hof:scan-left(\$seq, \$acc, \$f) { if(empty(\$seq)) then \$acc else ( \$acc, hof:scan-left(tail(\$seq), \$f(\$acc, head(\$seq)), \$f) ) }; ``` Examples Returns triangular numbers: ```hof:scan-left(1 to 10, 0, function(\$a, \$b) { \$a + \$b }) ```

## hof:take-while

 Signatures `hof:take-while(\$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:take-while(\$seq, \$pred) { if(empty(\$seq) or not(\$pred(head(\$seq)))) then () else ( head(\$seq), hof:take-while(tail(\$seq), \$pred) ) }; ``` Examples Computes at most 100 random integers, but stops if an integer is smaller than 10: ```hof:take-while( (1 to 100) ! random:integer(50), function(\$x) { \$x >= 10 } ) ```

## hof:drop-while

Introduced with Version 9.5.

 Signatures `hof:drop-while(\$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:drop-while(\$seq, \$pred) { if(\$pred(head(\$seq))) then ( hof:drop-while(tail(\$seq), \$pred) ) else ( \$seq ) }; ``` Examples Returns the name of the first file that does not exist on disk: ```hof:drop-while( (1 to 1000) ! (. || '.log'), file:exists#1 ) ```

# Sorting

## hof:top-k-by

 Signatures `hof:top-k-by(\$seq as item()*, \$sort-key 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 \$sort-key(\$x) descending return \$x )[position() <= \$k] ``` Examples `hof:top-k-by(1 to 1000, hof:id#1, 5)` returns `1000 999 998 997 996` `hof:top-k-by(1 to 1000, function(\$x) { -\$x }, 3)` returns `1 2 3` `hof:top-k-by(/@*, xs:integer#1, 2)/node-name()` returns `c b`

## hof:top-k-with

 Signatures `hof:top-k-with(\$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 less-than predicate `\$lt`. The function is a general version of `hof:top-k-by(\$seq, \$sort-key, \$k)`. Examples `hof:top-k-with(1 to 1000, function(\$a, \$b) { \$a lt \$b }, 5)` returns `1000 999 998 997 996` `hof:top-k-with(-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 higher-order functions. Examples `hof:id(1 to 5)` returns `1 2 3 4 5` With higher-order functions: ```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)) ) ``` 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 higher-order 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 higher-order functions: ```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) ) ``` Another use-case: 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 \$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') ) ``` returns `3 42`

Version 9.5
Version 8.1
Version 7.2
Version 7.0
• module added