尾递归文件夹

时间:2019-07-09 16:48:11

标签: functional-programming f#

我想用f#编写一个尾递归文件夹,以利用尾递归优化并了解有关函数式编程的更多信息。

我写了一个尾递归折叠和一个不是尾递归的文件夹。我以为可以通过反转馈给该函数的列表,然后在其上调用我的尾部递归折叠来获得尾部递归折叠器,但是由于该功能应被应用到的顺序不同,所以这行不通。

let rec tail_recurse_foldl(list: List<'a>, func:('b -> 'a -> 'b), acc: 'b) =
    match list with 
    | [] -> acc
    | [x] -> func acc x
    | x :: xs -> tail_recurse_foldl(xs, func, func acc x)

和非尾递归文件夹

let rec foldr(list: List<'a>, func:('a -> 'b -> 'b), acc: 'b) =
    match list with
    | [] -> acc
    | [x] -> func x acc
    | x::xs -> func x (foldr(xs, func, acc))

1 个答案:

答案 0 :(得分:7)

有两种方法可以做到这一点。一种简单的方法是反转列表(这是尾递归操作),然后从左侧开始折叠。一种更复杂的方法是使用延续传递样式。

在基于延续的版本中,您添加了一个额外的参数 continuation ,该参数是在列表处理完成后应调用的函数(以便您可以将{{1} }在此延续内部调用,而不是将其放在堆栈上。

func

当我们得到一个空列表时,我们只用初始状态let rec foldr(list: List<'a>, func:('a -> 'b -> 'b), acc: 'b, cont:'b -> 'b) = match list with | [] -> cont acc | x::xs -> foldr(xs, func, acc, fun r -> cont (func x r)) 调用延续。当您有非空列表时,我们递归调用acc(尾巴),并为其赋予一个延续,该延续将对结果运行foldr,然后使用其自己的{{1} }。