【发布时间】:2011-06-30 06:46:13
【问题描述】:
大家好,我正在尝试熟悉函数式编程(尤其是 F#),但在构建尾递归函数时遇到了困难。我很擅长将基本递归(函数基本上每次调用一次调用自身)转换为尾递归,但我现在的情况稍微复杂一些。
在我的例子中,函数必须接受一个列表作为参数。调用该函数时,我必须从列表中删除第一个元素,然后使用列表的其余部分进行递归。然后我需要将我以某种方式删除的第一个元素应用于递归的结果。接下来,我删除第二个元素并做同样的事情(注意:当我说“删除第二个元素”时,即从原始列表中,因此递归传递的列表也包括第一个元素)。我对列表的第三个、第四个等元素执行相同的操作。
有没有办法将上述情况转换为尾递归函数?也许嵌套的尾递归函数???感谢您的任何回答。
好的,这是我的基本代码。这个特殊的是一个排列生成器(不过,我不太关心排列部分 - 这是我想要关注的递归):
let permutationsOther str =
match str with
| value :: [] ->
[[value]]
| _ ->
let list = (List.map (fun a -> // This applies the remove part for every element a
let lst = (List.filter (fun b -> b <> a) str) // This part removes element a from the list
let permutedLst = permutations lst // recursive call
consToAll a permutedLst // constToAll this is my own function which performs "cons" operation with a and every element in the list permutedLst
) str)
List.reduce (fun acc elem -> elem @ acc) list // flatten list of lists produce by map into a single list
我希望这已经足够清楚 - 如果需要,我很乐意提供澄清。
顺便说一句,我找到了一种方法来重写这个特定的函数,使它只使用一个递归,但这只是一个侥幸,而不是一个明智的决定。但是,这让我很受鼓舞,可能有一个通用的方法可以将多次递归变成单次递归,但我还没有找到。
【问题讨论】:
-
根据您的描述,您的函数进行了多次递归调用,这(IIRC)意味着您无法将代码转换为尾递归。您需要提出不同的递归公式才能在此处使用尾递归。
-
噢——这就是我所害怕的。也许我会找到一种方法来“重新解释”我需要的东西——也许递归然后循环遍历列表——谁知道呢?感谢您的回复。
-
那是完全错误的。您可以肯定地将其变成尾递归的东西。您只需要对功能的结构方式进行创意。从表面上看,您可以使用扫描而不是递归来做同样的事情。肯,你为什么不发布你当前的实现(或类似的东西)让我们玩一玩?
-
我不太确定我知道你的函数应该做什么。你可以展示非尾递归版本作为示例吗?
-
Desco,他自己在问如何使用尾递归,那么他如何提供示例?
标签: f# functional-programming tail-recursion