2

「プログラミング 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または、元のコードを簡素化できる他のソリューションはありますか?

4

1 に答える 1

6

これを達成するために使用LanguagPrimitives.GenericOneしてLanguagPrimitives.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 に答える