我们可以使用更通用的类型来缩短F#中的代码吗?

时间:2013-04-23 06:47:52

标签: f# inline primitive

我在阅读“编程F#3.0”时遇到了这段代码:

type BitCounter =

    static member CountBits (x : int16) =
        let mutable x' = x
        let mutable numBits = 0
        for i = 0 to 15 do
            numBits <- numBits + int (x' &&& 1s)
        x' <- x' >>> 1
        numBits

    static member CountBits (x : int) =
        let mutable x' = x
        let mutable numBits = 0
        for i = 0 to 31 do
            numBits <- numBits + int (x' &&& 1)
        x' <- x' >>> 1
        numBits

    static member CountBits (x : int64) =
        let mutable x' = x
        let mutable numBits = 0
        for i = 0 to 63 do
            numBits <- numBits + int (x' &&& 1L)
        x' <- x' >>> 1
        numBits

我尝试通过辅助功能来缩短这部分:

type BitCounter =

    static member CountBitsWithRangedMask x upBound typeConverter =
        seq { for i = 0 to upBound do yield 1 <<< i }
            |> Seq.map typeConverter
            |> Seq.map ((&&&) x)
            |> Seq.filter ((<>) (typeConverter 0))
            |> Seq.length

    static member CountBits (x : int16) =
        BitCounter.CountBitsWithRangedMask x 15 int16

    static member CountBits (x : int) =
        BitCounter.CountBitsWithRangedMask x 31 int

    static member CountBits (x : int64) =
        BitCounter.CountBitsWithRangedMask x 63 int64

static member CountBits (x : int)导致编译错误:

error FS0001: This expression was expected to have type
    int16
but here has type
    int

所以我想知道我是否可以在Integral a的第一个参数中在Haskell中添加一些像CountBitsWithRangedMask这样的约束。 或者是否有其他解决方案可以简化原始代码?

1 个答案:

答案 0 :(得分:6)

您可以使用LanguagPrimitives.GenericOneLanguagPrimitives.GenericZero结合inline来实现此目标。

let inline CountBitsWithRangedMask x upBound =
    seq { for i = LanguagePrimitives.GenericZero to upBound do yield LanguagePrimitives.GenericOne <<< i }
    |> Seq.map ((&&&) x)
    |> Seq.filter ((<>) (LanguagePrimitives.GenericZero))
    |> Seq.length

let test16 (x:System.Int16) = CountBitsWithRangedMask x 15
let test32 (x:System.Int32) = CountBitsWithRangedMask x 31
let test64 (x:System.Int64) = CountBitsWithRangedMask x 63

使用它我们也不需要typeConverter参数,因为编译器会自动完成所有操作。

对于这些问题,这是一种相当普遍的方法。