3

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

let inline ( |+| ) (m1 : #IMeasurable) (m2 : #IMeasurable) = m1.Measure + m2.Measure

问题是,我不能这样做:

let three = m1 |+| m2 |+| m3

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

谢谢你。

4

2 回答 2

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

未经测试,因为我没有 IMeasurable,但它可能会完成这项工作。

于 2012-10-19T10:25:31.377 回答
6

如果您要定义一个行为类似的运算符,+那么我认为最好的设计是定义一个返回与其参数类型相同类型的值的运算符。这意味着我会将运算符更改为 returnIMeasurable而不是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)

这将使操作符定义更加统一和易于使用。您要编写的代码现在可以工作(返回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 (|+|)

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

于 2012-10-19T10:30:15.597 回答