XPath/XQuery for-each-pair function

Summary

Applies the function item $action to successive pairs of items taken one from $seq1 and one from $seq2, returning the concatenation of the resulting sequences in order.

Signature

fn:for-each-pair(
$seq1 as item()*,
$seq2 as item()*,
$action as function(item(), item()) as item()*
) as item()*

Properties

This function is deterministic, context-independent, focus-independent, and higher-order.

Rules

The effect of the function is equivalent to the following implementation in XQuery:

declare function fn:for-each-pair($seq1, $seq2, $action)
{
   if(fn:exists($seq1) and fn:exists($seq2)) 
   then (
     $action(fn:head($seq1), fn:head($seq2)),
     fn:for-each-pair(fn:tail($seq1), fn:tail($seq2), $action)
   )
   else ()
};

or its equivalent in XSLT:

<xsl:function name="fn:for-each-pair">
  <xsl:param name="seq1"/>
  <xsl:param name="seq2"/>
  <xsl:param name="action"/>
  <xsl:if test="fn:exists($seq1) and fn:exists($seq2)">
    <xsl:sequence select="$action(fn:head($seq1), fn:head($seq2))"/>
    <xsl:sequence select="fn:for-each-pair(fn:tail($seq1), fn:tail($seq2), $action)"/>
  </xsl:if>
</xsl:function>

Examples

The expression fn:for-each-pair(("a", "b", "c"), ("x", "y", "z"), concat#2) returns ("ax", "by", "cz").

The expression fn:for-each-pair(1 to 5, 1 to 5, function($a, $b){10*$a + $b}) returns (11, 22, 33, 44, 55).

The expression let $s := 1 to 8 return fn:for-each-pair($s, tail($s), function($a, $b){$a*$b}) returns (2, 6, 12, 20, 30, 42, 56).

Notes

If one sequence is longer than the other, excess items in the longer sequence are ignored.