【问题标题】:F# - how to write nested loops in a recursive way?F# - 如何以递归方式编写嵌套循环?
【发布时间】:2023-04-03 16:21:01
【问题描述】:

给定以下 C# 代码:

var product = new List<int>();
for (int n1 = 100; n1 < 1000; n1++)
{
    for (int n2 = 100; n2 < 1000; n2++)
    {
        product.Add(n1 * n2);
    }
 }

以函数式风格编写的等效 F# 代码是什么?

【问题讨论】:

  • 我不知道 F#,但我知道其他函数式语言,我可以提供一些建议:首先将内部(更嵌套的)循环转换为递归函数。那么将外循环转换为调用内循环函数的递归函数应该会更容易。

标签: f# functional-programming nested-loops


【解决方案1】:

我会用 for 循环这样写。即使是 Haskell 程序员也可能会用列表推导来表达这一点,在这种情况下,您可以编写例如

let productsList =
    [for x in 2..4 do
     for y in 2..4 do
     yield x*y]

在 F# 中。

【讨论】:

  • 您错过了语法糖,尽管我认为在这种情况下不合适。 (-> == do yield) let productsList = [ for x in 2 .. 4 do for y in 2..4 -> x*y ]
【解决方案2】:

Brian 建议的解决方案绝对是最佳选择(在 F# 中)。序列表达式为您提供了一种更简单的方式来表达您的意思,那么为什么不使用它们呢?

无论如何,如果您只是将其作为练习,那么您可以将嵌套循环重写为单个递归函数,将外部循环重写为第二个(正如 Imagist 建议的那样):

let product = 
  let rec outer(n1) = 
    let rec nested(n2) = 
      if n2 > 4 then [] else (n1 * n2)::(nested(n2 + 1))
    if n1 > 4 then [] else nested(2) @ outer(n1 + 1)
  outer(2)

我在嵌套函数中使用 :: 将元素附加到开头,并使用 @ 来连接由各个嵌套函数调用生成的列表。 @ 的使用效率不高,代码也不是尾递归的,所以使用 accumulator 参数的更好版本如下所示:

let product = 
  let rec outer n1 acc = 
    let rec nested n2 acc = 
      if n2 > 4 then acc else nested (n2 + 1) ((n1 * n2)::acc)
    if n1 > 4 then acc else outer (n1 + 1) (nested 2 acc)
  outer 2 [] |> List.rev

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 2021-08-11
    • 2023-04-01
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多