Основы комбинаторов анализаторов
Составляйте крупные анализаторы из небольших
«Основы комбинаторов анализаторов» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.
Что такое анализатор
Анализатор читает входные данные (обычно строку) и создаёт структурированный результат либо завершается неудачей. Мы начнём с уровня значений, чтобы сформировать интуитивное понимание, а затем перенесём те же идеи в систему типов.
type Parser<T> = (input: string) => { value: T; rest: string } | null;
// Consumes part of the input, returns a value and the leftoverНебольшой анализатор
Самый простой анализатор сопоставляет буквальный префикс. Если входные данные начинаются с ожидаемого текста, он успешно завершается и возвращает оставшуюся строку; в противном случае возвращает null.
function literal(prefix: string): Parser<string> {
return input =>
input.startsWith(prefix)
? { value: prefix, rest: input.slice(prefix.length) }
: null;
}
console.log(literal("ab")("abc"));Комбинаторы
Комбинатор принимает небольшие анализаторы и создаёт из них более крупные. Именно поэтому такой подход называется комбинаторами анализаторов: сложные анализаторы собираются из простых повторно используемых частей.
// Small parsers: digit, letter, literal
// Combinators: sequence, choice, many
// Compose them into: number, identifier, expressionПоследовательное выполнение
Комбинатор последовательности запускает один анализатор, затем другой для оставшихся данных и объединяет их результаты. Оба анализатора должны завершиться успешно, чтобы последовательность считалась успешной.
function seq<A, B>(pa: Parser<A>, pb: Parser<B>): Parser<[A, B]> {
return input => {
const ra = pa(input);
if (!ra) return null;
const rb = pb(ra.rest);
if (!rb) return null;
return { value: [ra.value, rb.value], rest: rb.rest };
};
}Использование последовательности
Объедините два литерала, чтобы разобрать их по порядку. Результат содержит оба сопоставленных фрагмента и оставшийся ввод.
const ab = seq(literal("a"), literal("b"));
const r = ab("abc");
console.log(r); // { value: ["a","b"], rest: "c" }Выбор
Комбинатор выбора сначала применяет первый анализатор, а при его сбое — второй. Так выражаются альтернативы, например «digit или буква».
function alt<T>(p1: Parser<T>, p2: Parser<T>): Parser<T> {
return input => p1(input) ?? p2(input);
}Повторение
Комбинатор many многократно применяет анализатор, пока тот не завершится с ошибкой, и собирает все результаты. С его помощью разбираются списки, последовательности digits или пробелы.
function many<T>(p: Parser<T>): Parser<T[]> {
return input => {
const out: T[] = [];
let rest = input;
let r = p(rest);
while (r) { out.push(r.value); rest = r.rest; r = p(rest); }
return { value: out, rest };
};
}Отображение результатов
Комбинатор map преобразует результат анализатора, не изменяя потребляемый им ввод, например превращая сопоставленные символы digit в число.
function map<A, B>(p: Parser<A>, f: (a: A) => B): Parser<B> {
return input => {
const r = p(input);
return r ? { value: f(r.value), rest: r.rest } : null;
};
}Построение
С помощью этих нескольких комбинаторов (литерал, последовательность, выбор, повторение и отображение) можно разбирать настоящие грамматики: числа, идентификаторы и даже небольшие языки выражений. Каждый уровень объединяет расположенный под ним.
const digit = alt(literal("0"), literal("1")); // toy digit
const digits = many(digit);
console.log(digits("0110x"));От значений к типам
Ключевая идея заключается в том, что та же композиционная структура работает и на уровне типов. Там «вводом» является строковый тип-литерал, а анализаторы представляют собой условные типы, использующие вывод по шаблону. Далее мы перейдём к этому уровню.
// Value level: (input: string) => { value, rest } | null
// Type level: conditional types over string literal typesЗачем нужен разбор на уровне типов
Анализаторы на уровне типов позволяют компилятору понимать структуру строковых литералов: пути маршрутов, строки форматов и ключи запросов. Сформированное здесь представление о комбинаторах напрямую связано с приёмами на уровне типов, которые используются в остальной части курса.
// Goal: parse "users/:id" into { id: string } at compile timeБыстрая проверка
Проверьте, насколько хорошо Вы понимаете комбинаторы анализаторов.
Итоги
Вы сформировали представление об анализаторах на уровне значений.
- Анализатор потребляет ввод и возвращает значение вместе с остатком либо завершается с ошибкой.
- Комбинаторы (последовательность, выбор, повторение и отображение) объединяют небольшие анализаторы в более крупные.
- Та же структура применяется и на уровне типов.
Далее: разбиение строк в системе типов.
Часто задаваемые вопросы
Урок «Основы комбинаторов анализаторов» бесплатный?
Да — полный текст урока «Основы комбинаторов анализаторов» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.
Чему я научусь в уроке «Основы комбинаторов анализаторов»?
Составляйте крупные анализаторы из небольших Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.
Сколько времени занимает урок «Основы комбинаторов анализаторов»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы комбинаторов анализаторов
- Разделение строк на уровне типов
- Разбор с помощью шаблонных литералов
- Мини-анализатор маршрутов на уровне типов