F# имеет ту же проблему как C#, где Вы не можете непосредственно использовать арифметические операторы с универсальными типами T?
Можно ли записать универсальную функцию Суммы, которая возвратила бы сумму какого-либо значения, которое поддерживает арифметическое дополнение?
Как упоминал Брайан, существует некоторая встроенная поддержка общих арифметических функций, и вы можете использовать "статические ограничения", которые позволяют вам определять некоторые общие функции самостоятельно (хотя это немного ограничено).
В дополнение к этому, вы также можете использовать динамические "числовые ассоциации", что немного медленнее при использовании в функции, но может быть приятно использовано, например, для определения вашего собственного типа вектора или матрицы. Вот пример:
#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
(по сути, она использует в качестве ключа некоторую таблицу поиска с типом). Затем вы можете использовать методы объекта числовых операций для выполнения таких вещей, как умножение, сложение (Умножение
, Add
) и многих других. Функция работает с любыми числами:
twoTimesLarger 3 4
twoTimesLarger 2.3 2.4
twoTimesLarger "a" "b" // Throws an exception!
Когда вы определяете свой собственный числовой тип, вы можете определить его числовые операции и зарегистрировать их, используя GlobalAssociations.RegisterNumericAssociation
. Я полагаю, что это также означает, что Вы сможете использовать встроенный F# Matrix
и Vector
после регистрации операций.
Лучший механизм, который я знаю для выполнения общей арифметики, - это классы типов, которые, к сожалению, ни C #, F #, ни среда выполнения .Net в целом не поддерживают. Однако вы можете смоделировать их самостоятельно, как упоминалось в этом сообщении в блоге:
Этот метод должен работать в C # 2.0 или более поздних версиях (с использованием анонимных делегатов / лямбда-выражений).
Часто люди обращаются к интерфейсам, но сталкиваются с парой проблем
Интерфейс объявляет, что для всех реализаций все методы в этом интерфейсе принимают один и тот же неявный тип параметра this. Если Foo реализует какой-то интерфейс, тогда, очевидно, параметр this должен иметь тип Foo для этой реализации. Но нет способа потребовать, чтобы другие параметры метода также имели тип Foo.
Классы типов позволяют (среди прочего) устанавливать такого рода ограничения на все параметры метода, а не только на первый параметр.
Как упоминалось в цитированной ранее статье, вы можете моделировать классы типов, передавая таблицы функций в качестве явных аргументов.
(Вики сообщества: разместил здесь пример из этой статьи, переведенный на C #, но не хватило времени с пространными объяснениями)
F # имеет ограниченную поддержку для этого. Хорошее общее решение, вероятно, включает классы типов, которые не поддерживаются CLR в целом или F # в частности.
В F # есть перегруженные арифметические операторы, использующие «статические ограничения членов» и «встроенные» функции. Это магия, которая позволяет, например, оператор +
для работы как с int
s, так и с float
s. Вы можете написать встроенные
функции, реализация которых основана на встроенных математических операторах, и добиться некоторого прогресса, но в целом это нетривиально. Вы можете проверить, например, исходный код 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
Вы могли бы сделать что-то подобное.
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
, я получу ошибку «неоднозначность типа, присущая использованию оператора '(+)'»