2015-10-28 2 views
5

я пытаю следующее: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 и переопределить все операторы, если я хочу, чтобы он делал другие вещи, которые делают сложные числа?

+0

Да, возможно, создание обертки - это путь. См. Здесь: http://stackoverflow.com/questions/3223660/can-existing-types-be-extended-to-work-with-seq-sum-etc – Petr

+0

Вещь, которую вы ищете, называется «более высокой полиморфизм ", и, к сожалению, F # не поддерживает его вообще. Вот голосовая просьба пользователя, пожалуйста, проголосуйте: http: //fslang.uservoice.ком/форумы/245727-е-язык/предложения/5664242-симулировать-выше-kinded-полиморфизм –

ответ

4

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

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

Возможно, это можно будет исправить в будущей версии F #, но проблема в том, что ограничения статического члена не работают с полями, если у них нет геттера. Однако в F # lib они могут «эмулировать» те элементы для существующих типов, they do it normally with primitive types в противном случае это не сработает с int, float, так как они тоже не имеют этого члена.

Я не уверен, что тот факт, что Complex определен в System.Numerics, был причиной того, что он не реализовал его таким образом, или может быть, они просто забыли его. В любом случае вы можете открыть проблему или отправить запрос на перенос, чтобы зафиксировать его.

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

1

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

Использование List.fold вместо:

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

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