Есть ли у F # общая арифметическая поддержка?

Есть ли у F # такая же проблема, как у С#, где вы не можете напрямую использовать арифметические операторы с общими типами T?

Можете ли вы написать общую функцию Sum, которая вернет сумму любого значения, которое поддерживает арифметическое дополнение?

Ответы

Ответ 1

Как упоминал Брайан, существует некоторая встроенная поддержка общего арифметического, и вы можете использовать "статические ограничения", которые позволяют вам определять некоторые общие функции самостоятельно (хотя это немного ограничено).

В дополнение к этому вы также можете использовать динамические "числовые ассоциации", которые при использовании в функции немного медленнее, но его можно использовать, например, для определения собственного вектора или типа матрицы. Вот пример:

#r "FSharp.PowerPack.dll"
open Microsoft.FSharp.Math

let twoTimesLarger (n:'a) (m:'a) = 
  let ops = GlobalAssociations.GetNumericAssociation<'a>()
  let sel = if ops.Compare(n, m) > 0 then n else m
  ops.Multiply(sel, ops.Add(ops.One, ops.One))

Сначала нам нужно сослаться на библиотеку F # PowerPack, которая содержит функциональные возможности. Затем определим общую функцию с сигнатурой 'a -> 'a -> 'a. Первая строка динамически получает числовые операции для работы с типом 'a (по сути, она использует некоторую таблицу поиска с типом в качестве ключа). Затем вы можете использовать методы объекта числовых операций для выполнения таких операций, как умножение, добавление (Multiply, Add) и многие другие. Функция работает с любыми числами:

twoTimesLarger 3 4  
twoTimesLarger 2.3 2.4
twoTimesLarger "a" "b" // Throws an exception!

Когда вы определяете свой собственный числовой тип, вы можете определить его числовые операции и зарегистрировать их с помощью GlobalAssociations.RegisterNumericAssociation. Я считаю, что это также означает, что после регистрации операций вы сможете использовать встроенные F # Matrix<YourType> и Vector<YourType>.

Ответ 2

F # имеет ограниченную поддержку для этого. Хорошее общее решение, вероятно, включает классы типов, которые не поддерживаются CLR вообще или F # в частности.

F # имеет перегруженные арифметические операторы, используя функции "статические ограничения членов" и "встроенные" функции. Это магия, которая позволяет, например, оператор + для работы как с int, так и float s. Вы можете написать функции inline, реализации которых основаны на встроенных математических операторах и сделать некоторый прогресс, но вообще нетривиальных действий. Вы можете проверить, например. исходный код Array.sum (в файле array.fs в FSharp.Core) в исходном дистрибутиве F #, который поставляется вместе с CTP, чтобы получить представление.

См. также "статические членские ограничения" и "имитировать классы типов" этого ответа:

Функции с общими типами параметров

а также различные биты библиотеки, такие как

http://msdn.microsoft.com/en-us/library/ee370581(VS.100).aspx

http://msdn.microsoft.com/en-us/library/ee340262(VS.100).aspx

Ответ 3

Вы можете сделать что-то вроде этого.

let inline sum<'a when 'a : (static member (+) : 'a -> 'a -> 'a)> a b =
    a + b

let result = sum<int> 3 4

Однако, если я попробую let result = sum 3 4, я получу ошибку "type ambiguity inherent in the use of the operator '( + )'"

Ответ 4

Лучший механизм, который я знаю для выполнения общей арифметики, - это классы типов, которые, к сожалению, не являются С#, F # или .Net runtime в общей поддержке. Тем не менее, вы можете имитировать их самостоятельно, как указано в этом сообщении в блоге:

Тип Классы - это секретный соус

Этот метод должен работать на С# 2.0 или более поздней версии (с использованием анонимных делегатов /lambdas ).

Часто люди обращаются к интерфейсам, но сталкиваются с несколькими проблемами

  • Вы не можете объявить, что существующий тип реализует интерфейс, поэтому вы не можете определить экземпляр этого интерфейса для встроенных типов, таких как int.
  • Интерфейсы не могут ограничивать тип других аргументов методами.

Интерфейс объявляет, что для всех реализаций все методы этого интерфейса имеют одинаковый неявный тип параметра 'this'. Если Foo реализует некоторый интерфейс, то, очевидно, параметр 'this' должен иметь тип Foo для этой реализации. Но нет способа требовать, чтобы другие параметры метода также имели тип Foo.

Типовые классы позволяют вам (среди прочего) выполнять такой тип ограничений для всех параметров метода, а не только для первого параметра.

Как упоминалось в цитированной ранее статье, вы можете моделировать классы типов, передавая таблицы функций как явные аргументы.

(Сообщество wiki: опубликует пример из этой статьи, переведенной на С# здесь, но закончилось время с длинным объяснением)