Инициализация бесконечного списка BigIntegers - PullRequest
5 голосов
/ 09 июня 2011

Хорошо, Поэтому мне нужен список всех натуральных чисел. Первое, что приходит на ум, это:

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 ]

12 голосов
/ 09 июня 2011
Seq.unfold (fun n -> Some(n, n + 1I)) 0I
5 голосов
/ 09 июня 2011
let numbers:bigint seq = 
    let rec loop n = seq { yield n; yield! loop (n+1I) }
    loop 0I
3 голосов
/ 09 июня 2011

Я сохраняю следующую статически ограниченную функцию, поскольку она очень гибкая (вы можете указать начальное значение и интервал пропуска) и работает со всеми числовыми типами:

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)
2 голосов
/ 09 июня 2011

Вы могли бы даже рассмотреть возможность расширения модуля 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
...