将F#泛型函数参数约束为整数类型

时间:2013-05-24 14:42:59

标签: generics f#

假设我正在构造一个带有单个参数f的F#泛型函数integral,并且函数语义的这个参数应该被约束到来自System.SByte的任何.NET整数类型通过System.Int32System.Numerics.BigInteger

一种方法是实施

let inline f (integral: 'a) =
    (* function body here *) ...

并依赖于编译器推导的约束'af的实体内容派生而来,这可能与整数.NET的集合一致,也可能不一致 类型。

另一种方法可能是强制显式选择先验约束到'a,这将真正保证已知的.NET类型只有整数类型传递静态 检查,例如

let inline f (integral: ^a when ^a:(static member (|||): ^a * ^a-> ^a)) =
    (* function body here, unit for illustration *)()

let inline f< ^a when ^a : (static member (|||): ^a * ^a -> ^a)> (integral: ^a) =
    (* function body here, unit for illustration *)()

所以f 1uyf 1Lf 1I会立即通过静态类型检查,但f 'a'f 1.0f 1m则不会。

如果有的话,使用第二种方法比第一种方法有什么好处?

是否有更多惯用的方法可以达到最初的目标?

更新02/03/2014 具有讽刺意味的是,只有在this answer查看@kvb's prompt之后才能获得{{3}}的工作代码:

let inline implementation integral = ((* whatever implementation here *)) 

type Integral = Integral with 
    static member ($) (Integral, value: byte) = implementation value
    static member ($) (Integral, value: sbyte) = implementation value
    static member ($) (Integral, value: int16) = implementation value
    static member ($) (Integral, value: uint16) = implementation value
    static member ($) (Integral, value: int) = implementation value
    static member ($) (Integral, value: uint32) = implementation value
    static member ($) (Integral, value: int64) = implementation value
    static member ($) (Integral, value: uint64) = implementation value
    static member ($) (Integral, value: bigint) = implementation value

let inline doit integral = Integral $ integral

doit 1
doit 1I
doit 1.0 // does not compile
doit 1.0m // does not compile
doit '1' // does not compile

2 个答案:

答案 0 :(得分:1)

第一个更好。 F#的类型推断实际上做了约束。显式约束是表明你想做什么的一种方式。什么可能比更好并让编译器静态地证明该参数对于操作有效?我不确定我是否看到了超出函数本身所指示的“整体约束”的好处。但也许你可以列出更多的案例。

答案 1 :(得分:1)

如果您真的只想将可能性限制为完整的类型,那么使用重载静态方法将是另一种选择。为了减少代码重复,这些都可以通过不受限制的通用函数来实现。