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]
(Если, конечно, вы не имеете дело с огромным количеством людей)