Перегрузка оператора F #: (+) для определяемого пользователем типа - PullRequest
3 голосов
/ 16 марта 2010

Следующий код завершается с ошибкой в ​​'Evaluate' с помощью:
«Ожидается, что это выражение будет иметь тип Complex, но здесь имеет тип двойной список»
Я нарушаю какое-то правило перегрузки оператора на '(+)'?
Все в порядке, если я изменю «(+)» на «Добавить».

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 Ответ

9 голосов
/ 16 марта 2010

Проблема с вашим кодом в том, что ваше определение + фактически скрывает все предыдущие определения оператора, поэтому компилятор F # считает, что + можно использовать только для добавления значений Powers. Это связано с тем, что значения функций (объявленные с использованием let), включая операторы F #, не поддерживают перегрузку.

Однако вы можете перегрузить операторы F #, если добавите их как static member некоторого типа. Это не работает для аббревиатур, поэтому вам нужно сначала изменить объявление типа на запись или дискриминированное объединение (я выбираю второй вариант). Тогда вы можете реализовать перегруженный оператор так:

/// 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), но остальная часть кода остается неизменной.

...