views:

71

answers:

1

The following code fails in 'Evaluate' with:
"This expression was expected to have type Complex but here has type double list"
Am I breaking some rule on operator over-loading on '(+)'?
Things are OK if I change '(+)' to 'Add'.

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 
+6  A: 

The problem with your code is that your definition of + actually hides all previous definitions of the operator, so the F# compiler thinks that + can be used only for addition of Powers values. This is because function values (declared using let) including F# operators do not support overloading.

However, you can overload F# operators if you add them as a static member of some type. This doesn't work for abberviations, so you'll need to change the type declaration to a record or discriminated union first (I choose the second option). Then you can implement overloaded operator like this:

/// 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)

Note that the operator is now declared as part of the Powers type. Since the type is a discriminated union, I needed to add unwrapping of parameters (P ls, P rs) and then again wrap the result. Your Evaluate function will look like this:

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

It again needs to unwrap the value (P ks), but the rest of the code is unchanged.

Tomas Petricek