【问题标题】:F# Continuation-based tail recursion on listF# 列表上基于延续的尾递归
【发布时间】:2017-12-15 08:00:09
【问题描述】:

我有一个非常简单的函数,它接受一个 int 并将其添加到列表的头部,然后递归调用 i 乘以自身:

let rec f i = function
    | []    -> []
    | x::xs -> (x+i)::f (i*i) xs

f 2 [1;2;3]
val it : int list = [3; 6; 19]

现在,我正在尝试使用延续来重写它,但我有点卡住了。到目前为止,这是我想出的:

let fC i l =
    let rec loop cont = function
        | []    -> []
        | x::xs -> cont(x+i)::loop (fun acc -> (acc*acc)) xs
    loop id l

fC 2 [1;2;3] //Expected [3;6;19]
val it : int list = [3; 16; 25]

任何提示我做错了什么?

【问题讨论】:

  • 它不是尾递归,但可能会帮助你到达那里:let fC i l = let rec loop cont = function | [] -> [] | x::xs -> x+cont(i)::loop (fun acc -> cont(acc*acc)) xs loop id l
  • 如果您仔细阅读上面链接中的 Q 答案以及之前 Q 的答案,您将很容易将您的函数转换为新版本
  • @FoggyFinder 它不是重复的,该问题询问的是尾递归,它与 CPS 不完全相同。
  • @Gustavo 知道了,我删除了我的投票

标签: recursion f#


【解决方案1】:

看着这个问题和 cmets,我觉得有些混乱。

尾递归并不一定意味着延续传递风格 (CPS)。

这是 CPS 中的函数:

let f' i p =
    let rec loop i p k =
        match p with
        | []    -> k []
        | x::xs -> loop (i*i) xs (fun a -> k ((x+i)::a))
    loop i p id

当然,它是尾递归的。但是你也可以通过使用累加器而不是延续来编写尾递归:

let f'' i p =
    let rec loop i p acc = 
        match p with
        | []    -> acc
        | x::xs -> loop (i*i) xs ((x+i)::acc)
    loop i p [] |> List.rev

另请参阅answer to this question 以了解更好的 CPS。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-10
    • 1970-01-01
    • 2017-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多