假设我正在构造一个带有单个参数f
的F#泛型函数integral
,并且函数语义的这个参数应该被约束到来自System.SByte
的任何.NET整数类型通过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
则不会。
如果有的话,使用第二种方法比第一种方法有什么好处?
是否有更多惯用的方法可以达到最初的目标?
更新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
答案 0 :(得分:1)
第一个更好。 F#的类型推断实际上做了约束。显式约束是表明你想做什么的一种方式。什么可能比更好并让编译器静态地证明该参数对于操作有效?我不确定我是否看到了超出函数本身所指示的“整体约束”的好处。但也许你可以列出更多的案例。
答案 1 :(得分:1)
如果您真的只想将可能性限制为完整的类型,那么使用重载静态方法将是另一种选择。为了减少代码重复,这些都可以通过不受限制的通用函数来实现。