Облегчённый шаблон HKT
Реализуйте приём дефункционализации Kind/URI
«Облегчённый шаблон HKT» — бесплатный урок TypeScript Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения TypeScript Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс TypeScript Academy содержит 4 уроков всего.
Дефункционализация
Приём, лежащий в основе кодирования, имеет название: дефункционализация. Вместо настоящей типовой функции высшего порядка мы представляем каждую функцию тегом и разрешаем её с помощью одного поиска первого порядка. Реестр URItoKind и есть такая таблица поиска.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// One lookup replaces true type-function applicationТип Kind
Kind<F, A> — это публичное представление шаблона. Читайте его как «конструктор F, применённый к A». Он скрывает индексацию реестра за понятным именем.
type A = Kind<"Array", number>; // number[]
type B = Kind<"Option", string>; // string | nullОграничение F множеством URIS
F должен быть зарегистрированным URI. Ограничьте его с помощью extends URIS, чтобы можно было использовать только допустимые теги, а опечатки превращались в ошибки компиляции.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// Kind<"Arrey", number> -> error, not a valid URIНаписание универсальных сигнатур
Теперь мы можем записать ранее невозможную сигнатуру Functor. Замените каждое F<A> на Kind<F, A>, и компилятор примет её.
interface Functor<F extends URIS> {
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}Разрешение на практике
Когда вы фиксируете F конкретным URI, Kind разрешается в настоящий тип контейнера. У Functor<"Array"> есть map, преобразующий A[] в B[].
type ArrayFunctor = Functor<"Array">;
// map: <A, B>(fa: A[], f: (a: A) => B) => B[]Несколько аргументов типа
Некоторые конструкторы принимают два аргумента, например Either<E, A>. fp-ts расширяет этот шаблон с помощью URItoKind2 и Kind2<F, E, A> для вида * -> * -> *. Идея масштабируется добавлением новых реестров.
interface URItoKind2<E, A> {
Either: { left: E } | { right: A };
}
type Kind2<F extends URIS2, E, A> = URItoKind2<E, A>[F];Соглашение fp-ts
В fp-ts закреплено соглашение, которому следует весь этот курс: отдельная строка URI для каждого типа данных, реестр URItoKind, расширяемый слиянием объявлений, и Kind для разрешения. Распознавая это соглашение, вы сможете читать сигнатуры типов в fp-ts и Effect.
// In fp-ts you will see exactly:
// declare module "fp-ts/HKT" { interface URItoKind<A> { ... } }Запись экземпляра
«Экземпляр» абстракции — это значение, реализующее её для конкретного URI. Экземпляр содержит конкретный map. В следующем уроке мы напишем экземпляр для массива, а здесь приведём его форму.
declare const arrayFunctor: Functor<"Array">;
const out = arrayFunctor.map([1, 2, 3], n => n * 2); // number[]Почему он «лёгкий»
Его называют шаблоном лёгкого HKT, потому что он не требует изменений компилятора или специального синтаксиса — нужны только интерфейсы и доступ по индексу. В обмен на настоящее обобщение кода по контейнерам приходится добавить немного служебных конструкций: URI и реестры.
type Kind<F extends URIS, A> = URItoKind<A>[F];
// No magic, just a typed lookup tableОграничения
Шаблон многословен, а сообщения об ошибках могут быть трудными для понимания, поскольку в них упоминается кодирование, а не предметная область. Кроме того, каждый контейнер необходимо зарегистрировать. В большинстве приложений вы используете библиотеки, где это уже сделано, вместо того чтобы создавать всё самостоятельно.
// Trade-off: real abstraction power vs. encoding ceremonyСобираем всё вместе
Полный рецепт лёгкого HKT: определить URI, зарегистрировать его в URItoKind, определить абстракции с помощью Kind<F, A> и предоставить экземпляры для каждого URI. Это весь набор инструментов, лежащий в основе универсальных функциональных библиотек для TypeScript.
type Kind<F extends URIS, A> = URItoKind<A>[F];
interface Functor<F extends URIS> {
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}Быстрая проверка
Проверьте, насколько хорошо вы понимаете шаблон лёгкого HKT.
Повторение
Вы собрали шаблон лёгкого HKT.
- Дефункционализация заменяет применение типовой функции поиском.
Kind<F, A>разрешает URI и аргумент в конкретный тип.- В универсальных сигнатурах используется
KindвместоF<A>. - Шаблон поддерживает два аргумента через
Kind2и соответствует соглашению fp-ts.
Далее: универсальный map с настоящими экземплярами.
Изучай TypeScript с ИИ-репетитором — бесплатно
Пиши и запускай код прямо в браузере, получай мгновенную помощь от ИИ-репетитора 24/7 и продолжи учиться на сайте или в приложении.
- Курсы
- 101
- Уроки
- 352
Часто задаваемые вопросы
Урок «Облегчённый шаблон HKT» бесплатный?
Да — полный текст урока «Облегчённый шаблон HKT» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс TypeScript Academy, подпишись на CoddyKit PRO. Курс TypeScript Academy содержит 4 уроков всего.
Чему я научусь в уроке «Облегчённый шаблон HKT»?
Реализуйте приём дефункционализации Kind/URI Ты практикуешь TypeScript Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать TypeScript Academy?
Предыдущий опыт не требуется. TypeScript Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Облегчённый шаблон HKT»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке TypeScript Academy?
Да. Каждый урок TypeScript Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Проблема HKT в TypeScript
- Определение конструкторов типов
- Облегчённый шаблон HKT
- Обобщённые функторы и мапперы