F # Использование рекурсивных списков

#f#

#f#

Вопрос:

Мой код (ниже) завершается с исключением переполнения стека. Я предполагаю, что F # не похож на haskell и dosent, которые хорошо работают с рекурсивными списками. Каков правильный способ работы с подобными рекурсивными списками в F #? Должен ли я передать ему значение int, чтобы оно имело определенный размер?

 let rec collatz num =
    match num with 
        |x when x % 2 = 0 ->num :: collatz (x/2)                                            
        |x ->               num :: collatz ((x * 3)   1)

let smallList = collatz(4) |> Seq.take(4)
  

Комментарии:

1. В дополнение к ответу Дэниела — проблема не в том, что список рекурсивен — это прекрасно в F #. Проблема в том, что список бесконечен , а списки F # по умолчанию не являются ленивыми.

Ответ №1:

Для такого бесконечного списка, как этот, вы хотите вернуть последовательность. Последовательности являются ленивыми; списки — нет.

 let rec collatz num = 
  seq {
    yield num
    match num with 
    | x when x % 2 = 0 -> yield! collatz (x/2)                                            
    | x -> yield! collatz ((x * 3)   1)
  }

let smallList = 
  collatz 4
  |> Seq.take 4
  |> Seq.toList //[4; 2; 1; 4]
  

Ответ №2:

 let collatz num =
  let next x = if x % 2 = 0 then x / 2 else x * 3   1
  (num, next num)
  |>Seq.unfold  (fun (n, x) -> Some (n, (x, next x)))