Базовые типы: int, float и раздельная арифметика
Знакомимся с примитивными типами OCaml и его фирменной особенностью — раздельной арифметикой целых и вещественных чисел.
В OCaml int и float — разные типы, и у них разные операторы:
+/*для целых,+./*.(с точкой) для вещественных.
Это первое, что удивляет новичков, и первое, за что OCaml потом благодарят. В большинстве языков + молча работает и для целых, и для дробных, неявно конвертируя одно в другое. Удобно — но именно тут прячутся коварные ошибки: целочисленное деление 5 / 2 = 2 вместо 2.5, потеря точности. OCaml отказался от неявных преобразований полностью.
Примитивные типы
| Тип | Пример | Что это |
int | 42 | целое (обычно 63-битное) |
float | 3.14 | вещественное двойной точности |
bool | true | логический |
char | 'a' | один символ |
string | "hi" | строка |
unit | () | «ничего», аналог void |
Раздельные операторы
let a = 5 + 3 (* int: 8 *)
let b = 5.0 +. 3.0 (* float: 8. *)
let c = 5.0 /. 2.0 (* float: 2.5 *)
let d = 5 / 2 (* int: 2 — целочисленное деление *)
Попытка смешать типы — это ошибка компиляции, а не молчаливое преобразование:
utop # 5 + 3.0 ;;
Error: This expression has type float but an
expression was expected of type int
Чтобы перейти между типами, нужно явно вызвать float_of_int или int_of_float (последняя усекает дробную часть).
let mix n = float_of_int n +. 0.5
(* mix : int -> float *)
unit — тип «ничего»
Тип unit имеет ровно одно значение — (). Его возвращают функции, выполняемые ради побочного эффекта. Это аналог void, но полноценный тип. Именно поэтому точка входа выглядит как let () = print_string "...": мы говорим, что выражение справа имеет тип unit.
Как работает под капотом
Внутри int хранится в машинном слове с одним битом-тегом, поэтому он 63-битный на 64-битных системах: один бит сборщик мусора использует, чтобы отличать число от указателя. Это делает арифметику int очень быстрой. float же — полноценное 64-битное число IEEE 754, которое в общем случае «упаковано» в куче. Раздельные операторы — следствие отсутствия перегрузки: поскольку + имеет ровно один тип int -> int -> int, для float понадобился отдельный оператор. Так система типов остаётся простой и предсказуемой.
Частые ошибки
- Написать
2 * 3.14. Нужно2.0 *. 3.14— и оператор, и литерал должны быть float. - Ждать
2.5от5 / 2. Это целые: результат2. - Забыть точку в литерале:
5.и5.0— float, а5— int.
Итоги
intиfloat— разные типы; смешивать без явного преобразования нельзя.- Float-операторы пишутся с точкой:
+.,-.,*.,/.. unitс единственным значением()— типизированный аналогvoid.