我正在尝试在XSLT 2.0中编写一个尾递归函数,它遍历日期的多值变量并返回最早的一个。出于某种原因,我的函数未被SaxonHE9.4识别为尾递归,当输入文件有超过150-200个条目左右时,我会收到以下错误:
tail\u rec\u测试第73行出错。xsl:嵌套函数调用太多。可能是由于无限递归。内置模板规则
以下是我的xml输入:
<?xml version="1.0"?>
<Events>
<Event>
<Date>2004-01-01</Date>
</Event>
<Event>
<Date>2003-01-01</Date>
</Event>
<Event>
<Date>2002-01-01</Date>
</Event>
<Event>
<Date>2001-01-01</Date>
</Event>
<Event>
<Date>2005-01-01</Date>
</Event>
<Event>
<Date>2006-01-01</Date>
</Event>
<Event>
<Date>2007-01-01</Date>
</Event>
<Event>
<Date>2008-01-01</Date>
</Event>
</Events>
这就是我的xsl-file的样子:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:own="http://ownfunctions">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:function name="own:findEarliestDate">
<xsl:param name="dates" as="xs:date*"/>
<xsl:variable name="size"><xsl:value-of select="count($dates)" /></xsl:variable>
<xsl:choose>
<xsl:when test="$size > 0">
<xsl:value-of select="own:findEarliestDate-helper($dates, $size, xs:date('2050-01-01'))" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="''"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:function name="own:findEarliestDate-helper" as="xs:date">
<xsl:param name="items" as="xs:date*"/>
<xsl:param name="i" as="xs:integer"/>
<xsl:param name="curMin" as="xs:date"/>
<xsl:choose>
<xsl:when
test="$i = 0">
<xsl:value-of select="xs:date($curMin)"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="item" as="xs:date">
<xsl:value-of select="xs:date($items[$i])"/>
</xsl:variable>
<xsl:variable name="next" as="xs:date">
<xsl:choose>
<xsl:when test="$item < $curMin">
<xsl:value-of select="$item"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$curMin"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="own:findEarliestDate-helper($items, $i - 1, $next)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
<xsl:template match="Events">
<xsl:variable name="items" as="xs:date*">
<xsl:for-each select="Event">
<xsl:value-of select="xs:date(Date)"/>
</xsl:for-each>
</xsl:variable>
<Test>
<EarliestDate>
<xsl:value-of select="own:findEarliestDate($items)"/>
</EarliestDate>
</Test>
</xsl:template>
</xsl:stylesheet>
如何将其转换为正确的尾部递归函数?我已经测试了此示例,但无法将其应用于我自己的代码:http://www.nesterovsky-bros.com/weblog/2008/02/20/EfficientXslt20RecursionInSaxon9.aspx
我不能再重复这个了。
使用Saxon 9.4.06EE(评估副本),结果是:
<Test xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:own="http://ownfunctions">
<EarliestDate>2001-01-01</EarliestDate>
</Test>
Saxon-EE 9.4.0.6J from Saxonica
Java version 1.6.0_31
Using license serial number XXXXXXXX
Generating byte code...
Stylesheet compilation time: 2168 milliseconds
Processing file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Building tree for file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml using class net.sf.saxon.tree.tiny.TinyBuilder
Tree built in 10 milliseconds
Tree size: 27 nodes, 80 characters, 0 attributes
Execution time: 122ms
Memory used: 52169472
NamePool contents: 8 entries in 8 chains. 6 URIs
顺便说一句,你可以用这个来产生同样的结果:
<xsl:value-of select="min(/*/*/Date/xs:date(.))"/>
更新:
问题出在这一行:
<xsl:value-of select="own:findEarliestDate-helper($items, $i - 1, $next)"/>
因为函数的返回类型是xs:date,所以上面的一行不是函数执行序列中的最后一行。它生成一个字符串(更准确地说,是一个文本节点),XSLT处理器需要获取该字符串并将其转换为日期,这意味着函数占用的内存不会被丢弃,调用堆栈会继续增长,直到溢出。
解决方案很简单:
将上述内容替换为:
<xsl:sequence select="own:findEarliestDate-helper($items, $i - 1, $next)"/>
这会生成一个xs: date
,XSLT处理器现在将该函数识别为尾部递归。
我用1000个事件(原始代码崩溃)测试了更正后的代码,结果正常(并且更快)生成。
Saxon-EE 9.4.0.6J from Saxonica
Java version 1.6.0_31
Using license serial number XXXXXXXXXX
Generating byte code...
Stylesheet compilation time: 2002 milliseconds
Processing file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml
Using parser com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser
Building tree for file:/C:/Program%20Files/Java/jre6/bin/marrowtr.xml using class net.sf.saxon.tree.tiny.TinyBuilder
Tree built in 124 milliseconds
Tree size: 3032 nodes, 9800 characters, 0 attributes
Execution time: 364ms
Memory used: 55089048
NamePool contents: 8 entries in 8 chains. 6 URIs
我有一个家庭作业问题,它给出了一个递归函数,我必须使用尾部递归来实现它。函数为f(0)=1 f(n)=1 2*f(n-1) 我并不擅长尾部递归,我试着查找示例,但我发现的都是没有斐波那契序列的示例,这没有多大帮助。 我真正拥有的是 我知道尾递归基本上每次调用都计算函数,我只是不知道如何实现它。 编辑:我打了一个错字f(n)应该是1 2*f(n-1)
各种各样的书籍、文章、博客帖子表明,将递归函数重写为尾部递归函数可以加快速度。毫无疑问,对于生成斐波那契数或计算阶乘等琐碎情况,它会更快。在这种情况下,有一种典型的重写方法,即使用“辅助函数”和用于中间结果的附加参数。 尾部递归很好地描述了尾部递归函数和非尾部递归函数之间的差异,以及如何将递归函数转换为尾部递归函数。对于这种重写来说什么是重要的-函数调用的数量是相同的(重写之前/之后),不同之处在
假设我编写这样的代码: 我如何让Kotlin优化这些相互递归的函数,以便在不抛出StackOverflower错误的情况下运行main?tailrec关键字适用于单函数递归,但没有更复杂的功能。我还看到一个警告,在使用关键字tailrec的地方没有找到尾部调用。也许这对编译器来说太难了?
我正在从事一个基于C中自定义数据结构list\t的项目。这是可以帮助我操作这个list\t的预定义函数,我被要求编写的函数叫做insert\u list(list\u t,list\u t,int),它是尾部递归的。 我要编写的insert_list()函数接受两个输入,类型为list_t和一个保证不大于第一个list_t大小的额外整数n,并返回另一个list_t,其中包含第一个list_t中的前
我对函数式编程很陌生,尤其是下面使用的Scheme。我正在尝试使以下函数是递归的,尾递归的。基本上,该函数的作用是对两个字符串的对齐方式进行评分。当给定两个字符串作为输入时,它会比较每个“列”字符,并根据在称为 scorer 的函数中实现的评分方案(由下面的代码中的函数调用)来累积该对齐的分数。 我有一个想法,用一个帮助函数来累积分数,但我不太确定如何去做,因此我该如何让下面的函数尾递归呢?
本文向大家介绍C#函数式编程中的递归调用之尾递归详解,包括了C#函数式编程中的递归调用之尾递归详解的使用技巧和注意事项,需要的朋友参考一下 关于递归相信大家已经熟悉的不能再熟悉了,所以笔者在这里就不多费口舌,不懂的读者们可以在博客园中找到很多与之相关的博客。下面我们直接切入正题,开始介绍尾递归。 尾递归 普通递归和尾递归如果仅仅只是从代码的角度出发来看,我们可能发现不了他的特点,所以笔者利用两张堆