【问题标题】:Constraining F# generic function argument to integral types将 F# 泛型函数参数约束为整数类型
【发布时间】:2013-05-24 14:42:58
【问题描述】:

假设我正在构造一个带有单个参数 integral 的 F# 泛型函数 f,并且函数语义的此参数应限制为从 System.SByteSystem.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 1uyf 1Lf 1I 立即通过静态类型检查,但f 'a'f 1.0f 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,这对于浮动类型不会发生。

标签: generics f#


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 有点夸张,但假设您定义了let inline equals a b = match Operators.compare a b with | 1 | -1 -&gt; false | _ -&gt; true,然后不幸有一天equals "A" "b"true
    • 你在隐藏内置函数吗?无论如何,您的问题似乎不是最好通过约束来解决,但是您尝试做的更完整的示例会有所帮助。
    • @GeneBelitski 好吧,那将是您应该修复的代码中的错误。我不确定如何限制也支持按位或提供帮助的类型。特别是因为例如int.CompareTo() is documented 在结果为“少”时返回负数,不一定是 -1。
    • @svick:我重申这是一个完全人为的、编造的、“糟糕的做法”、比较依赖于实现的示例;然而事实是,与编译器推断的约束巧合的是,观察到的函数行为将是错误的,并且手工挑选的约束参数仅限于整数类型 - 对。
    猜你喜欢
    • 2020-09-16
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多