如何使这些简单函数在f#中递归递归

时间:2012-02-21 17:27:25

标签: list recursion f# tail-recursion

我有这两个功能

//Remove all even indexed elements from a list and return the rest
let rec removeEven l =
match l with
| x0::x1::xs -> x1::removeEven (xs)
| [] -> []
| [_] -> []

//combine list members into pairs
let rec combinePair l =
match l with
| x0::x1::xs -> (x0,x1) :: combinePair(xs)
| [] -> []
| [_] -> []

那项工作。

但我现在想到的是,我不得不了解一下尾部递归,我很难掌握它。

这就是为什么我认为如果我能得到一些帮助来制作函数我自己的尾递归也许会更清楚它是如何工作的,而不是在某个地方读一些我可能不理解的例子以及我自己的代码(记住,我是一个完整的f#新手:))

关于我的代码的任何其他建设性意见当然是最受欢迎的!

2 个答案:

答案 0 :(得分:3)

在F#中使函数尾递归的典型方法是使用列表(在这种情况下为acc)来累积结果并将其反转以获得正确的顺序:

let removeEven l =
    let rec loop xs acc =
        match xs with        
        | [] | [_] -> acc
        | _::x1::xs' -> loop xs' (x1::acc)
    loop l [] |> List.rev

let combinePair l =
    let rec loop xs acc =
        match xs with        
        | [] | [_] -> acc
        | x0::x1::xs' -> loop xs' ((x0, x1)::acc)
    loop l [] |> List.rev

由于我们只是在每次递归调用loop后返回结果,因此这些函数是尾递归的。

你的功能看起来很不错,但我仍然有几条评论:

  • 缩进在F#中很重要。我希望match... withlec rec声明后面的几个空格。
  • 模式匹配案例应遵循一致的顺序。首先从基础案例开始是一个好主意。
  • 只要您的模式为functionfun t -> match t with关键字就可以自然地用于缩短功能。
  • 最好摆脱不必要的括号,特别是在带有一个参数的函数中。

应用上述评论,您的功能如下:

// Remove all even indexed elements from a list and return the rest
let rec removeEven = function
    | [] | [_] -> []
    | _::x1::xs -> x1::removeEven xs

// Combine list members into pairs
let rec combinePair = function
    | [] | [_] -> []
    | x0::x1::xs -> (x0, x1)::combinePair xs

答案 1 :(得分:2)

如果你需要一种使用更多内存的速度较慢,维护较少的方法,你可以使用延续。

let removeEven items = 
  let rec loop f = function
    | _::h::t -> loop (fun acc -> f (h::acc)) t
    | [] | [_] -> f []
  loop id items

但是,嘿,这是尾递归。