1

I need a function that produces primes in F#. I found this:

let primesSeq = 
    let rec nextPrime n p primes =
        if primes |> Map.containsKey n then
            nextPrime (n + p) p primes
        else
            primes.Add(n, p)

    let rec prime n primes =
        seq {
            if primes |> Map.containsKey n then
                let p = primes.Item n
                yield! prime (n + 1) (nextPrime (n + p) p (primes.Remove n))
            else
                yield n
                yield! prime (n + 1) (primes.Add(n * n, n))
        }

    prime 2 Map.empty

This works very well, but sometimes I need to work with int64/BigInts as well. Is there a more clever way of reusing this code than providing another sequences like these:

let primesSeq64 = Seq.map int64 primesSeq
let primesBigInts = Seq.map (fun (x : int) -> BigInteger(x)) primesSeq

I've heard about modifying a code using "inline" and "LanguagePrimitives", but all I've found was connected with function while my problem is related to a value.

Moreover - I'd like to have a function that works with integer types and computes a floor of a square root.

let inline sqRoot arg = double >> Math.Sqrt >> ... ?

but I can't see a way of returning the same type as "arg" is, as Math.Sqrt returns a double. Again - is there anything better than reimplementing the logic that computes a square root by myself ?

LA.27
  • 1,888
  • 19
  • 35

2 Answers2

4

So the general way to do this requires a function and languageprimitives - in your case everywhere you have 1 you write LanguagePrimitives.GenericOne which will produce 1 or 1.0 etc depending on what is required.

To get this to work, you need to create a function value - you can avoid this by doing something like:

let inline primesSeq() = ...
let primesintSeq = primesSeq() //if you use this as an int seq later the compiler will figure it out, otherwise you use
let specified : int seq = primesSeq()

I am not so sure about the sqrt case though - it probably depends on how hacky you are willing to make the solution.

John Palmer
  • 25,356
  • 3
  • 48
  • 67
2

A naïve implementation of generic sqRoot may go along these lines:

let sqRoot arg =
    let inline sqrtd a = (double >> sqrt) a
    let result = match box(arg) with
                    | :? int64 as i -> (sqrtd i) |> int64 |> box
                    | :? int as i -> (sqrtd i) |> int |> box
                    // cases for other relevant integral types
                    | _ -> failwith "Unsupported type"
    unbox result

and then, checking in FSI:

> let result: int = sqRoot 4;;
val result : int = 2
> let result: int64 = sqRoot 9L;;
val result : int64 = 3L
Gene Belitski
  • 10,270
  • 1
  • 34
  • 54