我有一个函数,它接受一个int和一个int列表。它返回一个小于第一个参数的int列表。
我想在不使用List.Filter
的情况下复制相同的代码:
let less e L =
L |> List.filter(fun a -> a < e)
less 3 [1;2;4;5]
我想学习递归思考,好像我是用SML编写的那样
我怎么递归写这个?
答案 0 :(得分:5)
基本上逻辑是这样的。对于基本情况,如果列表为空,那么您就完成了。只需返回空列表。对于包含头部项目(x
)和尾部(xs
)的列表,如果x < e
返回x
,则会将less
的结果附加到less
尾巴。否则,只需返回应用于尾部的let rec less e L =
match L with
| [] -> []
| x :: xs -> if x < e then x :: (less e xs) else (less e xs)
。
let lessTailRec e L =
let rec loop e L acc =
match L with
| [] -> acc
| x :: xs -> if x < e then loop e xs (x :: acc) else loop e xs acc
loop e L [] |> List.rev
然而,这有点效率低,因为它不是尾递归。尾递归调用是指立即返回递归调用的结果。这些更有效,因为编译器可以将它们基本上转换为不会为每次递归消耗额外堆栈空间的循环。为此,我们需要一个带累加器的辅助函数:
{{1}}
答案 1 :(得分:0)
我不确定这是否会编译,因为我刚刚在SO中编写了它。此外,它肯定不是最佳方式,但它可以让你进入递归轨道(mike z显示更好的方式)。
let rec less e L =
match L with
| [] -> []
| (head::tail) -> if head < e then (head :: less e tail) else (less e tail)
基本上,它包含几个步骤。
首先是将头部从列表中拉出来(如果它是一个空列表,则返回一个空列表)
其次是将头部与e进行比较
第三是将列表的尾部发送到递归行
第四是重建列表,可选择包括列表的头部。
List.Filter函数只是一个通用函数,它允许您注入一个函数来替换第二步并保存所有样板文件。通常你想在所有情况下使用List.Filter,除非在学习它的作用时。