F#中的全局运算符重载

时间:2013-10-30 12:36:24

标签: f# operators

我开始为笛卡尔积和矩阵乘法定义我自己的算子。

将矩阵和向量别名为列表:

type Matrix = float list list
type Vector = float list

我可以写下我自己的初始化代码(并通过写作获得笛卡尔产品)

let inline (*) X Y =
    X |> List.collect (fun x -> Y |> List.map (fun y -> (x, y)))

let createVector size f = 
    [0..size - 1] |> List.map (fun i -> f i)

let createMatrix rows columns f =
    [0..rows - 1] * [0..columns - 1] |> List.map (fun i j -> f i j)

到目前为止一切顺利。问题是我对*的定义消除了正常定义,即使我的版本仅为列表定义,但没有自己的乘法运算符。

文档http://msdn.microsoft.com/en-us/library/vstudio/dd233204.aspx指出“新定义的运算符优先于内置运算符”。但是,我没想到所有的数字化身都被消灭了 - 当然静态打字会照顾到这个吗?

我知道可以定义一个尊重类型的全局运算符,因为MathNet Numerics使用*进行矩阵乘法。我还想走这条路,这需要打字系统优先考虑矩阵乘法优先于Matrix类型(它们本身就是列表)的笛卡尔乘积。

有人知道如何在F#中执行此操作吗?

2 个答案:

答案 0 :(得分:13)

这是(非惯用的)解决方案:

type Mult = Mult with
    static member inline ($) (Mult, v1: 'a list) = fun (v2: 'b list) -> 
        v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
    static member inline ($) (Mult, v1:'a      ) = fun (v2:'a) -> v1 * v2 :'a

let inline (*) v1 v2 = (Mult $ v1) v2

答案 1 :(得分:10)

惯用解决方案是将Matrix定义为新类型,并将运算符添加为静态成员:

type Matrix = 
  | MatrixData of float list list
  static member (*) (MatrixData m1, MatrixData m2) = (...)

使用let定义的运算符在您知道定义与其他任何内容不冲突时,或者在小范围内(在函数内)本地定义运算符时非常有用。

对于自定义类型,最好将运算符定义为静态成员。这种方法的另一个好处是您的类型可以从C#(包括运算符)中使用。

要在您的示例中执行此操作,我必须将类型定义从类型别名(不是独立类型,因此它不能拥有自己的静态成员)更改为单个案例区分联合,它可以具有成员 - 但无论如何这可能是一个好主意。