2. ad-hoc полиморфизм -- это зависимые типы.
Программист работает с интерфейсами или перегрузкой функций (трейты, тайпклассы...). Функция
sum : Num a => [a] -> aведет себя по-разному для Int, Float и т.д.
К сожалению, на F# так компактно как в хаске записать подобную сигнатуру невозможно :(
Нужен when constraint с ^T, +, Zero...
Ладно, вот вам жава, для наглядности )
public int sum(List<Integer> list)
public double sum(List<Double> list)
Так вот, это по сути работа с зависимыми типами. Ограничение
Num a (Integer list, Double list) -- это не просто помощь компилятору/тайпчекеру, а дополнительный аргумент, который функция sum неявно принимает. Этот аргумент -- доказательство того, что для типа a существует реализация интерфейса Num. Тип Num a -- это тип-пропозиция, которая может быть либо доказана (и тогда мы получаем конкретную реализацию), либо нет. Таким образом, выбор реализации -- это просто применение функции к нужному "пруфу".
На практике имеем гарантии на этапе компиляции, явные контракты (сигнатура функции явно говорит о требованиях), и нужное нам для рефакторинга безопасное расширение функциональности. Не совсем завтипчики, но дух уже чувствуется )
type Money = { Amount: decimal; Currency: string }
// пруф 1: сложение только одинаковых валют
let sameCurrencyAdd a b = ...
// пруф 2: сложение с конвертацией по курсу
let convertAndAdd (exchangeRate: string -> string -> decimal) a b = ...
let money1 = { Amount = 100m; Currency = "USD" }
let money2 = { Amount = 500m; Currency = "RUB" }
sum convertAndAdd ... [money1; money2] - сконвертирует и сложит
sum sameCurrencyAdd ... [money1; money2] - ошибка компиляцииКто проходил мой курс по F#, попробуйте дописать до полноценного примера.
