【发布时间】:2012-12-19 02:33:47
【问题描述】:
我正在学习尾递归,但在确定我的函数是否为尾递归时遇到了一些困难(主要是在我使用另一个函数的函数上)。
我已经实现了以下两个函数,但我不确定它们是否是尾递归的。
第一个是连接两个列表的函数。
conca list [] = list
conca [] result = result
conca (h:t) result = conca (init (h:t)) ( last(h:t):result )
concatenate::[a]->[a]->[a]
concatenate list1 list2 = conca list1 list2
函数中的计算是在递归调用之前处理的,但它使用 last 和 init,它们不是尾递归(我在 http://ww2.cs.mu.oz.au/172/Haskell/tourofprelude.html 中检查了它们的定义)
第二个功能是删除给定列表中给定数字的第一次出现。
invert [] result = result
invert (h:t) result = invert t (h:result)
remov n [] aux result = invert result []
remov n (h:t) aux result
| aux==1 = remov n t 1 (h:result)
| n==h = remov n t 1 (result)
| otherwise = remov n t 0 (h:result)
remove n list = remov n list 0 []
参数 aux(可以假定 0 或 1 作为值)用于标记是否已删除出现。
在 remove 函数中,当部分结果通过递归调用向下传递时,列表被倒置,最后列表没有第一次出现而是倒置,因此它必须被倒置才能作为返回结果。
【问题讨论】:
-
出于效率原因,您可能正在学习尾递归。你读过this question 了吗?它解释了为什么尾调用优化不是您所需要的。另外,关于效率的话题,大量使用
init和last是一场灾难! -
请阅读。在这种情况下,我不是在寻找效率,而是在实践中使用尾递归实现一些基本功能。那么,与其使用 init 和 last ,还有什么更好的选择呢?
-
init和last都遍历整个列表,O(n) 操作也是如此。head和tail是 O(1),使用起来要好得多,但您可以通过模式匹配获得它们。(++)的标准定义是(x:xs) ++ ys = x:(xs ++ ys),这是一个经典的高效非尾递归惰性函数,它立即产生结果的头部。
标签: haskell recursion tail-recursion