问题
I'm trying to get documentation using the Clojure doc
function, but can't get it recognized from the REPL (I'm using Emacs and SLIME). The following sequence describes what's going on (error message follows immediately after each line):
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>
How do I refer to the doc
function and get it recognized as a function, not a variable?
ADDENDUM, 6/22/11, 9 hours after question posted
@kotarak made the most relevant comment: "Note, that clojure.core/doc is 1.2 and earlier. clojure.repl/doc is 1.3 and later." Sure enough, the following worked:
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>
I was able to confirm that Clojure 1.3 was active:
user> *clojure-version*
{:interim true, :major 1, :minor 3, :incremental 0, :qualifier "master"}
user>
But this too was confusing--my Leiningen project.clj had specified Clojure 1.2!
In my own experience, I once noticed that the SLIME-based REPL "hung onto" a Java classpath value even after I changed the contents of relevant directories. The solution then was to exit Emacs and lein swank
, then re-enter both and try again. I tried the same and got the following result:
user> *clojure-version*
{:major 1, :minor 2, :incremental 0, :qualifier ""}
user>
The only conclusion I can make is that my previous REPL had been using Clojure 1.3. The project that I worked on previous to this had used a Clojure 1.3 snapshot, so I'm guessing that the REPL had "hung onto" Clojure 1.3 somehow.
Problem solved, lesson learned, etc. For bonus points, can anybody explain the reason for what happened (with Clojure 1.2 vs. 1.3)?
Thanks to all who contributed.
回答1:
Couple of corrections. First, doc is a macro not a function. Also functions and macros can be stored in a var. Second, in clojure 1.3, which is likely the version you are using, doc is stored in the var clojure.repl/doc, not clojure.core/doc (as it is in 1.2). In the namespace user, doc is "used", aka there is an implicit "(use [clojure.repl :only [doc])". When you goto a new namespace, or even create one with ns, clojure.repl/doc is not automatically added, unlike it is with 'user.
To be more explicit about the questions:
Why does REPL treat clojure.core/doc as a var?
Functions, macros and values in clojure are either stored in vars or bound to a symbol such as in a let or function. clojure.core/doc is the var that holds the macro that does what doc does.
How do I refer to the doc function and get it recognized as a function, not a variable?
Like in all lisps, to do a call, whether a function or a macro, you must put the function/macro in the first position of a list.
(<fn/macro> *args)
So to call the macro doc on itself, you would do:
(doc doc)
回答2:
The doc for doc shows its a macro so expanding it with macroexpand shows that is expecting the name of a var containging a function. so the very short answer to your question would be "functions in a namespace are contained in vars".
in situations like this macroexpand-1 can be a good place to start:
(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
来源:https://stackoverflow.com/questions/6443922/why-does-repl-treat-clojure-core-doc-as-a-var