【问题标题】:Thinking recursively with F#使用 F# 递归思考
【发布时间】:2013-10-01 12:57:07
【问题描述】:

我有一个函数,它接受一个 int 和一个 int 列表。它返回一个小于第一个参数的整数列表。

我想在不使用 List.Filter 的情况下复制相同的代码:

let less e L = 
   L |> List.filter(fun a -> a < e)

less 3 [1;2;4;5]

我想学习递归思考,就好像我在用 SML 写这篇文章一样

我将如何递归地编写这个?

【问题讨论】:

    标签: recursion f#


    【解决方案1】:

    基本上逻辑是这样的。对于基本情况,如果列表为空,那么您就完成了。只需返回空列表。对于头部有项目 (x) 和尾部 (xs) 的列表,如果 x &lt; e 返回 xless 的结果附加到尾部。否则,只返回应用于尾部的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
    

    【讨论】:

    【解决方案2】:

    我不确定这是否可以编译,因为我只是在 SO 中编写了它。此外,这当然不是最好的方法,但它可以让你走上递归轨道(mike z's 展示了一种更好的方法)。

    let rec less e L =
        match L with
        | [] -> []
        | (head::tail) -> if head < e then (head :: less e tail) else (less e tail)
    

    基本上,它由几个步骤组成。

    首先将头部从列表中拉出(如果是空列表,则返回一个空列表)

    第二个是比较head和e

    第三个是将列表的尾部发送到递归行

    第四是重建列表,可选地包括列表的头部。

    List.Filter 函数只是一个通用函数,它允许您注入一个函数来替换第二步,并为您节省所有样板文件。通常您希望在所有情况下都使用 List.Filter,除非在学习它的作用时。

    【讨论】:

      猜你喜欢
      • 2013-07-10
      • 2022-10-09
      • 1970-01-01
      • 1970-01-01
      • 2018-09-19
      • 2017-04-26
      • 1970-01-01
      • 2017-12-13
      • 1970-01-01
      相关资源
      最近更新 更多