Custom Functions

An inline function, function($v as xs:double) as xs:double { $v * 2 } (types optional), is bound with let and called like a variable. Inline functions are closures that capture variables in scope, accept partial application with ?, and chain with the arrow operator. Each expression below evaluates to 6:

Inline functions, closures, partial application and recursion
xp 'let $f := (2, 3, 4) ! (let $a := . return function($n) { $a * $n }) return $f[2](2)' \
   'let $plus := function($x, $y) { $x + $y } return $plus(2, ?)(4)' \
   'let $s := function($n, $f) {if ($n) then $n + $f($n - 1, $f) else 0} return $s(3, $s)'
Output
let $f := (2, 3, 4) ! (let $a := . return function($n) { $a * $n }) return $f[2](2) => 6
let $plus := function($x, $y) { $x + $y } return $plus(2, ?)(4) => 6
let $s := function($n, $f) {if ($n) then $n + $f($n - 1, $f) else 0} return $s(3, $s) => 6

An inline function cannot see its own let variable, so recursion passes the function to itself. Type that parameter as function(*); the bare function() some references print is a syntax error (XPST0003). Named libraries belong in XQuery's declare function (XQuery 3.1 FLWOR Expressions) or XSLT's xsl:function.


Custom Functions

Custom functions are represented as function items (of type function(*)), a capability introduced in XPath 3.0 and extended in XPath 3.1 (e.g. the arrow operator => used in example 10 below). Each of the following expressions demonstrates a different function-related technique, but every one evaluates to the same result, 6:
let $f := function ($v) {$v * 2} return $f(3)a simple function
let
  $process := function($v as xs:double, $f as function(xs:double) as xs:double) as xs:double {$f($v)},
  $mult2 := function ($n as xs:double) as xs:double {$n*2}
return $process(3,$mult2)
passing a function to a function
let
  $compose := function($f as function(xs:double) as xs:double, $g as function(xs:double) as xs:double) as function(xs:double) as xs:double {function ($x as xs:double) {$g($f($x))}},
  $mult2 := function($x as xs:double) {$x*2},
  $mult3 := function($x as xs:double) {$x*3}
return $compose($mult2,$mult3)(1)
functions composition
let $plus := function($x as xs:integer, $y as xs:integer) as xs:integer {$x+$y}
return $plus(?,?)(2,4)
partial function application
let $plus := function ($m as xs:integer) as (function(xs:integer) as xs:integer) {function ($n as xs:integer) {$m + $n}}
return $plus(2)(4)
function closure
let
  $s := function ($n as xs:integer, $f as function(xs:integer, function()) as xs:integer) as xs:integer {if ($n<1) then 0 else $n+$f($n - 1,$f)},
  $sum := function($n as xs:integer) {$s($n,$s)}
return $sum(3)
recursive function (not supported by all processors)
function($a as xs:double, $b as xs:double) as xs:double { $a * $b }(2,3)inline function expression
let $f := (function($n){$n*2},function($n){$n*3}) return $f[2](2)dynamic function call without reference by name
let $f := (2,3,4) ! (let $a := . return function($n) { $a * $n}) return $f[2](2)collection of functions mapped from a collection (the bang operator ! can be used with nodes and built-in functions too)
let $p2 := function ($n){$n + 2}, $mult := function ($n,$f){$n*$f} return 1 => $p2() => $mult(2)chaining of arrow functions (usable with built-in functions too)
ch03-custom-functions.xpath.txt
merged-01-01-ch03-custom-functions.xpath.txt
let $f := function ($v) {$v * 2}
return $f(3)
Output
6