我在阅读“编程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
这样的约束。
或者是否有其他解决方案可以简化原始代码?
答案 0 :(得分: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
参数,因为编译器会自动完成所有操作。
对于这些问题,这是一种相当普遍的方法。