Question

I wonder why F-Sharp doesn't support infinity.

This would work in Ruby (but not in f#):

let numbers n = [1 .. 1/0] |> Seq.take(n)

-> System.DivideByZeroException: Attempted to divide by zero.

I can write the same functionality in much complex way:

let numbers n = 1 |> Seq.unfold (fun i -> Some (i, i + 1)) |> Seq.take(n)

-> works

However I think that first one would be much more clear. I can't find any easy way to use dynamically typed infinity in F#. There is infinity keyword but it is float:

let a = Math.bigint +infinity;;

System.OverflowException: BigInteger cannot represent infinity. at System.Numerics.BigInteger..ctor(Double value) at .$FSI_0045.main@() stopped due to error


Edit: also this seems to work in iteration:

let numbers n = Seq.initInfinite (fun i -> i+1) |> Seq.take(n)
Was it helpful?

Solution

First of all, F# lists are not lazy, (I'm not sure Ruby lists are lazy), so even with a general notion of infinity your first example can never work.

Second, there is no infinity value in Int32. Only MaxValue. There is a positive and negative infinity in Double though.

Putting it together, this works:

let numbers n = seq { 1. .. 1./0. } |> Seq.take(n)

I feel however Seq.initInfinite is your best option. The code above looks strange to me. (Or at least use Double.PositiveInfinity instead of 1./0.)

At first sight, a nice option to have in the language would be an infinite range operator like in haskell: seq { 1.. } The problem is that it would only work for seq, so I guess the extra work to support postfix operators is not worth it for this feature alone.

Bottom line: in my opinion, use Seq.initInfinite.

OTHER TIPS

I think the following is the best solution to infinite ranges in F#; by marking the function inline we do better than "dynamically typed infinity" we get structurally typed infinite ranges (works with int32, int64, bigint, ... any type that which has a static member + which takes two arguments of its own type and returns a value of it's own type):

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

//val inline infiniteRange :
//   ^a ->  ^b -> seq< ^a>
//    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^a)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top