Разделение пространства имен Clojure на несколько файлов

Можно ли разделить пространство имен Clojure на несколько исходных файлов при выполнении компиляции со временем :gen-class? Как вступают в игру (:main true) и (defn- ...)?

Ответ 1

Обзор

Конечно, вы можете, фактически, пространство имен clojure.core разбито таким образом и предоставляет хорошую модель, за которой вы можете следовать, глядя в src/clj/clojure:

core.clj
core_deftype.clj
core_print.clj
core_proxy.clj
..etc..

Все эти файлы участвуют в создании единого пространства имен clojure.core.

Основной файл

Один из них - это первичный файл, названный так, чтобы соответствовать имени пространства имен, чтобы он был найден, когда кто-то упоминает его в :use или :require. В этом случае основной файл clojure/core.clj, и он начинается с формы ns. Здесь вы должны поместить всю свою конфигурацию пространства имен, независимо от того, какой из ваших других файлов может понадобиться. Обычно это также :gen-class, поэтому что-то вроде:

(ns my.lib.of.excellence
  (:use [clojure.java.io :as io :only [reader]])
  (:gen-class :main true))

Затем в соответствующих местах вашего основного файла (чаще всего все в конце) используйте load для ввода ваших вспомогательных файлов. В clojure.core это выглядит так:

(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")

Обратите внимание, что вам не нужен текущий каталог в качестве префикса, и вам не нужен суффикс .clj.

Файлы-помощники

Каждый из вспомогательных файлов должен начинаться с объявления того пространства имён, которое им нужно, но должен делать это с помощью функции in-ns. Итак, для примера пространства имен выше, хелпер файлы будут начинаться с:

(in-ns 'my.lib.of.excellence)

Это все, что требуется.

генераторного класса

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

(defn -main [& args]
  ...)

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

Частные войны

Вы также спросили о форме (defn- foo ...), которая определяет частную функцию namespace-private. Функции, определенные таким образом, а также другие :private vars видны из пространства имен, где они определены, поэтому основной и все вспомогательные файлы будут иметь доступ к приватным vars, определенным в любом из файлов, загруженных до сих пор.