Кортежи и записи
Учимся группировать данные двумя способами: кортежами по позиции и записями по именам полей.
Кортеж объединяет фиксированное число значений разных типов по позиции; запись (record) — по именованным полям.
Любая программа работает со структурами: точка имеет координаты, пользователь — имя и возраст. OCaml предлагает два инструмента. Кортежи хороши для коротких безымянных группировок, записи — для долговечных доменных структур, где имена полей важны.
Кортежи
let point = (3, 4) (* int * int *)
let person = ("Аня", 25, true) (* string * int * bool *)
Тип кортежа записывается через *: int * int. Для пар есть готовые fst и snd:
let x = fst point (* 3 *)
let y = snd point (* 4 *)
let dist (x1, y1) (x2, y2) =
let dx = float_of_int (x2 - x1) in
let dy = float_of_int (y2 - y1) in
sqrt (dx *. dx +. dy *. dy)
Аргумент (x1, y1) прямо в заголовке функции разбирается на части — это сопоставление с образцом в действии.
Записи
type person = {
name : string;
age : int;
active : bool;
}
let anya = { name = "Аня"; age = 25; active = true }
let n = anya.name (* доступ к полю через точку *)
По сравнению с кортежем запись самодокументируется — anya.age понятнее, чем snd anya, и порядок полей при создании не обязан совпадать с объявлением.
Функциональное обновление
Записи неизменяемы, но есть синтаксис «создать копию с изменённым полем» через with:
let older = { anya with age = 26 }
(* новая запись: name="Аня", age=26, active=true *)
Это не мутация: anya остаётся прежней, а older — новое значение. Вместо изменения мы порождаем обновлённую версию.
Как работает под капотом
И кортеж, и запись представлены в памяти как блок последовательных полей — по сути одинаково. Разница чисто в синтаксисе и проверке типов: к полю записи компилятор обращается по известному смещению. Поэтому записи не медленнее кортежей. Функциональное обновление { r with f = v } аллоцирует новый блок и копирует поля, кроме изменённого. Имена полей принадлежат типу: если два типа имеют поле name, компилятор по умолчанию свяжет .name с последним объявленным типом, поэтому иногда нужна аннотация.
Частые ошибки
- Менять поле записи на месте. По умолчанию поля неизменяемы; для мутации нужно
mutable. - Путать
=и:при создании записи. В типе поля описываются через:, при создании — через=. - Ждать, что
withизменит исходную запись. Он создаёт новую копию.
Итоги
- Кортеж группирует значения по позиции (тип через
*); пары разбираютfst/snd. - Запись группирует по именованным полям; доступ через точку, самодокументируется.
{ r with поле = значение }создаёт обновлённую копию, не меняя оригинал.