Почему REPL рассматривает clojure.core/doc как var?

Я пытаюсь получить документацию с помощью функции Clojure doc, но не могу распознать ее в REPL (я использую Emacs и SLIME). Следующая последовательность описывает, что происходит (сообщение об ошибке следует сразу после каждой строки):

gaidica.core> (doc first)
; Evaluation aborted.

Unable to resolve symbol: doc in this context
  [Thrown class java.lang.Exception]

gaidica.core> (clojure.core/doc first)
; Evaluation aborted.

No such var: clojure.core/doc
  [Thrown class java.lang.Exception]

user> (clojure.core/doc first)
; Evaluation aborted.

No such var: clojure.core/doc
  [Thrown class java.lang.Exception]

user> (doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil
user> 

Как обратиться к функции doc и распознать ее как функцию, а не как переменную?


ДОБАВЛЕНИЕ, 22.06.11, через 9 часов после публикации вопроса

@kotarak сделал наиболее подходящий комментарий: «Обратите внимание, что clojure.core/doc — это 1.2 и более ранние версии. clojure.repl/doc — это 1.3 и более поздние версии». Конечно же, сработало следующее:

user> (clojure.repl/doc first)
-------------------------
clojure.core/first
([coll])
  Returns the first item in the collection. Calls seq on its
    argument. If coll is nil, returns nil.
nil
user>

Я смог подтвердить, что Clojure 1.3 был активен:

user> *clojure-version*
{:interim true, :major 1, :minor 3, :incremental 0, :qualifier "master"}
user> 

Но это тоже сбивало с толку — в моем проекте Leiningen project.clj был указан Clojure 1.2!

По своему собственному опыту я однажды заметил, что REPL на основе SLIME «зависает» от значения пути к классам Java даже после того, как я изменил содержимое соответствующих каталогов. Тогда решение состояло в том, чтобы выйти из Emacs и lein swank, затем снова войти в оба и повторить попытку. Я попробовал то же самое и получил следующий результат:

user> *clojure-version*
{:major 1, :minor 2, :incremental 0, :qualifier ""}
user> 

Единственный вывод, который я могу сделать, это то, что мой предыдущий REPL использовал Clojure 1.3. В проекте, над которым я работал до этого, использовался моментальный снимок Clojure 1.3, поэтому я предполагаю, что REPL каким-то образом «повис» на Clojure 1.3.

Проблема решена, урок усвоен и т. д. В качестве бонусных баллов кто-нибудь может объяснить причину того, что произошло (с Clojure 1.2 по сравнению с 1.3)?

Спасибо всем, кто внес свой вклад.


person Gregg Williams    schedule 22.06.2011    source источник
comment
Я заметил, что вы не приняли ни одного ответа ни на один из ваших вопросов. Вам определенно следует принять некоторые ответы, если вы считаете, что их достаточно. Вот как работают веб-сайты stackoverflow.   -  person bmillare    schedule 23.06.2011
comment
@kotarak и @bmillare: Пожалуйста, прочитайте мой вопрос и два ответа. Я думаю, вы согласитесь, что, хотя оба ответа пытаются быть полезными, ни один из них не отвечает на мой вопрос. Поэтому я тоже не принял.   -  person Gregg Williams    schedule 24.06.2011
comment
@gregg-williams, что, безусловно, верно и для всех других ваших вопросов, где вы не предоставили никаких отзывов о том, помогли ли предложенные решения или нет.   -  person kotarak    schedule 24.06.2011
comment
@gregg Я обновил свой ответ. Я был более явным и предположил меньше. Пожалуйста, дайте обратную связь, если это все еще неясно.   -  person bmillare    schedule 24.06.2011
comment
@kotarak, я неправильно прочитал ваш оригинальный комментарий. Спасибо, что указали, что я не выбрал ответы на два предыдущих вопроса. С тех пор я так и сделал, и я ценю, что вы указали, что было не так; Я действительно хочу быть хорошим гражданином. Спасибо.   -  person Gregg Williams    schedule 24.06.2011


Ответы (2)


Пара поправок. Во-первых, doc — это макрос, а не функция. Также функции и макросы могут храниться в var. Во-вторых, в clojure 1.3, которую, скорее всего, используете вы, doc хранится в var clojure.repl/doc, а не в clojure.core/doc (как в 1.2). В пользовательском пространстве имен документ «используется», иначе говоря, есть неявный «(использовать [clojure.repl: только [doc])». Когда вы переходите к новому пространству имен или даже создаете его с помощью ns, clojure.repl/doc не добавляется автоматически, в отличие от «user.

Чтобы быть более точным в вопросах:

Почему REPL рассматривает clojure.core/doc как переменную?

Функции, макросы и значения в clojure либо хранятся в vars, либо привязываются к символу, например, в let или функции. clojure.core/doc — это переменная, содержащая макрос, который делает то, что делает doc.

Как обратиться к функции doc и распознать ее как функцию, а не как переменную?

Как и во всех лиспах, чтобы сделать вызов, будь то функция или макрос, вы должны поместить функцию/макрос в первую позицию списка.

(<fn/macro> *args)

Итак, чтобы вызвать документ макроса сам по себе, вы должны сделать:

(doc doc)
person bmillare    schedule 22.06.2011
comment
Обратите внимание, что clojure.core/doc — это 1.2 и более ранние версии. clojure.repl/doc — это 1.3 и более поздние версии. - person kotarak; 23.06.2011

Документ для документа показывает его макрос, поэтому его расширение с помощью macroexpand показывает, что ожидается имя переменной, содержащей функцию. поэтому очень коротким ответом на ваш вопрос будет «функции в пространстве имен содержатся в vars».

в подобных ситуациях можно начать с macroexpand-1:

(macroexpand-1 '(doc doc))
(clojure.core/print-doc (var doc))
sso-config.core> (doc doc)
-------------------------
clojure.core/doc
([name])
Macro
  Prints documentation for a var or special form given its name
person Arthur Ulfeldt    schedule 22.06.2011