Seq.unfold объяснение в F#

Я пытаюсь создать последовательность лениво с помощью F#.

Последовательность определяется следующим образом:

N-й член последовательности треугольных чисел задается как tn = ½n(n+1); Итак, первые десять треугольных чисел:

1, 3, 6, 10, 15, 21, 28, 36, 45, 55,...

Вот то, что я имею до сих пор, но это, кажется, не работает:

let tri_seq = 1.0 |> Seq.unfold (fun x -> match x with                                         
                                          | _ -> Some (x, 0.5*x*(x + 1.0)))

Большое спасибо, кто может помочь мне понять, как работает разворачивание. Спасибо

Изменить: я отметил первый ответ как правильный, но он не работает, однако я немного изменил его, и он работал.

let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0),x + 1.0))

4 ответа

Решение

Во-первых, почему вы используете match если у вас есть только один случай?

let tri_seq = 1.0 |> Seq.unfold (fun x -> Some (x, 0.5 * x * (x + 1.0)))

Во-вторых, что "не похоже на работу"? Знаете ли вы, что вы производите бесконечный список?

/ Edit: для полноты, вот правильное решение, которое ОП нашел сам и опубликовал в качестве комментария:

let tri_seq = 
    1.0 |> Seq.unfold (fun x -> Some (0.5 * x * (x + 1.0), x + 1.0))

Другая альтернатива коду, который опубликовал Брайан, - это использовать рекурсию вместо обязательного цикла while:

let tri = 
  let rec loop(n, diff) = seq { 
    yield n        
    yield! loop(n + diff, diff + 1.0) }
  loop(1.0, 2.0)
printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)

Это гораздо менее эффективно (поэтому вы должны быть здесь немного осторожнее...), но это более идиоматическое функциональное решение, поэтому может быть легче увидеть, что делает код.

Вот альтернатива:

let tri = seq {
    let n = ref 1.0
    let diff = ref 2.0
    while true do
        yield !n
        n := !n + !diff
        diff := !diff + 1.0
    }

printfn "%A" (tri |> Seq.take 10 |> Seq.to_list)

Я знаю, что это довольно старое, но я не могу понять, почему использовать float, когда вы уверены, что x * (x + 1) является четным числом и действительно делится на 2. Так что я бы просто использовал это вместо (не много разницу я знаю но по крайней мере у вас есть int seq):

let tri_seq = 1 |> Seq.unfold (fun x -> Some (x * (x + 1) / 2 , x + 1)) 

tri_seq |> Seq.take 6 |> Seq.toList //[1; 3; 6; 10; 15; 21]

играть на скрипке

(Если, конечно, вы не имеете дело с огромным количеством людей)

Другие вопросы по тегам