我正在尝试为包装类定义通用加法运算符。到目前为止我有这个:(从实际代码简化)
type Wrap<'a> =
| Wrap of 'a
static member inline (+) (Wrap x, Wrap y) = Wrap (x + y)
let inline addSelf x = x + x
确实有效:
let i = addSelf (Wrap 1) // returns Wrap 2
let f = addSelf (Wrap 1.) // returns Wrap 2.0
但是以下 addSelf 的替代方案无法编译
let inline addSelf' (Wrap x) = (Wrap x) + (Wrap x) // compile error
给出错误 FS0193:类型参数缺少约束 'when (^a 或 ^?15169) : (static member (+) : ^a * ^?15169 -> ^?15170)'
为什么当 addSelf 工作正常时,更受限制的 addSelf' 却不起作用?谢谢!
最佳答案
正如我在评论中所说,我认为这是一个错误。这是我的推理。当编译器看到
let inline addSelf (Wrap x) = (Wrap x) + (Wrap x)
我认为大致应该做出以下推论:
- 参数的类型为
Wrap< ^t>
一些新鲜的^t
. - 因此
x
类型为^t
. - 因此,右侧的操作数也都是
Wrap< ^t>
类型. - 这些值将被传递到
(+)
运算符(operator)。因此,Wrap< ^t>
需要支持静态运算符(+)
类型Wrap< ^t> * Wrap< ^t> -> ^u
对于一些新鲜类型^u
. - 唯一的静态运算符
(+)
定义于Wrap<_>
类型为Wrap< ^a> * Wrap< ^b> -> Wrap< ^c> when (^a or ^b) : (static member (+) : ^a * ^b -> ^c
. - 统一类型变量,整体类型
addSelf
应该是addSelf : Wrap< ^t> -> Wrap< ^c> when ^t : (static member (+) : ^t * ^t -> ^c)
各种类型推断步骤都很棘手,所以我肯定可能遗漏了一些东西,而这种行为是预期的。另一方面,各种类型推断步骤很棘手,因此它们有点错误:)。还令人担忧的是,您无法注释函数和所有子表达式并编译代码:
let inline doStuff< ^t, ^u when ^t : (static member (+) : ^t * ^t -> ^u)> ((Wrap x) : Wrap< ^t>) : Wrap< ^u> =
((Wrap x) : Wrap< ^t>) + ((Wrap x) : Wrap< ^t>)
您仍然会收到编译器错误,其中包含对新类型参数的神秘引用 ^?12020
和^?12021
(或者你的情况下任何独特的整数)。我认为这不应该发生。
关于generics - F# 类型参数缺少约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6849557/