Начиная с Clojure без опыта Java - как лучше организовать и запустить проекты?

Извините заранее за несколько дискурсивный характер этой совокупности связанных вопросов; Я надеюсь, что ответы станут полезным ресурсом для новичков Clojure.

Я только начал изучать Clojure, частично мотивированный этот эссе. Я не профессиональный разработчик, но у меня есть несколько десятилетий опыта программирования (ARexx, VB/VBScript/VBA, а затем Perl и ежедневное использование R, начиная с 2011 года). Моя платформа - 64-битная Windows 7. Я использую Emacs 24.3, cider 20131221 и Leiningen 2.3.3 на Java 1.7.0_45 64-разрядном сервере Java Hotspot. Я купил Clojure Программирование и Clojure Анализ данных Cookbook и погрузился в оба. Я нашел их многообещающими, но я теряюсь в деталях.

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

Clojure очень отличается и не имеет опыта работы на Java, я изо всех сил пытаюсь собрать эти штуки. Clojure В программировании есть целая глава по организации и строительству проектов, но она настолько всеобъемлющая, что, наоборот, мне трудно разоблачить информацию, имеющую отношение ко мне сейчас. Наверное, я искал что-то вроде этого ответа в Swank, но инструменты, похоже, с этого времени продвинулись. Так вот.

  • Leiningen производит среди прочего файл project.clj, который содержит определение проекта и зависимости. Думаю, я понял. Могу ли я использовать этот файл для кода, не связанного с определением, ниже defproject, или лучше оставить его нетронутым и иметь сам код в разных файлах clj?
  • Если ответ заключается в том, чтобы оставить только файл project.clj, как установить связь между этим и другими файлами? Просто ли все файлы clj в папке проекта считаются частью проекта?
  • Как определить основной файл кода, "точку входа" проекта? Скажем, у меня есть project.clj и main.clj с некоторыми вспомогательными функциями в common.clj - как определяются отношения между этими тремя файлами? Я могу вызывать функции из main.clj, но как проект знает, что основной является ядром проекта, если/когда я упаковываю проект в uberjar?
  • Если у меня есть несколько файлов clj, каков наилучший способ импорта функций? Я читал о require и useimport и refer и...), но я не совсем понимаю разницу, и эти два ключевых слова трудно найти. Примеры для REPL в Clojure книге анализа данных чаще всего выбирают use. Я нашел аналогичный вопрос, но это было немного над моей головой.
  • Это больше зависит от конкретного инструмента, но по мере того, как Emacs, по-видимому, широко используется, кажется справедливым спросить: какой хороший рабочий процесс запускать небольшие фрагменты кода, указанные (скажем), пример main.clj, приведенный выше? В настоящее время я просто открываю файл main.clj в Emacs, делаю M-x cider-jack-in, чтобы установить REPL, эксперимент в REPL, а затем, когда я хочу попробовать что-то, я выбираю весь буфер и выбираю Eval region из меню CIDER (C-c C-R). Является ли эта стандартная процедура работы или совершенно ошибочной?
  • Существует ли соглашение для определения пространств имен? Я думаю, я понимаю, что пространства имен могут охватывать несколько файлов clj и что ns используется для определения пространства имен. Должен ли я явным образом определять пространство имен (в начале) каждого файла кода? Clojure Программирование имеет некоторые рекомендации, но меня интересуют данные от других пользователей.
  • Clojure программирование говорит "Использовать символы подчеркивания в именах файлов, когда пространства имен содержат тире. Очень просто, если ваше пространство имен должно быть com.my-project.foo, исходный код для этого пространства имен должен находиться в файле, расположенном в com/my_project/foo.clj". (EDIT, как объяснено в этот полезный ответ, а также этот). Это ограничение никогда бы не произошло со мной. Существуют ли какие-либо другие ошибки в отношении имен пространств имен и переменных? R часто использует точки в именах переменных, но, я думаю, учитывая соединение с Java, в большинстве случаев следует избегать точек.

Ответ 1

  • Нет, не указывайте фактический код там, если вы не знаете, что делаете (например, сгенерируйте номер версии для defproject из локального репозитория git, как в репозиториях juxt)
  • Project.clj - это просто один большой параметр для инструмента Clojures build leiningen. См. Пример здесь https://github.com/technomancy/leiningen/blob/master/sample.project.clj. Например, вы можете указать другой исходный каталог, чем src в :source-path.
  • Значение по умолчанию - -main в project.core, но вы можете указать различные конфигурации в project.clj.
  • require является предпочтительным. :use импортирует все публики пространства имен, если вы не используете его в сочетании с :only. Требовать, чтобы вы использовали псевдоним для всего пространства имен с :as, но вы можете иметь тот же эффект от use с помощью :only, используя :refer. Обратите внимание, что в ClojureScript :use без :only даже не разрешено.
  • Это нормально. Есть и другие комбо, например. C-c C-k, чтобы перезагрузить весь файл буфера. Если вы входите слишком много форм в REPL и скорее отредактируете их в отдельном буфере https://www.refheap.com/22235.
  • Мне нравится экспериментировать, пытаясь назвать пространства имен в глаголах, а не существительные, e. г. Я предпочитаю myproject.parse, myproject.interpret, над myproject.parser, myproject.interpreter и т.д. Но это вопрос личного стиля. EDIT: Да, явное определение имен пространства имен по его имени файла и форме ns в начале исходного файла. Необычно иметь несколько исходных файлов, определяющих одно пространство имен.
  • Afaic это единственное предостережение относительно наименования пространства имен. Вы не можете это знать заранее.

Мне нравится ваш "беспокойный" подход. Вы (надеюсь) узнаете, что Clojure и особенно Leiningen почти бессмысленны в терминах этих вопросов.

Что касается использования REPL: я видел ваш комментарий в ответ @Mars, что вы хотите использовать REPL таким образом, чтобы вы могли повторно использовать то, что вы вводите. Две вещи:

  • Динамическое развитие является удивительным, позволяя вам интерактивно протестировать небольшие компоненты или функции, без необходимости запускать всю программу, написанную для этой цели.
  • Если вы обнаружите, что вы сами вводите огромные формы в REPL, которые вы намерены позже или позже перекомпоновать в функции или тесты, я рекомендую редактировать их в отдельном файле clj, который не является частью источника проекта (т.е. не в Пространство имен). Затем вы можете использовать this Emacs взломать формы eval из буфера Clojure в REPL. Идеально разделяйте Emacs в двух окнах (C-x 3) с помощью nrepl-буфера с одной стороны и вашего .clj с другой стороны. Затем используйте C-x C-. из файла clj, чтобы иметь форму в точке, вставленной в nrepl, и оцениваться. Инструкции по установке находятся по ссылке (и ваш файл .emacs обычно находится в домашнем каталоге).

Ответ 2

@Igrapenthin ответы велики. Вот еще несколько мыслей.

В пространствах имен этот учебник отлично.

Просто пояснить re # 2: Нет, не просто класть файлы .clj в любом месте проекта. Они должны находиться под src/или в любых каталогах (в виде строк) в векторе после :source-paths в project.clj, если эта запись существует. Затем удалите этот исходный путь, когда вы создаете имена имен пространства имен. Это сводило меня с ума, пока я не понял это. (Люди, которые знают лучше, пожалуйста, поправьте меня, если что-то здесь не так.)

Один № 3, вам нужен ответ Igraphenthin, но почему бы просто не начать с оценки выражений в REPL? Я работаю над проектом в течение нескольких недель, и он делает много, но моя функция -main все еще ничего не делает. Я просто запускаю те части, над которыми я работаю. Ну, вы привыкли к языкам с полнофункциональными подсказками - вы решаете.

РЕДАКТИРОВАТЬ. Независимо от того, используете ли вы функцию -main для чего-либо, вы также можете поместить ключевые слова :use или :require в оператор ns, который определяет пространство имен для того же файла. Они будут автоматически вызваны при запуске REPL с помощью lein repl, и все, что вы сделали доступными с помощью ключевых слов ns, будет доступно в REPL. Таким образом, у вас есть ваша предыдущая работа, но вы можете играть с ней по-разному в REPL. (Кроме того, если вам не нравится имя по умолчанию для автоматически загружаемого файла, вы можете переопределить его в project.clj с помощью :main. Играфентин ссылался на это.)