← На главную

Bellroy ускорил сборку на 10% с RequiredTypeArguments из GHC 9.10

26.06.2026 15:30 · hackernews

Разработчики из Bellroy нашли способ ускорить компиляцию одного из своих внутренних пакетов на 10%. Они заменили тысячи вызовов TemplateHaskell одним type-level трюком и получили проверяемый на этапе типов конструктор непустых строк NonEmptyText.

Раньше код выглядел так: $$(NonEmptyText.makeTH "hello"). Если передать пустую строку, ошибка вылезала только во время выполнения сплайса. Новая версия — просто NonEmptyText.make "hello". А если написать "", GHC выдаст ошибку типа прямо при компиляции с сообщением "Expected a non-empty string".

Всё работает благодаря расширению GHC 9.10 — RequiredTypeArguments. Оно позволяет передать строковый литерал на уровне типов прямо как аргумент функции. Дальше в игру вступает класс IsNonEmptySymbol с overlapping инстансами: для пустой строки — кастомная ошибка через Unsatisfiable, для любой другой — успех. Надо только не забыть включить UndecidableInstances.

Этот подход срезал около 10% времени сборки пакета bellroy-data, в котором хранятся данные про перевозчиков, налоги, товары и т.д. И таких TH-сплайсов там были тысячи.

Тот же приём можно переиспользовать для проверки, что Natural положительный, или вообще для любого типа, для которого можно придумать type-level предикат. Например, так сделали конструктор валидных имён таблиц DynamoDBTableName. Имя должно соответствовать regex /^[a-zA-Z_.-]{3,255}$/. Вся проверка — на уровне типов: длина от 3 до 255, каждый символ проходит через IsValidTableChar. Если имя не подходит, GHC ругается кастомной ошибкой.

Правда, есть нюанс: GHC по умолчанию ограничивает 20 шагов редукции type family, так что длинные строки так просто не распарсить. И выражать сложные алгоритмы в терминах type family всё ещё неудобно — нет нормальных let и case. Но общий тренд к Dependent Haskell делает такие трюки всё более доступными с каждым релизом GHC.

Читать оригинал →