Я перейду от высокого уровня к вашей конкретной проблеме:
Как обычно работают Clojure (или LISP)
REPL или циклы Read-Eval-Print являются ядромкак создаются LISP:
- считыватель преобразует поток символов в структуры данных (называемые формами считывания).
- оценщик берет набор форм для чтения и оценивает их.
- Принтер выдает результаты оценщика.
Поэтому, когда вы вводите текст в REPL, он выходитчерез каждый из этих шагов обработать ваш ввод и вернуть вывод на ваш терминал.
Reader Forms
Сначала некоторые, clojure reader формы.Это будет очень кратко, я призываю вас прочитать или посмотреть ( часть 1 , часть 2 ) об этом.
A символ в clojure - это форма, которая может представлять определенное значение (например, переменную).Сами символы можно передавать как данные.Они аналогичны указателям в c, но без элементов управления памятью.
Символ с двоеточием перед ним - ключевое слово .Ключевые слова похожи на символы, за исключением того, что значение ключевого слова всегда является самим собой - подобно строкам или числам.Они идентичны символам Ruby (которые также имеют префикс двоеточий).
A quote перед формой указывает оценщику оставить структуру данных как есть:
user=> (list 1 2)
(1 2)
user=> '(1 2)
(1 2)
user=> (= (list 1 2) '(1 2))
true
Хотя кавычки могут применяться не только к спискам, но в основном они используются для списков, потому что оценщик clojure обычно выполняет списки как вызов функции.Использование '
является сокращением к макросу кавычек:
user=> (quote (1 2)) ; same as '(1 2)
(1 2)
Кавычка в основном определяет структуру данных для возврата, а не фактический код для выполнения.Таким образом, вы можете цитировать символы, которые относятся к символу.
user=> 'foo ; not defined earlier
foo
И цитирование является рекурсивным.Таким образом, все данные внутри тоже процитированы:
user=> '(foo bar)
(foo bar)
Чтобы получить поведение (foo bar)
без кавычек, вы можете оценить его:
user=> (eval '(foo bar)) ; Remember, foo and bar weren't defined yet.
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1)
user=> (def foo identity)
#'user/foo
user=> (def bar 1)
#'user/bar
user=> (eval '(foo bar))
1
Есть еще много чего,но это выходит за рамки.
Требование
Что касается операторов require, я предполагаю, что вы нашли первое в форме:
(ns my.namespace
(:require [clojure.set :as set]))
ns
является макросом , который преобразует выражение: require в последнюю описанную вами форму:
(require '[clojure.set :as set])
Наряду с некоторой работой с пространством имен.Основы описаны при запросе документов ns в REPL.
user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
Sets *ns* to the namespace named by name (unevaluated), creating it
if needed. references can be zero or more of: (:refer-clojure ...)
(:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)
with the syntax of refer-clojure/require/use/import/load/gen-class
respectively, except the arguments are unevaluated and need not be
quoted. (:gen-class ...), when supplied, defaults to :name
corresponding to the ns name, :main true, :impl-ns same as ns, and
:init-impl-ns true. All options of gen-class are
supported. The :gen-class directive is ignored when not
compiling. If :gen-class is not supplied, when compiled only an
nsname__init.class will be generated. If :refer-clojure is not used, a
default (refer 'clojure) is used. Use of ns is preferred to
individual calls to in-ns/require/use/import:
Использование REPL
В общем, не используйте ns
в REPL, а просто используйтеФункции require
и use
.Но в файлах используйте макрос ns
, чтобы сделать это.