我在F#中编写一个库¹,它提供了一些按位操作,我想确保尽可能多的函数inline
让静态类型参数绑定(这允许我编写一个函数)并将其用于int16
,int32
,甚至bignum
,只需很少的开销。这条路线肯定无法在某个时刻起作用。所述库提供的一些功能有些复杂。
¹注意:我知道通过公共接口公开内联let绑定的问题。
但是,我想把它延伸到最远的程度。现在,我正试图以这种形式编写population count算法,我遇到了一个问题。我不确定如何编码掩码,例如0x3333...
,出现在这些算法中。我可以使用一些额外的技巧来绕过移位常数和类似的东西。
我是否可以使用任何技巧,无论是通过F#的类型推断和静态类型参数,还是通过bit-twiddling,以我想要的方式编写算法?有什么办法可以在静态泛型函数中编码这些常量吗?
一个更模糊的问题:我是否可以依赖一些特定的东西来充分利用静态类型参数,尤其是在数值的背景下?例如,我大量使用GenericOne
和GenericZero
。还有更多这样的事情,我可能错过了吗?
答案 0 :(得分:5)
首先,您可以使用numeric literals来避免对GenericOne
和GenericZero
的丑陋使用。这是一个简短的例子:
module NumericLiteralG = begin
let inline FromZero() = LanguagePrimitives.GenericZero
let inline FromOne() = LanguagePrimitives.GenericOne
let inline FromInt32 (n:int) =
let one : ^a = FromOne()
let zero : ^a = FromZero()
let n_incr = if n > 0 then 1 else -1
let g_incr = if n > 0 then one else (zero - one)
let rec loop i g =
if i = n then g
else loop (i + n_incr) (g + g_incr)
loop 0 zero
end
// Usage
let inline ten() = 10G
ten() + 1
ten() + 2L
其次,F#似乎不支持泛型六进制数字文字。一个技巧是使用双反引号,以便您有指示性名称:
let inline shift x =
let ``0x33333333G`` = 858993459G
((x >>> 2) &&& ``0x33333333G``) + (x &&& ``0x33333333G``)
// Usage
shift 20
shift 20L
shift 20uy
关于数字文字,有一些很好的问题。如果你走这条路,我会提供一些参考资料: