Рекомендации по созданию и развертыванию приложений Clojure: хорошие учебные пособия?

Я новичок в Clojure, и я начинаю экспериментировать с созданием приложения.

До сих пор все, что я видел о учебниках по компиляции программ Clojure, подразумевает интерактивность. Например, "загрузите REPL и введите (load-file" this-or ") для запуска. Это нормально, но этого недостаточно.

Я так привык к идиомам редактирования компиляции таких языков, как C или Delphi, что я инстинктивно вынужден редактировать, а затем нажимаю "M-x compile".

Проблема заключается в том, что "lein uberjar", который, как я понимаю, эквивалентен "make", мучительно медленно исполняется даже для мира привет. Поэтому мне нужно выяснить, как работает этот "интерактивный проект", перестать использовать uberjar, как это сделать быстро, и сохранить его только в конце дня.

Еще одна вещь, которую я заметил при построении (используя lein uberjar), - это то, что небольшое приложение GUI, над которым я работаю, создает всплывающие кадры в процессе компиляции, как если бы они выполнялись во время компиляции. Мне кажется, это немного противоречит мне; это не совсем так же похоже на "сделать", как я думал.

Я знаю, что способ разработки вещей интерактивно работает в REPL, и я не пытаюсь это изменить: я бы хотел адаптироваться к этому образу жизни. К сожалению, я мало видел в форме документации о том, как это сделать. Например, как reset текущее состояние машины. Просто кажется, что бесполезно просто компилировать отдельные фрагменты на лету, не имея возможности сделать что-то вроде reset.

Большинство обучающих программ, которые я видел на Clojure (и Lisp), как правило, сосредоточены на взломе в REPL. Рекомендации по развертыванию приложений остаются для меня загадкой. Мои пользователи просто будут пользователями; они не собираются быть разработчиками, которые собираются загружать файлы в REPL.

Итак, вот мой вопрос: какие-либо ресурсы для хорошей информации или учебники по всему процессу построения приложения Clojure, включая развертывание?

(Примечание. У меня есть все необходимые установки и работа (например, Emacs, Slime, Leiningen и т.д.), так что это не вопрос об этом).

Ответ 1

Несколько быстрых подсказок, затем некоторые ссылки:

Не используйте lein uberjar во время разработки; предпочитают lein jar. Разница в том, что lein uberjar помещает все ваши зависимости в сгенерированный jar (включая Clojure), так что ваша единственная банка - это полностью автономный пакет с вашим приложением внутри; lein jar использует только собственный код. Подход uberjar имеет очевидные преимущества для развертывания, но для разработки вы должны просто использовать соответствующий путь к классам при запуске приложения, экономя время, необходимое для подготовки uberjar. Если вы не хотите управлять классом классов для тестовых прогонов, посмотрите lein run плагин.

Кроме того, скорее всего, большая часть вашего кода не должна быть фактически скомпилирована. AOT необходим в некоторых сценариях взаимодействия Java, но большую часть времени он привносит небольшой импульс в скорость запуска и раздражает проблемы с двоичной совместимостью с различными версиями Clojure. Я полагаю, что последняя проблема не относится к проекту типа uberjar -ed для автономного приложения, но любой код библиотеки, по крайней мере, должен быть оставлен JIT-ed, если это вообще возможно. С Leiningen вы можете поместить предложение :namespaces в форму defproject в project.clj, чтобы определить, какие пространства имен должны быть скомпилированы; независимо от того, что вы оставите, по умолчанию будет JIT-ed. Старые версии Leiningen использовали для компиляции всего по умолчанию, что на самом деле является хорошей причиной для обновления!

Что касается окон, всплывающих во время компиляции, я бы предположил, что вы либо запускаете код выхода из окна во время макроразложения, либо вне определения какой-либо функции или аналогичной конструкции. (Что-то вроде (println "Foo!") на верхнем уровне.) Что-то, чего вы не должны делать, я полагаю - если вы не планируете запускать свой код как script, так или иначе. Чтобы избежать проблемы, оберните побочный код в определениях функций и укажите точку входа в приложение, используя предложение :main в project.clj. (Если вы скажете :main foo, то функция -main из пространства имен foo будет использоваться в качестве точки входа в ваше приложение. По умолчанию, во всяком случае, и, по крайней мере, вышеупомянутое lein run похоже, имеет имя hardcoded - не уверен относительно самого lein.)

Как для сброса состояния REPL - вы можете просто перезапустить его. С SLIME M-x slime-restart-lower- lisp будет делать это только при сохранении всех остальных состояний сеанса Emacs.

См. также эти обсуждения в группе Clojure Google:

Ответ 2

Нет, вы не вводите функции в REPL.

Вы редактируете исходные файлы, как обычно. Преимущество Lisp заключается в том, что у вас одновременно работает система в фоновом режиме, поэтому вы можете скомпилировать отдельные функции из исходного файла и поместить их в запущенную систему или даже заменить их там.

Если вы используете Slime, вы нажимаете C-c C-c в исходном файле для компиляции и загрузки функции в точке. Затем вы можете переключиться на REPL для тестирования и изучения, но все, что вы хотите сохранить в качестве источника, вы помещаете в свои исходные файлы.

Учебные пособия обычно начинаются с ввода данных в REPL, потому что для этого вам не нужно настраивать, но серьезная разработка объединяет текущую систему и управление исходным файлом.


Просто, чтобы проиллюстрировать, мой обычный рабочий процесс (я использую Common Lisp, но Clojure аналогичен) выглядит следующим образом:

  • Запустить Emacs
  • M-x slime, чтобы запустить Slime, систему Lisp и подключить два через Swank
  • , (команда) load-system foo для загрузки текущего проекта (компиляция только при необходимости) в изображение
  • C-x b перейти в буфер источника
  • C-c ~ сделать исходный каталог текущим каталогом и исходным пакетом текущего пакета REPL

Теперь я настроен на работу моей системы в фоновом режиме. Затем работает:

  • изменить или добавить функцию или определение класса
  • C-c C-c для компиляции и загрузки в изображение
  • переключиться на REPL, проверить
  • отладки

Нет значительных пауз для компиляции, потому что я никогда не компилирую все это сразу, а только отдельные определения.