Вывод типов: статика без аннотаций
F# статически типизирован, но типы почти всегда выводятся сами — компилятор работает за вас.
Вывод типов — это способность компилятора определить типы значений и функций по их использованию, без явных аннотаций со стороны программиста.
Типобезопасность без многословности
В C# или Java тип часто пишут руками (int x = 5;). F# наследует от ML мощный вывод типов (алгоритм Хиндли–Милнера): компилятор сам выясняет типы, оставляя код кратким, но при этом полностью статически типизированным.
let add a b = a + b // выведен тип: int -> int -> int
let result = add 2 3
printfn "%d" resultВывод:
5
Мы нигде не написали int, но компилятор понял: раз a + b используется с целыми при вызове, значит add работает с int. Передадим строку — будет ошибка на этапе компиляции, а не в рантайме.
Вывод идёт по всей программе
Вывод типов в F# учитывает использование значения дальше по коду, а не только строку объявления. Это отличает его от «локального» вывода var в C#.
let describe x =
if x > 10 then "много" else "мало"
// x выведен как int (из-за x > 10), результат — stringКогда тип указывают явно
Иногда вывода недостаточно или мы хотим документировать намерение. Тогда добавляют аннотацию.
let toUpper (s: string) = s.ToUpper()
// без аннотации компилятор не знал бы, что s — строка с методом ToUpperАннотация нужна, когда тип нельзя вывести из контекста — например, при вызове перегруженного метода .NET или метода объекта.
Обобщённость по умолчанию
Если тип не привязан к конкретному, F# делает функцию обобщённой (generic) автоматически.
let identity x = x
// тип: 'a -> 'a — работает для любого типаЗапись 'a — это типовая переменная (как T в C#). Здесь обобщённость возникла сама, без слова generic.
Как работает под капотом
Компилятор строит систему уравнений на типы: каждое использование значения добавляет ограничение, затем уравнения решаются унификацией. Если решение единственное — тип выведен; если значение используется одинаково обобщённо — выводится типовая переменная 'a; если ограничения противоречивы — ошибка типов. Всё это происходит до запуска, поэтому рантайм-проверок типов нет.
Частые ошибки
- Думать, что отсутствие аннотаций = динамическая типизация. Это статика, просто типы выводятся.
- Удивляться ошибке «не удалось вывести тип» при вызове метода .NET-объекта — добавьте аннотацию аргумента.
- Ожидать вывод как в C# (по одной строке) — в F# вывод смотрит на всё использование.
Итоги
- F# статически типизирован, но типы почти всегда выводятся автоматически (Хиндли–Милнер).
- Ошибки типов ловятся на компиляции, не в рантайме.
- Аннотация
(x: тип)нужна, когда контекста для вывода мало. - Невязанные типы становятся обобщёнными (
'a) автоматически.