F # - как писать вложенные циклы рекурсивным способом? - PullRequest
2 голосов
/ 26 августа 2009

Учитывая следующий код 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 #, написанный в функциональном стиле?

Ответы [ 2 ]

17 голосов
/ 26 августа 2009

Я бы просто написал это так для циклов for. Даже программист на Haskell, вероятно, выразит это с пониманием списка, и в этом случае вы можете написать, например,

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

в F #.

7 голосов
/ 27 августа 2009

решение, которое предлагает Брайан, определенно является лучшим вариантом (в 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)

Я использую :: во вложенной функции для добавления элементов в начало и @ для объединения списков, генерируемых отдельными вызовами вложенных функций. Использование @ не очень эффективно, и код также не является рекурсивным, поэтому лучшая версия с использованием параметра аккумулятора будет выглядеть так:

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

Надеюсь, это поможет!

...