F#中重载的内联运算符:(| + |)

Gre*_*Ros 3 syntax f# operator-overloading

我正在尝试定义一个重载的运算符,例如|+|,如下所示:

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = m1.Measure + m2.Measure
Run Code Online (Sandbox Code Playgroud)

问题是,我做不了类似的事情:

let three = m1 |+| m2 |+| m3
Run Code Online (Sandbox Code Playgroud)

因为|+|没有为案例定义操作员(m1 : int) (m2 : #IMeasurable).有没有办法重载此运算符或使用静态类型约束使上述表达式成为可能?有没有办法修改IMeasurable(我可以编辑),这是可能的?还有什么能让上面的表达能够起作用?

谢谢.

Gus*_*Gus 11

type Overloads = Overloads with
    static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure 
    static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure

let inline ( |+| ) m1 m2 = (Overloads $ m1) m2
Run Code Online (Sandbox Code Playgroud)

没有经过测试,因为我没有IMeasurable,但它可以完成这项工作.


Tom*_*cek 5

如果您正在定义一个行为类似的运算符,+我认为最好的设计是定义一个运算符,该运算符返回与其参数类型相同类型的值.这意味着我会将运算符更改为return IMeasurable而不是int:

type IMeasurable =
  abstract Measure : int

let newMeasure m = 
  { new IMeasurable with 
      member x.Measure = m }

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = 
  newMeasure (m1.Measure + m2.Measure)
Run Code Online (Sandbox Code Playgroud)

这将使操作员定义更加统一和易于使用.您想要编写的代码现在可以工作(返回IMeasurable),但您也可以使用Seq.reduce:

// Now you can add multiple measure values without issues
let res = (newMeasure 2) |+| (newMeasure 3) |+| (newMeasure 4)

// Moreover, you can also use `Seq.reduce` which would not work
// with your original operator (because it has wrong type)
let res = [newMeasure 2; newMeasure 3; newMeasure 4] |> Seq.reduce (|+|)
Run Code Online (Sandbox Code Playgroud)

也就是说,如果你真的想要重载使用的运算符,let你不能将它作为静态成员添加到类型中(因为你不能修改类型),那么你需要使用Gustavo描述的技巧