【发布时间】:2013-05-24 14:42:58
【问题描述】:
假设我正在构造一个带有单个参数 integral 的 F# 泛型函数 f,并且函数语义的此参数应限制为从 System.SByte 到 System.Int32 到 @ 的任何 .NET 整数类型987654328@.
一种方法是实施
let inline f (integral: 'a) =
(* function body here *) ...
并依赖于从f 主体的实际内容派生的'a 的编译器推导约束,这可能与.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 日更新 具有讽刺意味的是,仅在今天查看 this answer 后,才设法从 @kvb's prompt 中得到一个工作代码:
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
【问题讨论】:
-
答案难道不取决于您为什么要首先限制允许的类型吗?
-
一个意图示例,可能有点人为:比较的行为类似于
sign的积分,但不同的是string。 -
Hackish 方法 - 将
GenericZero添加到应该将您限制为数字类型的参数。然后,您可以在运行时检查该类型中的3/2是否等于1,这对于浮动类型不会发生。