Вы могли бы даже рассмотреть возможность расширения модуля Seq
, если это то, что вам часто нужно.
module Seq =
let initInfiniteBig =
seq {
let i = ref 0I
while true do
yield !i
i := !i + 1I
}
let ten = Seq.initInfiniteBig |> Seq.take 10
Обновление
Я протестировал несколько вариантов:
let initInfiniteBig =
seq {
let i = ref 0I
while true do
yield !i
i := !i + 1I
}
let initInfiniteBig2 =
seq {
let i = ref 0I
while true do
yield i.contents
i.contents <- i.contents + 1I
}
let initInfiniteBig3 =
let rec loop i =
seq {
yield i
yield! loop (i + 1I)
}
loop 0I
let initInfiniteBig4 = Seq.unfold (fun n -> Some(n, n + 1I)) 0I
let range s = s |> Seq.take 100000000 |> Seq.length |> ignore
range initInfiniteBig //Real: 00:00:29.913, CPU: 00:00:29.905, GC gen0: 0, gen1: 0, gen2: 0
range initInfiniteBig2 //Real: 00:00:30.045, CPU: 00:00:30.045, GC gen0: 0, gen1: 0, gen2: 0
range initInfiniteBig3 //Real: 00:00:40.345, CPU: 00:00:40.310, GC gen0: 2289, gen1: 5, gen2: 0
range initInfiniteBig4 //Real: 00:00:30.731, CPU: 00:00:30.716, GC gen0: 1146, gen1: 4, gen2: 1
Обновление 2
Вот общая функция диапазона, как у Стивена, но без start
и skip
.
let inline infiniteRange() : seq<'a> =
let zero : 'a = LanguagePrimitives.GenericZero
let one : 'a = LanguagePrimitives.GenericOne
seq {
let n = ref zero
while true do
yield !n
n := !n + one
}
Вот подпись:
unit -> seq< ^a>
when ^a : (static member get_Zero : -> ^a) and
^a : (static member get_One : -> ^a) and
^a : (static member ( + ) : ^a * ^a -> ^a)
И эталонный тест:
range (infiniteRange() : seq<bigint>) //Real: 00:00:30.042, CPU: 00:00:29.952, GC gen0: 0, gen1: 0, gen2: 0