2

假设我正在构造一个f带有单个参数的 F# 泛型函数integral,并且函数语义的这个参数应该被限制为从 到 的任何 .NETSystem.SByte整数System.Int32类型System.Numerics.BigInteger

一种方法是实施

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

并依赖编译器推导的约束'a从 ' 的主体的实际内容派生f,这可能与 .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 1uy, f 1L,f 1I马上通过静态类型检查,但是f 'a', f 1.0,f 1m没有。

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

有没有更惯用的方法来达到最初的目标?

更新 2014年 2 月 3日具有讽刺意味的是,仅在今天查看此答案后,才设法从@kvb 的提示中获取了工作代码:

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
4

2 回答 2

1

第一个更好。F# 的类型推断实际上做了正确的约束。显式约束是一种说明您想要做什么的方式。有什么比做并让编译器静态地证明参数对操作有效更好的呢?我不确定我是否看到在函数体本身规定的范围之外拼出“整体约束”的好处。但也许你可以列出更多你的情况。

于 2013-05-24T15:42:53.017 回答
1

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

于 2013-05-24T16:20:09.770 回答