List 如何使这些简单函数在f中进行尾部递归#
我有这两个功能List 如何使这些简单函数在f中进行尾部递归#,list,recursion,f#,tail-recursion,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
//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#新手:)
当然,欢迎对我的代码提出任何其他建设性意见 使函数在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
因为我们只是在每次递归调用循环
后返回结果,所以这些函数是尾部递归的
您的函数看起来很不错,但我仍有几点意见:
- 缩进在F#中很重要。我更喜欢
是匹配。。。with
声明后面的几个空格lec rec
- 模式匹配案例应遵循一致的顺序。首先从基本案例开始是个好主意
- 每当你有一个
的模式时,funt t->match t with
关键字自然会用于缩短函数function
- 最好去掉不必要的括号,尤其是在只有一个参数的函数中
// 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
如果您需要一种更慢、更不易维护、占用更多内存的方法,可以使用延续
let removeEven items =
let rec loop f = function
| _::h::t -> loop (fun acc -> f (h::acc)) t
| [] | [_] -> f []
loop id items
但是,嘿,它是尾部递归的。真不错!thx很多这正是我想要的。不完全确定我是否理解“loop l[]|>List.rev”行的功能。我的意思是,我知道它应该反转列表,但为什么循环l[]?什么时候才能到达rec代码?
[]->[].[].[].[].[].[].[/code>也可以折叠成[].[].[].[].[/code>,保存两行。@ildjarn:您的建议已被应用:)。@PNS:该行与List.rev(循环l[])相同。
。我们从一个空的列表开始积累。当输入列表少于2个元素时,我们返回累加器列表并将其反转。我认为这是正确的。它应该删除偶数索引元素,而不是偶数值元素,在这种情况下,1具有索引0,2具有索引1为什么removeEven[1;2]
返回[2]
?我在回答中复制了它的行为,但它似乎应该被称为returnEven
或removeOdd
或其他什么。很抱歉删除我的评论。我重新措辞了。那么,偶数指的是指数?好的。@Daniel:代码顶部的注释一直这么说。.-]@伊尔贾恩:谁读代码注释?!?:-)我认为结果应该是肯定的reversed@TysonWilliams不,先生。没有。哦,是的。你的回答是正确的。对不起,我弄错了。(我知道我应该在发表评论之前测试它:P)