如何在不破坏对其他类型的支持的情况下正确地重载全局(+)和(*)

Duc*_*tro 3 f# operator-overloading

我已经导入了一个矢量数学库,并希望添加我自己的(*)和(+)运算符,同时保留基本int和float的现有运算符.

我尝试过以下方法:

let inline (*) (x : float) (y : Vector) = y.Multiply(x)
let inline (*) (x : Vector) (y : float) = x.Multiply(y)
let inline (+) (x : Vector) (y : Vector) = x.Add(y)
Run Code Online (Sandbox Code Playgroud)

这有两个问题:

  1. 它似乎删除int + intint * int,和
  2. 第二行(旨在完成交换)不编译,因为它是"重复定义".

如何在我导入的Vector类型上定义一些可交换运算符,同时也不会在int和float上丢失这些操作?

(我希望能够使用*和+在其他地方编写通用代码,而不必指定float/Vector/int类型约束).

pad*_*pad 10

如果您能够修改库的源代码,则通过类型扩展添加一些重载更简单:

type Vector with
    static member (*) (x : Vector) (y : float) = x.Multiply(y)
    static member (+) (x : Vector) (y : Vector) = x.Add(y)
Run Code Online (Sandbox Code Playgroud)

但是,如果第一个操作数具有基本类型(例如,您的第一个示例),则重载分辨率不再起作用.

无论如何,您可以利用成员重载并将约束传播到内联函数:

type VectorOverloadsMult =
    | VectorOverloadsMult
    static member (?<-) (VectorOverloadsMult, x: float, y: Vector) = y.Multiply(x)
    static member (?<-) (VectorOverloadsMult, x: Vector, y: float) = x.Multiply(y)     
    static member inline (?<-) (VectorOverloadsMult, x, y) = x * y

let inline (*) x y = (?<-) VectorOverloadsMult x y
Run Code Online (Sandbox Code Playgroud)

这适用于现有类型,(*)因为我们将它们保存在最后一个静态成员中.你可以为(+)运营商做同样的事情.

let v: Vector = ... // Declare a Vector value
let a = 2.0 * v
let b = v * 2.0
let c = 2 * 3
let d = 2.0 * 3.0
Run Code Online (Sandbox Code Playgroud)

即使您无法修改Vector类型,此技术也可以使用.