使用F#的静态类型参数和编码数字常量

Gre*_*Ros 5 generics f# numbers bit-manipulation inline

我在F#中编写了一个提供一些按位操作的库¹,我想确保尽可能多的函数是inline使用静态类型参数进行绑定(这允许我编写一个函数并将其用于int16,int32也许甚至bignum只有很少的开销).这条路线肯定无法在某些时候起作用.所述库提供的一些功能有些复杂.

¹注意:我知道通过公共接口公开内联let绑定的问题.

但是,我想把它延伸到最远的程度.现在,我正在尝试以这种形式编写人口计数算法,我正面临一个问题.我不确定如何对掩码进行编码,例如0x3333...,这些算法中出现的掩码.我可以使用一些额外的技巧来绕过移位常数和类似的东西.

有没有我可以使用的技巧,无论是通过F#的类型推断和静态类型参数,还是通过bit-twiddling,以我想要的方式编写算法?有没有什么办法可以在静态泛型函数中编码这些常量?

一个更模糊的问题:我是否可以依赖一些特定的东西来充分利用静态类型参数,尤其是在数值的背景下?例如,我大量使用GenericOneGenericZero.还有更多这样的事情,我可能错过了吗?

pad*_*pad 5

首先,您可以使用数字文字来避免丑陋地使用GenericOneGenericZero.这是一个简短的例子:

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

其次,F#似乎不支持通用的六进制数字文字.一个技巧是使用双反引号,以便您有指示性名称:

let inline shift x = 
    let ``0x33333333G`` = 858993459G
    ((x >>> 2) &&& ``0x33333333G``) + (x &&& ``0x33333333G``)

// Usage
shift 20
shift 20L
shift 20uy
Run Code Online (Sandbox Code Playgroud)

有关数字文字的SO有一些很好的问题.如果你走这条路,我会提供一些参考: