Почему оператор мощности в F # работает только для чисел с плавающей запятой?
Я никогда не видел, чтобы на каком-либо языке был экспонентом или силовым оператором только с номерами с плавающей запятой?
Например:
2 ** 2
выдает сообщение об ошибке The type 'int' does not support any operators named 'Pow'
Есть ли веские причины для этого проектного решения?
Ответы
Ответ 1
(**)
и pown
- две разные вещи. Когда вы видите (**)
, вы можете думать о математической формуле, используя логарифмы. Когда вы видите pown
, это просто серия умножений. Я понимаю, что это может быть удивительно/запутанно сначала, потому что большинство других языков не имеют такой разницы (главным образом потому, что целые числа часто неявно преобразуются в значения с плавающей запятой). Даже в математике существует небольшая разница: см. запись в Википедии, первое определение работает только для положительных целых показателей.
Поскольку они представляют собой две разные (но связанные) вещи, у них разные подписи. Здесь (**)
:
^a -> ( ^b -> ^a) when ^a : (static member Pow : ^a * ^b -> ^a)
И вот pown
:
^a -> (int -> ^a)
when ^a : (static member get_One : -> ^a) and
^a : (static member ( * ) : ^a * ^a -> ^a) and
^a : (static member ( / ) : ^a * ^a -> ^a)
Если вы создаете свой собственный тип, вам нужно иметь только One
, (*)
и (/)
, чтобы он работал с pown
. Библиотека сделает цикл для вас (он оптимизирован, это не наивный O (n)).
Если вы хотите использовать оператор (**)
для вашего типа для нецелых значений, вам придется написать полную логику (и это не тот же алгоритм, что и в pown
).
Я думаю, что было хорошим дизайнерским решением отделить две концепции.
Ответ 2
Для интегральных степеней F # предоставляет другой оператор: pown
. Кроме того, в качестве побочного примечания, как (**)
, так и pown
перегружены, поэтому вполне возможно использовать их с другими типами, которые предоставляют соответствующие элементы (статический метод Pow
в случае (**)
; (*)
и (/)
и статическое свойство One
в случае pown
).
Я не могу сказать, почему команда F # предпочла не моделировать член Pow
на int
, но, возможно, они не чувствовали, что это было срочно, поскольку вместо этого мог использоваться оператор pown
(и поскольку вероятно, имеет смысл конвертировать в float сначала в случае больших операндов).
Ответ 3
Короткий ответ заключается в том, что он не очень полезен для целых типов, даже для int64. 2 ^ 26 дает вам ~ 1.84467441E19. Поэтому, если у вас есть два значения X и Y, которые превышают 19, тогда оператор мощности приведет к переполнению.
Я согласен, что это полезно при малых значениях, однако оно не является полезным для целых типов.
Ответ 4
Язык, на котором основан F #, - это OCaml, который не выполняет перегрузку оператора или автоматическое принуждение данных (они предпочитают явное принуждение).
Таким образом, даже добавление удвоений требует другого оператора (+.). Я не уверен, что именно здесь F # строго следит за этим, но я предполагаю, что это так.
В динамических языках, таких как Python или Scheme, вы получите автоматическое принуждение данных к большему хранилищу данных, если число было слишком большим. Например, у вас могут быть целые числа с целыми показателями, дающими большое целое для результата.
OCaml и F # обладают духом безопасности экстремального типа.