5

好的,所以我需要一个所有正整数的列表。首先想到的是:

let numbers:Seq<bigint>=Seq.initInfinite n...

但 initInfite 实际上并不是 infitint:http: //msdn.microsoft.com/en-us/library/ee370429.aspx (与 bigint 不同)它唯一的:Int32.MaxValue = 2,147,483,647 远远不够大。

目前我的计划是用某种手工类(可能是 IEnumerable)替换序列。它会很简单(并且可能对我的使用更有效)但我想知道如何做到这一点

4

4 回答 4

12
Seq.unfold (fun n -> Some(n, n + 1I)) 0I
于 2011-06-09T06:31:14.500 回答
6
let numbers:bigint seq = 
    let rec loop n = seq { yield n; yield! loop (n+1I) }
    loop 0I
于 2011-06-09T09:58:34.870 回答
3

我保留了以下静态约束函数,因为它非常灵活(您可以指定起始值和跳过间隔)并且适用于所有数字类型:

let inline infiniteRange start skip = 
    seq {
        let n = ref start
        while true do
            yield n.contents
            n.contents <- n.contents + skip
    }

FSI 给出的类型签名:

val inline infiniteRange :
   ^a ->  ^b -> seq< ^a>
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a)

以下是生成所有整数(BigInts,即——在 FSI 中显示)的方式:

> infiniteRange 1I 1I;;
val it : seq<System.Numerics.BigInteger> =
  seq [1 {IsEven = false;
          IsOne = true;
          IsPowerOfTwo = true;
          IsZero = false;
          Sign = 1;}; 2 {IsEven = true;
                         IsOne = false;
                         IsPowerOfTwo = true;
                         IsZero = false;
                         Sign = 1;}; 3 {IsEven = false;
                                        IsOne = false;
                                        IsPowerOfTwo = false;
                                        IsZero = false;
                                        Sign = 1;}; 4 {IsEven = true;
                                                       IsOne = false;
                                                       IsPowerOfTwo = true;
                                                       IsZero = false;
                                                       Sign = 1;}; ...]

更新:正如 Daniel 所展示的,您可以使用通用语言原语轻松地编写另一个静态约束函数,infiniteRange其中包含内置的 skip 1:

let inline infiniteRangeSkip1 start = 
    infiniteRange start LanguagePrimitives.GenericOne

这是类型签名:

val inline infiniteRangeSkip1 :
   ^a -> seq< ^a>
    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a) and
          ^b : (static member get_One : ->  ^b)
于 2011-06-09T14:50:53.920 回答
2

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

这是一个通用范围函数,如斯蒂芬的,但没有startand 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
于 2011-06-09T14:09:22.520 回答