Тип сложения (+) в F # - PullRequest
13 голосов
/ 09 июня 2011

Я только что узнал, что у OCAML должен быть постфикс . для выполнения арифметики с плавающей точкой.Примером будет 3. +. 4., что равно 7. (float).Тем не менее, F # обрабатывает float и целочисленную арифметику одинаково, так что и 3 + 4 (int) и 3. + 4. (float) работают.

F # имеют +, естественно назначенные для int, поэтому let add a b = a + b - этотипа int -> int -> int.И действительно, (+) дает мне val it : (int -> int -> int) = <fun:it@6-1>.

Это приводит к следующей последовательности, которую я считаю довольно нелогичной:

> 3. + 4.;;
val it : float = 7.0
> (+);;
val it : (int -> int -> int) = <fun:it@8-2>

Итак, мой вопрос: «Перегрузка» выполняется специальным механизмом / регистром в компиляторе или это общеязыковая вещь, поэтому я потенциально могу определить функцию с именем add (или что-нибудь еще), которая имеет одно определение для целых чисел и одно дляплавает (или любой другой тип.)

Ответы [ 3 ]

12 голосов
/ 09 июня 2011

Вкратце, F # имеет специальный механизм перегрузки через ключевое слово inline и «статические ограничения членов». Существует еще одна магия, специфичная для встроенных математических операторов, которая магически предполагает тип int отсутствия других ограничений. (+) - это почти самая особенная / волшебная вещь во всех F #, поэтому она не является хорошим введением в систему языка / типа.

В общем, «перегрузка» затруднена для статически типизированных языков с выводом типа. Выбор F # здесь очень прагматичен. OCaml делает разные, простые, прагматичные вещи (без перегрузки). Haskell делает разные, сложные, но элегантные вещи (классы типов). Все они несколько разумны в области дизайна языка / библиотеки.

6 голосов
/ 09 июня 2011

Перегруженные функции (и операторы) должны быть отмечены inline в F #. Это потому, что они зависят от явных ограничений членов . Эти ограничения разрешаются во время компиляции. Функция let inline add a b = a + b имеет тип 'a -> 'b -> 'c (requires member (+)), где + - статическая функция / оператор. Вы не можете сделать это в C #; он не имеет статических ограничений членов.

let inline add a b = a + b
add 1 2 //works
add 1.0 2.0 //also works
3 голосов
/ 09 июня 2011

В дополнение к ответу Брайана и ссылке:

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 в качестве вывода (с предупреждением о том, что вы не должны этого делать).

...