F#中的全局运算符重载

Rob*_*don 16 f# operators

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

矩阵和向量别名为列表:

type Matrix = float list list
type Vector = float list
Run Code Online (Sandbox Code Playgroud)

我可以通过写作来编写自己的初始化代码(并将笛卡尔产品纳入讨价还价)

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)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.问题是我的定义*消除了正常的定义,即使我的版本仅为Lists定义,而Lists没有自己的乘法运算符.

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

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

有谁知道如何在F#中做到这一点?

Gus*_*Gus 14

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

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
Run Code Online (Sandbox Code Playgroud)

  • 是的,如果您想了解更多相关信息,我做了一个项目,使用了这种技术的改进https://github.com/gmpl/FsControl (3认同)

Tom*_*cek 11

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

type Matrix = 
  | MatrixData of float list list
  static member (*) (MatrixData m1, MatrixData m2) = (...)
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • "谁在乎它是否是惯用的?" - 那么每个人都必须阅读,维护和扩展代码...... (8认同)
  • 谁在乎它是否是惯用的 - 也许与.NET相关.我更喜欢Gustavo的解决方案,它是类型安全的,它更优雅,更实用,它在F#中提供'类型类',这一切都很重要!也许F#在未来的版本中应该得到更好的支持. (5认同)