Почему REPL рассматривает clojure.core / doc как переменную? - PullRequest
5 голосов
/ 22 июня 2011

Я пытаюсь получить документацию, используя функцию 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 и получить ее как функцию, а не переменную?


ADDENDUM, 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.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)?

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

Ответы [ 2 ]

12 голосов
/ 22 июня 2011

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

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

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

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

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

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

(<fn/macro> *args)

Таким образом, чтобы вызвать макрос на себя, вы должны сделать:

(doc doc)
1 голос
/ 23 июня 2011

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

в подобных ситуациях 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
...