F#运算符重载:(+)表示用户定义的类型

时间:2010-03-15 21:10:49

标签: f# operator-overloading

以下代码在“评估”中失败: “这个表达式预计有复杂类型,但这里有类型双列表” 我是否在'(+)'上打破了运算符过载的规则? 如果我将'(+)'改为'添加',那就没事了。

open Microsoft.FSharp.Math

/// real power series [kn; ...; k0] => kn*S^n + ... + k0*S^0
type Powers = double List

let (+) (ls:Powers) (rs:Powers) =
    let rec AddReversed (ls:Powers) (rs:Powers) =
        match ( ls, rs ) with
        | ( l::ltail, r::rtail ) -> ( l + r ) :: AddReversed ltail rtail
        | ([], _) -> rs
        | (_, []) -> ls
    ( AddReversed ( ls |> List.rev ) ( rs |> List.rev) ) |> List.rev

let Evaluate (ks:Powers) ( value:Complex ) =
    ks |> List.fold (fun (acc:Complex) (k:double)-> acc * value +  Complex.Create(k, 0.0)  ) Complex.Zero 

1 个答案:

答案 0 :(得分:9)

您的代码的问题在于您的+定义实际上隐藏了所有先前的运算符定义,因此F#编译器认为+只能用于添加Powers值。这是因为包含F#运算符的函数值(使用let声明)不支持重载。

但是,如果将F#运算符添加为某种类型的static member,则可以重载它们。这不适用于abberviations,因此您需要首先将类型声明更改为记录或区分联合(我选择第二个选项)。然后你可以像这样实现重载运算符:

/// real power series [kn; ...; k0] => kn*S^n + ... + k0*S^0 
type Powers = 
  | P of double list 
  static member (+) (P ls, P rs) = 
    let rec AddReversed ls rs = 
        match ( ls, rs ) with 
        | ( l::ltail, r::rtail ) -> ( l + r ) :: AddReversed ltail rtail 
        | ([], _) -> rs 
        | (_, []) -> ls 
    P (( AddReversed ( ls |> List.rev ) ( rs |> List.rev) ) |> List.rev)

请注意,运算符现在声明为Powers类型的一部分。由于类型是一个有区别的联合,我需要添加展开参数(P ls, P rs),然后再次包装结果。您的Evaluate函数将如下所示:

let Evaluate (P ks) ( value:Complex ) = 
  ks |> List.fold (fun (acc:Complex) (k:double)-> 
    acc * value +  Complex.Create(k, 0.0)  ) Complex.Zero

它再次需要打开值(P ks),但其余代码没有改变。