如何在实现中缀运算符时避免循环依赖

时间:2016-11-24 15:52:46

标签: matrix vector f# operators static-methods

我们假设我希望在F#中实现Vector和Matrix类。该语言不允许循环依赖,因此我不能让Vector类引用Matrix类,反之亦然。让我们进一步说,我选择这两个类都不应该依赖于另一个(与例如Vector取决于Matrix而不是相反的情况相反)。

现在我想用一个Vector实例实现矩阵实例的右乘,即a * b,其中a是矩阵,b是Vector。首先想到的是将op_Multiply声明为静态成员方法,例如Matrix类。在C#中,这意味着要使用带有此签名的静态方法

public static Vector operator *(Matrix matrix, Vector vector);

例如Matrix类。但是,此操作既依赖于Vector类又依赖于Matrix类,因此不能在Matrix和Vector类中声明,因为不允许这些操作相互依赖。

下一个想法可能是将它声明为某种扩展方法,在F#中的效果如下:

[<Extension>]
static member (*) (matrix : IMatrix, vector : IVector) =
    ...

但是,这只允许我写一些类似

的内容
a.op_Multiply(b)

而不是

a * b

从某种意义上说,这里的问题是我无法编写“运算符扩展方法”。如何定义乘法方法,以避免Matrix和Vector相互依赖,同时还能实现写“a * b”之类的东西?

1 个答案:

答案 0 :(得分:4)

我认为您可以将let - 运算符编写为具有[<AutoOpen>]属性的模块中的绑定函数:

module Foo =
    type Bar = Bar of string

module Ploeh =
    type Fnaah = Fnaah of string

[<AutoOpen>]
module Operators =
    let (+) (Foo.Bar b) (Ploeh.Fnaah f) = b + f

open Foo
open Ploeh

let sum = (Bar "sgryt") + (Fnaah "ler")

这至少会产生FSI的预期输出:

> let sum = (Bar "sgryt") + (Fnaah "ler");;    
val sum : string = "sgrytler"

这不是我经常做的事情,所以我不能说是否有一些角落案例会使这项工作在实践中不那么理想......