I want to create an unbounded sequence and wondered if i could do it via a tail recursive function.
a simple example being
<xsl:function name="kooks:repeat" as="xs:integer*">
<xsl:sequence select="1"/>
<xsl:sequence select="kooks:repeat()"/>
</xsl:function>
<xsl:template match="/">
<xsl:sequence select="kooks:repeat()[5]"/>
</xsl:template>
(I'm using Saxon-ee 11.4)
This fails with
Severity: error
Description: class java.lang.StackOverflowError
I think the issue is because there are 2 sequence statements then saxon interprets this as a append/cons operation and thus the function is no longer tail recursive (in its model).
If we compare this to the F# code (which is what I'm trying to translate into XSLT)
let rec ones () =
seq {
yield 1
yield! ones ()
}
let tenMillionthEntry =
ones ()
|> Seq.skip 10000000
|> Seq.take 1
|> Seq.head
this doesn't consider the consecutive yield, yield! as an operation in the function and so its tail recursion optimisation works (presumably as this code doesnt blow up).
Christian Grün on the XML slack came up with something along the following lines:
let $inf-rec := function($start, $self) {
map {
'skip': function($c) { $self($start + $c, $self) },
'take': function($c) { $start to $start + $c - 1 }
}
},
$inf := function() {
$inf-rec(1, $inf-rec)
}
return $inf()?skip(10000000)?take(1) ! head(.)
He also said in XPath 4.0 there are functions https://qt4cg.org/specifications/xpath-functions-40/Overview.html#func-do-until and https://qt4cg.org/specifications/xpath-functions-40/Overview.html#func-while-do that could help.
Also wait whether Dimitre Novatchev shows up to explain his ideas for infinite sequences in XPath 4.