F# - Как расширить тип с get Zero, чтобы я мог использовать существующий тип в общем виде?


Я пытаюсь сделать следующее:

let c x = System.Numerics.Complex(x, 0.0)
let sum = [c 1.0; c 2.0] |> List.sum

Но я получаю эту ошибку:

The type 'System.Numerics.Complex' does not support the operator 'get_Zero'

Я читал правила о расширении типов, начиная с https://msdn.microsoft.com/en-us/library/dd233211.aspx , и попробуйте сделать следующее:

module ComplexExtension =
    let c x = System.Numerics.Complex(x, 0.0)

    type System.Numerics.Complex with
        // I also tried a bunch of other ways of writing these
        // as static or instance members, but nothing worked
        static member Zero = c 0.0
        static member One = c 1.0

open ComplexExtension

let sum = [c 1.0; c 2.0] |> List.sum

Я все еще получаю эту ошибку.

Можно ли расширить тип с помощью оператора get_Zero? Или мне нужно создать свой собственный тип оболочки вокруг System.Numerics.Complex и переопределить все операторы, если я хочу, чтобы он делал другие вещи, которые сложные числа делать?

2 6

2 ответа:

List.sum использует статические ограничения членов. Статические ограничения членов не рассматривают методы расширений, так что это не вариант.

Обертывание всего сложного типа-это вариант, но это перебор, если это просто конкретный вызов, у вас есть много способов вычислить сумму с помощью еще нескольких нажатий клавиш, вы можете использовать fold, как показано на другом ответе. В качестве альтернативы можно использовать List.reduce (+), Если вы уверены, что в списке всегда будет хотя бы один элемент.

Это может быть возможно получить исправлено в будущей версии F#, но проблема в том, что статические ограничения членов не работают с полями, если у них нет геттера. Однако в F# lib они могут "эмулировать" эти члены для существующих типов, они делают это обычно с примитивными типами иначе это не будет работать с int, float, поскольку у них тоже нет этого члена.

Я не уверен, был ли тот факт, что Complex определен в System.Numerics, причиной, чтобы не реализовать его таким образом, или, возможно, они просто забыли об этом. В в любом случае вы можете открыть проблему или отправить запрос на ее устранение. Наконец, еще один вариант, если вы все еще хотите использовать его в общем виде, - это переопределить функцию sum. Например, функция sum (вот источник ) из последней версии F#+ будет работать нормально (у нее была та же проблема, но ее было очень легко исправить, на самом деле это была ошибка) практически со всеми числовыми типами, включая Complex и большинство сторонних числовых типов, потому что у нее есть запасной вариант механизм, который полагается в некоторых преобразованиях, когда тип не имеет члена get_Zero.

List.sum не распознает Zero, определенный как расширение. Он должен быть частью этого типа.

Вместо этого используйте List.fold:

let sum = [c 1.0; c 2.0] |> List.fold (+) Complex.Zero

Кстати, System.Numerics.Complex на самом деле имеет статическое Zero, но это поле, а не свойство.