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

Jav*_*ran 2 primitive f# inline

我在阅读"编程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
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

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

error FS0001: This expression was expected to have type
    int16
but here has type
    int
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*mer 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
Run Code Online (Sandbox Code Playgroud)

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

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