Зачем мы транспилируем Haskell в JavaScript
23 Mar 2021

Соавтор: Денис Редозубов

Оригинал: https://habr.com/ru/company/typeable/blog/548574/

Сегодня мы расскажем, почему мы пишем фронтенд на Haskell и компилируем его в JavaScript. Вообще говоря, подобный процесс называется транспиляцией:

Транспиляция – это процесс преобразования программы на языке X в эквивалентную программу на языке Y. В отличие от компиляции, языки X и Y находятся примерно на одном и том же уровне абстракции.

Зачем нужна транспиляция?

В общем случае можно выделить две основные цели транспиляции:

  1. Миграция между разными версиями одного языка. Языки программирования не стоят на месте, активно развиваются и обрастают новыми удобными фичами с каждой новой версией, которые хочется использовать. К сожалению, везде и сразу новые средства языка могут не поддерживаться, поэтому возникает вопрос об обратной совместимости версий. В данном случае такой межверсионный транспилятор производит что-то вроде “рассахаривания” (deshugaring) конструкций в более старые и обычно менее выразительные версии. Примером может служить Babel, переводящий код на JS в его подмножество, поддерживаемое браузерами. Возможно и преобразование в другую сторону, когда необходимо перевести проект на более новую версию языка, а делать вручную это долго и лень. Например, для транспиляции кода на Python 2.x в код на Python 3 есть 2to3.
  2. Перевод с одного ЯП на другой, исходя из требований рантайм системы и/или пожеланий разработчиков. Например, для исполнения в браузере требуется код на JS (чаще всего применяется на данный момент) или WASM (пока что менее распространён), а для разработки ставятся требования, которым лучше соответствует другой язык. Этот исходный язык может поддерживать уникальные механизмы, такие как автоматическое распараллеливание, или же вообще относиться к другой парадигме. Код, генерируемый транспайлерами, может быть как максимально похож на исходный (это упрощает отладку), так и стать неузнаваемым по сравнению с кодом на исходном языке. Существуют утилиты, позволяющие сопоставить результат транспиляции с оригинальным кодом (например, SourceMap для JS).

Приведём несколько примеров:

Почему бы не вести разработку на чистом JS?

Как можно увидеть из приведённых выше примеров, разговор о транспиляции в целом неизбежно затрагивает трансляцию в JS. Давайте разберём более подробно, какие цели это преследует и какие может дать преимущества:

Наш опыт транспиляции в JS

При выборе инструментов для фронтенд-разработки мы принимали во внимание следующие факторы:

На данный момент мы в Typeable ведём фронтенд-разработку на Haskell и используем веб-фреймворк Reflex и функциональное реактивное программирование (FRP). Исходный код на Haskell транспилируется в код на JavaScript с помощью GHCJS.

TypeScript и прочие расширения JS нам не подошли из-за недостаточно строгой типизации, не такой развитой системы типов, как в Haskell, да и в целом эти языки слишком радикально отличаются от привычных для нашей команды.

Reflex мы предпочли таким вариантам как Elm и PureScript в первую очередь из-за желания использовать тот же стек разработки, что и для бэкенда. Кроме того, Reflex позволяет не следовать определённой архитектуре приложений и в какой-то степени является более гибким и “низкоуровневым”. Подробнее про сравнение Elm и Reflex можно прочитать в нашем посте на эту тему.

Выводы

Нам удалось получить те преимущества транспиляции в JS, о которых мы рассказали выше:

Разумеется, есть и определённые трудности:


back · about · posts · main