2016-11-24 73 views
3

假设我希望在F#中实现Vector和Matrix类。该语言不允许循环依赖,所以我不能同时使用Vector类和Matrix类,反之亦然。我们还要说,我做出选择,任何一个类别都不应该依赖于其他类型(与例如Vector取决于Matrix的情况相反,而不是其他方式)。如何在实现中缀运算符时避免循环依赖关系

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

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

on Matrix类。但是,此操作既取决于Vector类又取决于Matrix类,因此不能在Matrix和Vector类中声明,因为它们不允许相互依赖。

下一个想到的可能是将其声明为某种形式的扩展方法,在F#的东西的影响:

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

然而,这只是让我写东西像

a.op_Multiply(b) 

而不是

a * b 

这里的问题在某种意义上是,我不能写“operator ext外挂方式“。如何定义乘法方法,以避免矩阵和矢量互相依赖,同时还能实现像“a * b”这样的功能?

+2

首先,F#允许圆形d在小范围内的附属性。如果你愿意,你可以完全让'Vector'和'Matrix'互相引用。其次,要根据以前定义的类型定义一个运算符,使其成为一个独立的函数,而不是类方法。 –

回答

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" 

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