2

我在阅读“Programming 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在 HaskellCountBitsWithRangedMask的第一个参数上添加一些约束。或者有没有其他可以简化原始代码的解决方案?

4

1 回答 1

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参数,因为编译器会自动执行所有操作。

对于这类问题,这是一种相当通用的方法。

于 2013-04-23T08:15:57.920 回答