Тип добавления (+) в F #
Я только что узнал, что OCAML должен иметь постфикс .
для выполнения арифметики float. Примером может быть 3. +. 4.
, равным 7.
(float). Тем не менее, F # обрабатывает арифметику float и integer одинаково, поэтому работают как 3 + 4
(int), так и 3. + 4.
(float).
F # имеют +
, естественно присваиваемые int, поэтому let add a b = a + b
имеет тип int -> int -> int
. И действительно (+)
дает мне val it : (int -> int -> int) = <fun:[email protected]>
.
Это приводит к следующей последовательности, которая, по моему мнению, довольно counter- интуитивно понятна:
> 3. + 4.;;
val it : float = 7.0
> (+);;
val it : (int -> int -> int) = <fun:[email protected]>
Итак, мой вопрос: является ли "перегрузка" выполняемым специальным механизмом/случаем в компиляторе, или это просто language-, поэтому я потенциально могу определить функцию с именем add
(или что-то еще), которые имеют одно определение для целых чисел и одно для float (или любого другого типа.)
Ответы
Ответ 1
Вкратце, F # имеет механизм перегрузки ad- hoc- через ключевое слово inline
и "статические ограничения элементов". Существует еще одна магия, специфичная для built- в математических операторах, которая волшебным образом предполагает тип int
отсутствие других ограничений. (+)
- это всего лишь самая особенная/магическая вещь во всех F #, поэтому она не делает ничего хорошего для введения в систему языка/типа.
В общем, "перегрузка" сложна для statically- типизированных, type- языков. Варианты F # здесь очень прагматичны. OCaml делает другую, простую, прагматичную вещь (без перегрузки). Haskell выполняет другую, complex- but- элегантную вещь (типы классов). Они все несколько разумные точки в пространстве дизайна языка/библиотеки.
Ответ 2
Перегруженные функции (и операторы) должны быть отмечены inline
в F #. Это связано с тем, что они зависят от явных ограничений элементов. Эти ограничения разрешаются во время компиляции. Функция let inline add a b = a + b
имеет тип 'a -> 'b -> 'c (requires member (+))
, где +
- статическая функция/оператор. Вы не можете сделать это на С#; он не имеет ограничений статического члена.
let inline add a b = a + b
add 1 2 //works
add 1.0 2.0 //also works
Ответ 3
В дополнение к ответу и ссылке Брайана:
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs
Я нашел некоторые определения в коде:
let inline (+) (x:int) (y:int) = (# "add" x y : int #)
и
let inline (+) (x: ^T) (y: ^U) : ^V =
AdditionDynamic<(^T),(^U),(^V)> x y
when ^T : int32 and ^U : int32 = (# "add" x y : int32 #)
when ^T : float and ^U : float = (# "add" x y : float #)
when ^T : float32 and ^U : float32 = (# "add" x y : float32 #)
...
И AdditionDynamic
определяется здесь (нагрузки статического материала и CIL):
https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/prim-types.fs#L2374
Забавные вещи:
(# "add" 1 2 : int32 #)
работает и дает 3 в качестве вывода (с предупреждением, что вы не должны этого делать.)