F# имеет универсальную арифметическую поддержку?

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

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

19
задан Guy Coder 12 April 2016 в 11:56
поделиться

4 ответа

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

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

#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 после регистрации операций.

8
ответ дан 30 November 2019 в 04:59
поделиться

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

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

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

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

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

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

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

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

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

2
ответ дан 30 November 2019 в 04:59
поделиться

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

4
ответ дан 30 November 2019 в 04:59
поделиться

Вы могли бы сделать что-то подобное.

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 , я получу ошибку «неоднозначность типа, присущая использованию оператора '(+)'»

4
ответ дан 30 November 2019 в 04:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: