F#中的泛化函数

时间:2014-01-01 00:27:14

标签: optimization f# inline automatic-generalization

我需要一个在F#中产生素数的函数。我发现了这个:

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

这非常有效,但有时我也需要使用int64 / BigInts。是否有一种更巧妙的方法来重用此代码而不是提供其他类似的序列:

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

我听说过使用" inline"修改代码和" LanguagePrimitives",但我发现的所有内容都与函数有关,而我的问题与某个值有关。

此外 - 我希望有一个适用于整数类型的函数,并计算平方根的底数。

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

但是我无法看到一种返回与#34; arg"相同类型的方法。是,因为Math.Sqrt返回一个double。再说一次 - 有没有比重新实现自己计算平方根的逻辑更好的了?

2 个答案:

答案 0 :(得分:4)

因此,执行此操作的一般方法需要函数和语言原型 - 在您的情况下,只要1编写LanguagePrimitives.GenericOne,就会生成11.0等等。根据需要。

要使其工作,您需要创建一个函数值 - 您可以通过执行以下操作来避免这种情况:

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()

我对sqrt案例不太确定 - 这可能取决于你是否愿意做出解决方案。

答案 1 :(得分:2)

通用sqRoot的天真实现可能会遵循以下几点:

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

然后,检查FSI:

> let result: int = sqRoot 4;;
val result : int = 2
> let result: int64 = sqRoot 9L;;
val result : int64 = 3L