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;}; ...]

更新:そしてダニエルが示したように、汎用言語プリミティブを使用しinfiniteRangeて、スキップ 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

これはスティーブンのもののような一般的な範囲関数ですが、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
于 2011-06-09T14:09:22.520 に答える