Clojure "apropos"

On my 25 days of Clojure post I made a passing reference to Clojure needing an "apropos" command:

The Clojure documentation can be hard to decipher, and the clojure.core namespace is huge. ClojureDocs helps, but I believe there's a need for an apropos-like functionality built into the system.

In case you're not familiar with /usr/bin/apropos, here's what it looks like:

~> apropos audio
SoX(1)                   - Sound eXchange, the Swiss Army knife of audio manipulation  
faad(1)                  - Process an Advanced Audio Codec stream  
flac(1)                  - Free Lossless Audio Codec  
gst-visualise-0.10(1), gst-visualise(1) - Run a GStreamer pipeline to display an audio visualisation  
lame(1)                  - create mp3 audio files  
libsox(3)                - SoX, an audio file-format and effect library  
libswresample(3)         - audio resampling library  
sndfile-cmp(1)           - compares two audio files  
sndfile-concat(1)        - concatenates two or more audio files  
soxeffect(7), SoX(7)     - Sound eXchange, the Swiss Army knife of audio manipulation  
soxformat(7), SoX(7)     - Sound eXchange, the Swiss Army knife of audio manipulation  
twolame(1)               - an optimised MPEG Audio Layer 2 (MP2) encoder  
bluetoothaudiod(8)       - The Mac OS X Bluetooth audio daemon  
mount_cddafs(8)          - mount an Audio CD  

This generated a couple of responses via tweets and private emails pointing out that Clojure does indeed have an apropos function:

(apropos str-or-pattern)

Given a regular expression or stringable thing, return a seq of all public definitions in all currently-loaded namespaces that match the str-or-pattern.

However, even in the ClojureDocs apropos example you can see how it's not really what I had in mind:

user=> (apropos "temp")  
()

user=> (require 'clojure.template)  
nil

user=> (apropos "temp")  
(apply-template do-template)

... since it only searches the currently-loaded namespace. If you don't know what you're looking for, you probably won't have loaded the containing namespace in the first place. Of course, most of the time you're looking for something in clojure.core which is loaded by default, so let's move on.

Phrasing

Let's try another example. Let's say I want to add something to a collection. The keywords I'm thinking of are "add", "append", "prepend", "push", "insert". Here's what the output of apropos for all those are:

user=> (apropos "add")  
(clojure.core/add-classpath clojure.core/add-watch clojure.core/unchecked-add clojure.core/unchecked-add-int clojure.java.javadoc/add-local-javadoc clojure.java.javadoc/add-remote-javadoc clojure.tools.nrepl.middleware.session/add-stdin)
user=> (apropos "append")  
(clojure.core/chunk-append)
user=> (apropos "prepend")  
()
user=> (apropos "push")  
(clojure.core/push-thread-bindings clojure.tools.reader.reader-types/indexing-push-back-reader clojure.tools.reader.reader-types/input-stream-push-back-reader clojure.tools.reader.reader-types/push-back-reader clojure.tools.reader.reader-types/source-logging-push-back-reader clojure.tools.reader.reader-types/string-push-back-reader)
user=> (apropos "insert")  
()

Of course, the function I'm looking for is conj. Here's the built-in documentation for it:

user=> (doc conj)  
-------------------------
clojure.core/conj  
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item).  The 'addition' may
    happen at different 'places' depending on the concrete type.

You can see that "add" is mentioned twice, so you'd expect this would show up when doing (apropos "add") — but the fact is that clojure.repl/apropos searches only function names. This, combined with the very short names of most functions, results in very limited functionality.

Update: @mfikes on Twitter pointed out find-doc. It produces a ton of output though and it's not easily skimmable (I had to constrain the height of this code block to avoid messing the whole post up):

  
user=> (find-doc "add")  
-------------------------
clojure.tools.nrepl.middleware.session/add-stdin  
([h])
  stdin middleware.  Returns a handler that supports a "stdin" :op-eration, which
   adds content provided in a :stdin slot to the session's *in* Reader.  Delegates to
   the given handler for other operations.

   Requires the session middleware.
-------------------------
clojure.tools.nrepl.middleware.session/session  
([h])
  Session middleware.  Returns a handler which supports these :op-erations:

   * "ls-sessions", which results in a response message
     containing a list of the IDs of the currently-retained sessions in a
     :session slot.
   * "close", which drops the session indicated by the
     ID in the :session slot.  The response message's :status will include
     :session-closed.
   * "clone", which will cause a new session to be retained.  The ID of this
     new session will be returned in a response message in a :new-session
     slot.  The new session's state (dynamic scope, etc) will be a copy of
     the state of the session identified in the :session slot of the request.

   Messages indicating other operations are delegated to the given handler,
   with the session identified by the :session ID added to the message. If
   no :session ID is found, a new session is created (which will only
   persist for the duration of the handling of the given message).

   Requires the interruptible-eval middleware (specifically, its binding of
   *msg* to the currently-evaluated message so that session-specific *out*
   and *err* content can be associated with the originating message).
-------------------------
clojure.test/add-ns-meta  
([key coll])
  Adds elements in coll to the current namespace metadata as the
  value of key.
-------------------------
clojure.tools.nrepl.server/start-server  
([& {:keys [port bind transport-fn handler ack-port greeting-fn], :or {port 0}}])
  Starts a socket-based nREPL server.  Configuration options include:

   * :port — defaults to 0, which autoselects an open port on localhost
   * :bind — bind address, by default "localhost")
   * :handler — the nREPL message handler to use for each incoming connection;
       defaults to the result of `(default-handler)`
   * :transport-fn — a function that, given a java.net.Socket corresponding
       to an incoming connection, will return an value satisfying the
       clojure.tools.nrepl.Transport protocol for that Socket.
   * :ack-port — if specified, the port of an already-running server
       that will be connected to to inform of the new server's port.
       Useful only by Clojure tooling implementations.

   Returns a (map) handle to the server that is started, which may be stopped
   either via `stop-server`, (.close server), or automatically via `with-open`.
   The port that the server is open on is available in the :port slot of the
   server map (useful if the :port option is 0 or was left unspecified.
-------------------------
clojure.core.server/start-server  
([opts])
  Start a socket server given the specified opts:
    :address Host or address, string, defaults to loopback address
    :port Port, integer, required
    :name Name, required
    :accept Namespaced symbol of the accept function to invoke, required
    :args Vector of args to pass to accept function
    :bind-err Bind *err* to socket out stream?, defaults to true
    :server-daemon Is server thread a daemon?, defaults to true
    :client-daemon Are client threads daemons?, defaults to true
   Returns server socket.
-------------------------
cljs.stacktrace/parse-stacktrace  
  Parse a JavaScript stacktrace string into a canonical data form. The
  arguments:

  repl-env - the repl environment, an optional map with :host and :port keys
             if the stacktrace includes url, not file references
  st       - the original stacktrace string to parse
  err      - an error map. :ua-product key defines the type of stacktrace parser
             to use, for example :chrome
  opts     - additional options. :output-dir maybe given in this argument if
             :host and :port do not apply, for example, a file path

  The canonical stacktrace representation can easily be mapped to a
  ClojureScript one see mapped-stacktrace and mapped-stacktrace-str
-------------------------
cljs.module-graph/add-cljs-base  
([modules])
  Adds :cljs-base module to compiler :modules if not already present.
-------------------------
cljs.module-graph/add-cljs-base-dep  
([modules])
  Adds :cljs-base to any module in compiler :modules with an empty :depends-on.
-------------------------
cljs.module-graph/inputs->assigned-modules  
([inputs modules])
  Given compiler inputs assign each to a single module. This is done by first
  starting with :entries. Dependencies for every entry in a module are also added
  to that module. Inputs may of course be assigned to several modules initially
  but we must eventually choose one. User supplied module :entries are respected
  but all other input assignments are computed automatically via
  deepest-common-parent. This function returns a map assigning all inputs (indexed
  by munged name) to a single module. Any orphan inputs will be assigned to
  :cljs-base.
-------------------------
clojure.pprint/*print-miser-width*  
  The column at which to enter miser style. Depending on the dispatch table,
miser style add newlines in more places to try to keep lines short allowing for further  
levels of nesting.  
-------------------------
clojure.pprint/add-english-scales  
([parts offset])
  Take a sequence of parts, add scale numbers (e.g., million) and combine into a string
offset is a factor of 10^3 to multiply by  
-------------------------
cljs.analyzer/add-consts  
([compiler-state constants-map])
  Given a compiler state and a map from fully qualified symbols to constant
  EDN values, update the compiler state marking these vars as const to support
  direct substitution of these vars in source.
-------------------------
clojure.set/join  
([xrel yrel] [xrel yrel km])
  When passed 2 rels, returns the rel corresponding to the natural
  join. When passed an additional keymap, joins on the corresponding
  keys.
-------------------------
cljs.repl/repl  
([repl-env & opts])
  Generic, reusable, read-eval-print loop. By default, reads from *in* using
  a c.t.r.reader-types/source-logging-push-back-reader,
  writes to *out*, and prints exception summaries to *err*. If you use the
  default :read hook, *in* must either be an instance of
  c.t.r.reader-types/PushbackReader or duplicate its behavior of both supporting
  unread and collapsing CR, LF, and CRLF into a single \newline. Options
  are sequential keyword-value pairs. The first argument is the JavaScript
  evaluation environment, the second argument is an extended version of the
  standard ClojureScript compiler options. In addition to ClojureScript compiler
  build options it also take a set of options similar to clojure.main/repl with
  adjustments for ClojureScript evalution and compilation model:

  Available clojure.main/repl style options and their defaults:

     - :init, function of no arguments, initialization hook called with
       bindings for set!-able vars in place.
       default: #()

     - :need-prompt, function of no arguments, called before each
       read-eval-print except the first, the user will be prompted if it
       returns true.
       default: #(if (c.t.r.readers-types/indexing-reader? *in*)
                   (== (c.t.r.reader-types/get-column-number *in*) 1)
                   (identity true))

     - :prompt, function of no arguments, prompts for more input.
       default: repl-prompt

     - :flush, function of no arguments, flushes output
       default: flush

     - :read, function of two arguments, reads from *in*:
         - returns its first argument to request a fresh prompt
           - depending on need-prompt, this may cause the repl to prompt
             before reading again
         - returns its second argument to request an exit from the repl
         - else returns the next object read from the input stream
       default: repl-read

     - :eval, function of one argument, returns the evaluation of its
       argument. The eval function must take repl-env, the JavaScript evaluation
       environment, env, the ClojureScript analysis environment, the form
       and opts, the standard ClojureScript REPL/compiler options.
       default: eval

     - :print, function of one argument, prints its argument to the output
       default: println

     - :caught, function of three arguments, a throwable, called when
       read, eval, or print throws an exception or error default. The second
       argument is the JavaScript evaluation environment this permits context
       sensitive handling if necessary. The third argument is opts, the standard
       ClojureScript REPL/compiler options. In the case of errors or exception
       in the JavaScript target, these will be thrown as
       clojure.lang.IExceptionInfo instances.
       default: repl-caught

     - :reader, the c.t.r reader to use.
       default: c.t.r.reader-types/source-logging-push-back-reader

     - :print-no-newline, print without a newline.
       default: print

     - :source-map-inline, whether inline source maps should be enabled. Most
       useful in browser context. Implies using a fresh reader for each form.
       default: true
-------------------------
clojure.java.javadoc/add-local-javadoc  
([path])
  Adds to the list of local Javadoc paths.
-------------------------
clojure.java.javadoc/add-remote-javadoc  
([package-prefix url])
  Adds to the list of remote Javadoc URLs.  package-prefix is the
  beginning of the package name that has docs at this URL.
-------------------------
clojure.tools.nrepl/client-session  
([client & {:keys [session clone]}])
  Returns a function of one argument.  Accepts a message that is sent via the
   client provided with a fixed :session id added to it.  Returns the
   head of the client's response seq, filtered to include only
   messages related to the :session id that will terminate when the session is
   closed.
-------------------------
clojure.tools.nrepl/message  
([client {:keys [id], :as msg, :or {id (uuid)}}])
  Sends a message via [client] with a fixed message :id added to it.
   Returns the head of the client's response seq, filtered to include only
   messages related to the message :id that will terminate upon receipt of a
   "done" :status.
-------------------------
clojure.tools.nrepl/url-connect  
  Connects to an nREPL endpoint identified by the given URL/URI.  Valid
   examples include:

      nrepl://192.168.0.12:7889
      telnet://localhost:5000
      http://your-app-name.heroku.com/repl

   This is a multimethod that dispatches on the scheme of the URI provided
   (which can be a string or java.net.URI).  By default, implementations for
   nrepl (corresponding to using the default bencode transport) and
   telnet (using the clojure.tools.nrepl.transport/tty transport) are
   registered.  Alternative implementations may add support for other schemes,
   such as HTTP, HTTPS, JMX, existing message queues, etc.
-------------------------
cljs.closure/add-core-macros-if-cljs-js  
([compiled])
  If a compiled entity is the cljs.js namespace, explicitly
  add the cljs.core macros namespace dependency to it.
-------------------------
cljs.closure/add-dep-string  
([opts input])
  Return a goog.addDependency string for an input.
-------------------------
cljs.closure/add-dependencies  
([opts & inputs])
  Given one or more IJavaScript objects in dependency order, produce
  a new sequence of IJavaScript objects which includes the input list
  plus all dependencies in dependency order.
-------------------------
cljs.closure/add-dependency-sources  
([inputs] [inputs compile-opts])
  Given list of IJavaScript objects, produce a new sequence of IJavaScript objects
  of all dependencies of inputs.
-------------------------
cljs.closure/add-js-sources  
([inputs opts])
  Given list of IJavaScript objects, add foreign-deps, constants-table
   IJavaScript objects to the list.
-------------------------
cljs.closure/add-preloads  
([inputs opts])
  Add :preloads to a given set of inputs (IJavaScript). Returns a new
  list of inputs where the preloaded namespaces and their deps come immediately after
  cljs.core or the constants table depending on the optimization setting. Any
  files needing copying or compilation will be compiled and/or copied to the
  appropiate location.
-------------------------
cljs.closure/watch  
([source opts] [source opts compiler-env] [source opts compiler-env quit])
  Given a source directory, produce runnable JavaScript. Watch the source
   directory for changes rebuilding when necessary. Takes the same arguments as
   cljs.closure/build in addition to some watch-specific options:
    - :watch-fn, a function of no arguments to run after a successful build.
    - :watch-error-fn, a function receiving the exception of a failed build.
-------------------------
clojure.tools.nrepl.middleware/topologically-sort  
([comparator stack])
  Topologically sorts the given middlewares according to the comparator,
  with the added huristic that any middlewares that have no dependencies
  will be sorted toward the end.
-------------------------
clojure.tools.reader.impl.errors/eof-error  
([rdr & msgs])
  Throws an ExceptionInfo with the given message.
   If rdr is an IndexingReader, additional information about column and line number is provided
-------------------------
clojure.tools.reader.impl.errors/illegal-arg-error  
([rdr & msgs])
  Throws an ExceptionInfo with the given message.
   If rdr is an IndexingReader, additional information about column and line number is provided
-------------------------
clojure.tools.reader.impl.errors/reader-error  
([rdr & msgs])
  Throws an ExceptionInfo with the given message.
   If rdr is an IndexingReader, additional information about column and line number is provided
-------------------------
clojure.core/add-classpath  
([url])
  DEPRECATED

  Adds the url (String or URL object) to the classpath per
  URLClassLoader.addURL
-------------------------
clojure.core/add-watch  
([reference key fn])
  Adds a watch function to an agent/atom/var/ref reference. The watch
  fn must be a fn of 4 args: a key, the reference, its old-state, its
  new-state. Whenever the reference's state might have been changed,
  any registered watches will have their functions called. The watch fn
  will be called synchronously, on the agent's thread if an agent,
  before any pending sends if agent or ref. Note that an atom's or
  ref's state may have changed again prior to the fn call, so use
  old/new-state rather than derefing the reference. Note also that watch
  fns may be called from multiple threads simultaneously. Var watchers
  are triggered only by root binding changes, not thread-local
  set!s. Keys must be unique per reference, and can be used to remove
  the watch with remove-watch, but are otherwise considered opaque by
  the watch mechanism.
-------------------------
clojure.core/assoc!  
([coll key val] [coll key val & kvs])
  When applied to a transient map, adds mapping of key(s) to
  val(s). When applied to a transient vector, sets the val at index.
  Note - index must be <= (count vector). Returns coll.
-------------------------
clojure.core/completing  
([f] [f cf])
  Takes a reducing function f of 2 args and returns a fn suitable for
  transduce by adding an arity-1 signature that calls cf (default -
  identity) on the result argument.
-------------------------
clojure.core/conj  
([coll x] [coll x & xs])
  conj[oin]. Returns a new collection with the xs
    'added'. (conj nil item) returns (item).  The 'addition' may
    happen at different 'places' depending on the concrete type.
-------------------------
clojure.core/conj!  
([] [coll] [coll x])
  Adds x to the transient collection, and return coll. The 'addition'
  may happen at different 'places' depending on the concrete type.
-------------------------
clojure.core/defn  
([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])
Macro  
  Same as (def name (fn [params* ] exprs*)) or (def
    name (fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata. prepost-map defines a map with optional keys
    :pre and :post that contain collections of pre or post conditions.
-------------------------
clojure.core/defrecord  
([name [& fields] & opts+specs])
Macro  
  (defrecord name [fields*]  options* specs*)

  Options are expressed as sequential keywords and arguments (in any order).

  Supported options:
  :load-ns - if true, importing the record class will cause the
             namespace in which the record was defined to be loaded.
             Defaults to false.

  Each spec consists of a protocol or interface name followed by zero
  or more method bodies:

  protocol-or-interface-or-Object
  (methodName [args*] body)*

  Dynamically generates compiled bytecode for class with the given
  name, in a package with the same name as the current namespace, the
  given fields, and, optionally, methods for protocols and/or
  interfaces.

  The class will have the (immutable) fields named by
  fields, which can have type hints. Protocols/interfaces and methods
  are optional. The only methods that can be supplied are those
  declared in the protocols/interfaces.  Note that method bodies are
  not closures, the local environment includes only the named fields,
  and those fields can be accessed directly.

  Method definitions take the form:

  (methodname [args*] body)

  The argument and return types can be hinted on the arg and
  methodname symbols. If not supplied, they will be inferred, so type
  hints should be reserved for disambiguation.

  Methods should be supplied for all methods of the desired
  protocol(s) and interface(s). You can also define overrides for
  methods of Object. Note that a parameter must be supplied to
  correspond to the target object ('this' in Java parlance). Thus
  methods for interfaces will take one more argument than do the
  interface declarations. Note also that recur calls to the method
  head should *not* pass the target object, it will be supplied
  automatically and can not be substituted.

  In the method bodies, the (unqualified) name can be used to name the
  class (for calls to new, instance? etc).

  The class will have implementations of several (clojure.lang)
  interfaces generated automatically: IObj (metadata support) and
  IPersistentMap, and all of their superinterfaces.

  In addition, defrecord will define type-and-value-based =,
  and will defined Java .hashCode and .equals consistent with the
  contract for java.util.Map.

  When AOT compiling, generates compiled bytecode for a class with the
  given name (a symbol), prepends the current ns as the package, and
  writes the .class file to the *compile-path* directory.

  Two constructors will be defined, one taking the designated fields
  followed by a metadata map (nil for none) and an extension field
  map (nil for none), and one taking only the fields (using nil for
  meta and extension fields). Note that the field names __meta
  and __extmap are currently reserved and should not be used when
  defining your own records.

  Given (defrecord TypeName ...), two factory functions will be
  defined: ->TypeName, taking positional parameters for the fields,
  and map->TypeName, taking a map of keywords to field values.
-------------------------
clojure.core/ex-info  
([msg map] [msg map cause])
  Create an instance of ExceptionInfo, a RuntimeException subclass
   that carries a map of additional data.
-------------------------
clojure.core/find-keyword  
([name] [ns name])
  Returns a Keyword with the given namespace and name if one already
  exists.  This function will not intern a new keyword. If the keyword
  has not already been interned, it will return nil.  Do not use :
  in the keyword strings, it will be added automatically.
-------------------------
clojure.core/gen-class  
([& options])
Macro  
  When compiling, generates compiled bytecode for a class with the
  given package-qualified :name (which, as all names in these
  parameters, can be a string or symbol), and writes the .class file
  to the *compile-path* directory.  When not compiling, does
  nothing. The gen-class construct contains no implementation, as the
  implementation will be dynamically sought by the generated class in
  functions in an implementing Clojure namespace. Given a generated
  class org.mydomain.MyClass with a method named mymethod, gen-class
  will generate an implementation that looks for a function named by
  (str prefix mymethod) (default prefix: "-") in a
  Clojure namespace specified by :impl-ns
  (defaults to the current namespace). All inherited methods,
  generated methods, and init and main functions (see :methods, :init,
  and :main below) will be found similarly prefixed. By default, the
  static initializer for the generated class will attempt to load the
  Clojure support code for the class as a resource from the classpath,
  e.g. in the example case, ``org/mydomain/MyClass__init.class``. This
  behavior can be controlled by :load-impl-ns

  Note that methods with a maximum of 18 parameters are supported.

  In all subsequent sections taking types, the primitive types can be
  referred to by their Java names (int, float etc), and classes in the
  java.lang package can be used without a package qualifier. All other
  classes must be fully qualified.

  Options should be a set of key/value pairs, all except for :name are optional:

  :name aname

  The package-qualified name of the class to be generated

  :extends aclass

  Specifies the superclass, the non-private methods of which will be
  overridden by the class. If not provided, defaults to Object.

  :implements [interface ...]

  One or more interfaces, the methods of which will be implemented by the class.

  :init name

  If supplied, names a function that will be called with the arguments
  to the constructor. Must return [ [superclass-constructor-args] state]
  If not supplied, the constructor args are passed directly to
  the superclass constructor and the state will be nil

  :constructors {[param-types] [super-param-types], ...}

  By default, constructors are created for the generated class which
  match the signature(s) of the constructors for the superclass. This
  parameter may be used to explicitly specify constructors, each entry
  providing a mapping from a constructor signature to a superclass
  constructor signature. When you supply this, you must supply an :init
  specifier.

  :post-init name

  If supplied, names a function that will be called with the object as
  the first argument, followed by the arguments to the constructor.
  It will be called every time an object of this class is created,
  immediately after all the inherited constructors have completed.
  Its return value is ignored.

  :methods [ [name [param-types] return-type], ...]

  The generated class automatically defines all of the non-private
  methods of its superclasses/interfaces. This parameter can be used
  to specify the signatures of additional methods of the generated
  class. Static methods can be specified with ^{:static true} in the
  signature's metadata. Do not repeat superclass/interface signatures
  here.

  :main boolean

  If supplied and true, a static public main function will be generated. It will
  pass each string of the String[] argument as a separate argument to
  a function called (str prefix main).

  :factory name

  If supplied, a (set of) public static factory function(s) will be
  created with the given name, and the same signature(s) as the
  constructor(s).

  :state name

  If supplied, a public final instance field with the given name will be
  created. You must supply an :init function in order to provide a
  value for the state. Note that, though final, the state can be a ref
  or agent, supporting the creation of Java objects with transactional
  or asynchronous mutation semantics.

  :exposes {protected-field-name {:get name :set name}, ...}

  Since the implementations of the methods of the generated class
  occur in Clojure functions, they have no access to the inherited
  protected fields of the superclass. This parameter can be used to
  generate public getter/setter methods exposing the protected field(s)
  for use in the implementation.

  :exposes-methods {super-method-name exposed-name, ...}

  It is sometimes necessary to call the superclass' implementation of an
  overridden method.  Those methods may be exposed and referred in
  the new method implementation by a local name.

  :prefix string

  Default: "-" Methods called e.g. Foo will be looked up in vars called
  prefixFoo in the implementing ns.

  :impl-ns name

  Default: the name of the current ns. Implementations of methods will be
  looked up in this namespace.

  :load-impl-ns boolean

  Default: true. Causes the static initializer for the generated class
  to reference the load code for the implementing namespace. Should be
  true when implementing-ns is the default, false if you intend to
  load the code via some other method.
-------------------------
clojure.core/import  
([& import-symbols-or-lists])
Macro  
  import-list => (package-symbol class-name-symbols*)

  For each name in class-name-symbols, adds a mapping from name to the
  class named by package.name to the current namespace. Use :import in the ns
  macro in preference to calling this directly.
-------------------------
clojure.core/init-proxy  
([proxy mappings])
  Takes a proxy instance and a map of strings (which must
  correspond to methods of the proxy superclass/superinterfaces) to
  fns (which must take arguments matching the corresponding method,
  plus an additional (explicit) first arg corresponding to this, and
  sets the proxy's fn map.  Returns the proxy.
-------------------------
clojure.core/keyword  
([name] [ns name])
  Returns a Keyword with the given namespace and name.  Do not use :
  in the keyword strings, it will be added automatically.
-------------------------
clojure.core/partial  
([f] [f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more])
  Takes a function f and fewer than the normal arguments to f, and
  returns a fn that takes a variable number of additional args. When
  called, the returned function calls f with args + additional args.
-------------------------
clojure.core/partition  
([n coll] [n step coll] [n step pad coll])
  Returns a lazy sequence of lists of n items each, at offsets step
  apart. If step is not supplied, defaults to n, i.e. the partitions
  do not overlap. If a pad collection is supplied, use its elements as
  necessary to complete last partition upto n items. In case there are
  not enough padding elements, return a partition with less than n items.
-------------------------
clojure.core/proxy  
([class-and-interfaces args & fs])
Macro  
  class-and-interfaces - a vector of class names

  args - a (possibly empty) vector of arguments to the superclass
  constructor.

  f => (name [params*] body) or
  (name ([params*] body) ([params+] body) ...)

  Expands to code which creates a instance of a proxy class that
  implements the named class/interface(s) by calling the supplied
  fns. A single class, if provided, must be first. If not provided it
  defaults to Object.

  The interfaces names must be valid interface types. If a method fn
  is not provided for a class method, the superclass methd will be
  called. If a method fn is not provided for an interface method, an
  UnsupportedOperationException will be thrown should it be
  called. Method fns are closures and can capture the environment in
  which proxy is called. Each method fn takes an additional implicit
  first arg, which is bound to 'this. Note that while method fns can
  be provided to override protected methods, they have no other access
  to protected members, nor to super, as these capabilities cannot be
  proxied.
-------------------------
clojure.core/refer  
([ns-sym & filters])
  refers to all public vars of ns, subject to filters.
  filters can include at most one each of:

  :exclude list-of-symbols
  :only list-of-symbols
  :rename map-of-fromsymbol-tosymbol

  For each public interned var in the namespace named by the symbol,
  adds a mapping from the name of the var to the var to the current
  namespace.  Throws an exception if name is already mapped to
  something else in the current namespace. Filters can be used to
  select a subset, via inclusion or exclusion, or to provide a mapping
  to a symbol different from the var's name, in order to prevent
  clashes. Use :use in the ns macro in preference to calling this directly.
-------------------------
clojure.core/remove-watch  
([reference key])
  Removes a watch (set by add-watch) from a reference
-------------------------
clojure.core/require  
([& args])
  Loads libs, skipping any that are already loaded. Each argument is
  either a libspec that identifies a lib, a prefix list that identifies
  multiple libs whose names share a common prefix, or a flag that modifies
  how all the identified libs are loaded. Use :require in the ns macro
  in preference to calling this directly.

  Libs

  A 'lib' is a named set of resources in classpath whose contents define a
  library of Clojure code. Lib names are symbols and each lib is associated
  with a Clojure namespace and a Java package that share its name. A lib's
  name also locates its root directory within classpath using Java's
  package name to classpath-relative path mapping. All resources in a lib
  should be contained in the directory structure under its root directory.
  All definitions a lib makes should be in its associated namespace.

  'require loads a lib by loading its root resource. The root resource path
  is derived from the lib name in the following manner:
  Consider a lib named by the symbol 'x.y.z; it has the root directory
  /x/y/, and its root resource is /x/y/z.clj. The root
  resource should contain code to create the lib's namespace (usually by using
  the ns macro) and load any additional lib resources.

  Libspecs

  A libspec is a lib name or a vector containing a lib name followed by
  options expressed as sequential keywords and arguments.

  Recognized options:
  :as takes a symbol as its argument and makes that symbol an alias to the
    lib's namespace in the current namespace.
  :refer takes a list of symbols to refer from the namespace or the :all
    keyword to bring in all public vars.

  Prefix Lists

  It's common for Clojure code to depend on several libs whose names have
  the same prefix. When specifying libs, prefix lists can be used to reduce
  repetition. A prefix list contains the shared prefix followed by libspecs
  with the shared prefix removed from the lib names. After removing the
  prefix, the names that remain must not contain any periods.

  Flags

  A flag is a keyword.
  Recognized flags: :reload, :reload-all, :verbose
  :reload forces loading of all the identified libs even if they are
    already loaded
  :reload-all implies :reload and also forces loading of all libs that the
    identified libs directly or indirectly load via require or use
  :verbose triggers printing information about each load, alias, and refer

  Example:

  The following would load the libraries clojure.zip and clojure.set
  abbreviated as 's'.

  (require '(clojure zip [set :as s]))
-------------------------
clojure.core/transduce  
([xform f coll] [xform f init coll])
  reduce with a transformation of f (xf). If init is not
  supplied, (f) will be called to produce it. f should be a reducing
  step function that accepts both 1 and 2 arguments, if it accepts
  only 2 you can add the arity-1 with 'completing'. Returns the result
  of applying (the transformed) xf to init and the first item in coll,
  then applying xf to that result and the 2nd item, etc. If coll
  contains no items, returns init and f is not called. Note that
  certain transforms may inject or skip items.
-------------------------
clojure.core/unchecked-add  
([x y])
  Returns the sum of x and y, both long.
  Note - uses a primitive operator subject to overflow.
-------------------------
clojure.core/unchecked-add-int  
([x y])
  Returns the sum of x and y, both int.
  Note - uses a primitive operator subject to overflow.
-------------------------
clojure.core/update-proxy  
([proxy mappings])
  Takes a proxy instance and a map of strings (which must
  correspond to methods of the proxy superclass/superinterfaces) to
  fns (which must take arguments matching the corresponding method,
  plus an additional (explicit) first arg corresponding to this, and
  updates (via assoc) the proxy's fn map. nil can be passed instead of
  a fn, in which case the corresponding method will revert to the
  default behavior. Note that this function can be used to update the
  behavior of an existing instance without changing its identity.
  Returns the proxy.
-------------------------
clojure.core/use  
([& args])
  Like 'require, but also refers to each lib's namespace using
  clojure.core/refer. Use :use in the ns macro in preference to calling
  this directly.

  'use accepts additional options in libspecs: :exclude, :only, :rename.
  The arguments and semantics for :exclude, :only, and :rename are the same
  as those documented for clojure.core/refer.
-------------------------
cljs.core/defn  
([name doc-string? attr-map? [params*] prepost-map? body] [name doc-string? attr-map? ([params*] prepost-map? body) + attr-map?])
Macro  
  Same as (def name (core/fn [params* ] exprs*)) or (def
    name (core/fn ([params* ] exprs*)+)) with any doc-string or attrs added
    to the var metadata. prepost-map defines a map with optional keys
    :pre and :post that contain collections of pre or post conditions.
-------------------------
cljs.core/defrecord  
([rsym fields & impls])
Macro  
  (defrecord name [fields*]  options* specs*)

  Currently there are no options.

  Each spec consists of a protocol or interface name followed by zero
  or more method bodies:

  protocol-or-Object
  (methodName [args*] body)*

  The record will have the (immutable) fields named by
  fields, which can have type hints. Protocols and methods
  are optional. The only methods that can be supplied are those
  declared in the protocols.  Note that method bodies are
  not closures, the local environment includes only the named fields,
  and those fields can be accessed directly.

  Method definitions take the form:

  (methodname [args*] body)

  The argument and return types can be hinted on the arg and
  methodname symbols. If not supplied, they will be inferred, so type
  hints should be reserved for disambiguation.

  Methods should be supplied for all methods of the desired
  protocol(s). You can also define overrides for
  methods of Object. Note that a parameter must be supplied to
  correspond to the target object ('this' in JavaScript parlance). Note also
  that recur calls to the method head should *not* pass the target object, it
  will be supplied automatically and can not be substituted.

  In the method bodies, the (unqualified) name can be used to name the
  class (for calls to new, instance? etc).

  The type will have implementations of several ClojureScript
  protocol generated automatically: IMeta/IWithMeta (metadata support) and
  IMap, etc.

  In addition, defrecord will define type-and-value-based =,
  and will define ClojureScript IHash and IEquiv.

  Two constructors will be defined, one taking the designated fields
  followed by a metadata map (nil for none) and an extension field
  map (nil for none), and one taking only the fields (using nil for
  meta and extension fields). Note that the field names __meta
  and __extmap are currently reserved and should not be used when
  defining your own records.

  Given (defrecord TypeName ...), two factory functions will be
  defined: ->TypeName, taking positional parameters for the fields,
  and map->TypeName, taking a map of keywords to field values.
-------------------------
cljs.core/import  
([& import-symbols-or-lists])
Macro  
  import-list => (closure-namespace constructor-name-symbols*)

  For each name in constructor-name-symbols, adds a mapping from name to the
  constructor named by closure-namespace to the current namespace. Use :import in the ns
  macro in preference to calling this directly.
-------------------------
cljs.core/require  
([& args])
Macro  
  Loads libs, skipping any that are already loaded. Each argument is
  either a libspec that identifies a lib or a flag that modifies how all the identified
  libs are loaded. Use :require in the ns macro in preference to calling this
  directly.

  Libs

  A 'lib' is a named set of resources in classpath whose contents define a
  library of ClojureScript code. Lib names are symbols and each lib is associated
  with a ClojureScript namespace. A lib's name also locates its root directory
  within classpath using Java's package name to classpath-relative path mapping.
  All resources in a lib should be contained in the directory structure under its
  root directory. All definitions a lib makes should be in its associated namespace.

  'require loads a lib by loading its root resource. The root resource path
  is derived from the lib name in the following manner:
  Consider a lib named by the symbol 'x.y.z; it has the root directory
  /x/y/, and its root resource is /x/y/z.clj. The root
  resource should contain code to create the lib's namespace (usually by using
  the ns macro) and load any additional lib resources.

  Libspecs

  A libspec is a lib name or a vector containing a lib name followed by
  options expressed as sequential keywords and arguments.

  Recognized options:
  :as takes a symbol as its argument and makes that symbol an alias to the
    lib's namespace in the current namespace.
  :refer takes a list of symbols to refer from the namespace.
  :refer-macros takes a list of macro symbols to refer from the namespace.
  :include-macros true causes macros from the namespace to be required.
  :rename specifies a map from referred var names to different
    symbols (and can be used to prevent clashes)


  Flags

  A flag is a keyword.
  Recognized flags: :reload, :reload-all, :verbose
  :reload forces loading of all the identified libs even if they are
    already loaded
  :reload-all implies :reload and also forces loading of all libs that the
    identified libs directly or indirectly load via require or use
  :verbose triggers printing information about each load, alias, and refer

  Example:

  The following would load the library clojure.string :as string.

  (require '[clojure.string :as string])
-------------------------
clojure.test  
  A unit testing framework.

   ASSERTIONS

   The core of the library is the "is" macro, which lets you make
   assertions of any arbitrary expression:

   (is (= 4 (+ 2 2)))
   (is (instance? Integer 256))
   (is (.startsWith "abcde" "ab"))

   You can type an "is" expression directly at the REPL, which will
   print a message if it fails.

       user> (is (= 5 (+ 2 2)))

       FAIL in  (:1)
       expected: (= 5 (+ 2 2))
         actual: (not (= 5 4))
       false

   The "expected:" line shows you the original expression, and the
   "actual:" shows you what actually happened.  In this case, it
   shows that (+ 2 2) returned 4, which is not = to 5.  Finally, the
   "false" on the last line is the value returned from the
   expression.  The "is" macro always returns the result of the
   inner expression.

   There are two special assertions for testing exceptions.  The
   "(is (thrown? c ...))" form tests if an exception of class c is
   thrown:

   (is (thrown? ArithmeticException (/ 1 0)))

   "(is (thrown-with-msg? c re ...))" does the same thing and also
   tests that the message on the exception matches the regular
   expression re:

   (is (thrown-with-msg? ArithmeticException #"Divide by zero"
                         (/ 1 0)))

   DOCUMENTING TESTS

   "is" takes an optional second argument, a string describing the
   assertion.  This message will be included in the error report.

   (is (= 5 (+ 2 2)) "Crazy arithmetic")

   In addition, you can document groups of assertions with the
   "testing" macro, which takes a string followed by any number of
   assertions.  The string will be included in failure reports.
   Calls to "testing" may be nested, and all of the strings will be
   joined together with spaces in the final report, in a style
   similar to RSpec 

   (testing "Arithmetic"
     (testing "with positive integers"
       (is (= 4 (+ 2 2)))
       (is (= 7 (+ 3 4))))
     (testing "with negative integers"
       (is (= -4 (+ -2 -2)))
       (is (= -1 (+ 3 -4)))))

   Note that, unlike RSpec, the "testing" macro may only be used
   INSIDE a "deftest" or "with-test" form (see below).


   DEFINING TESTS

   There are two ways to define tests.  The "with-test" macro takes
   a defn or def form as its first argument, followed by any number
   of assertions.  The tests will be stored as metadata on the
   definition.

   (with-test
       (defn my-function [x y]
         (+ x y))
     (is (= 4 (my-function 2 2)))
     (is (= 7 (my-function 3 4))))

   As of Clojure SVN rev. 1221, this does not work with defmacro.
   See http://code.google.com/p/clojure/issues/detail?id=51

   The other way lets you define tests separately from the rest of
   your code, even in a different namespace:

   (deftest addition
     (is (= 4 (+ 2 2)))
     (is (= 7 (+ 3 4))))

   (deftest subtraction
     (is (= 1 (- 4 3)))
     (is (= 3 (- 7 4))))

   This creates functions named "addition" and "subtraction", which
   can be called like any other function.  Therefore, tests can be
   grouped and composed, in a style similar to the test framework in
   Peter Seibel's "Practical Common Lisp"
   

   (deftest arithmetic
     (addition)
     (subtraction))

   The names of the nested tests will be joined in a list, like
   "(arithmetic addition)", in failure reports.  You can use nested
   tests to set up a context shared by several tests.


   RUNNING TESTS

   Run tests with the function "(run-tests namespaces...)":

   (run-tests 'your.namespace 'some.other.namespace)

   If you don't specify any namespaces, the current namespace is
   used.  To run all tests in all namespaces, use "(run-all-tests)".

   By default, these functions will search for all tests defined in
   a namespace and run them in an undefined order.  However, if you
   are composing tests, as in the "arithmetic" example above, you
   probably do not want the "addition" and "subtraction" tests run
   separately.  In that case, you must define a special function
   named "test-ns-hook" that runs your tests in the correct order:

   (defn test-ns-hook []
     (arithmetic))

   Note: test-ns-hook prevents execution of fixtures (see below).


   OMITTING TESTS FROM PRODUCTION CODE

   You can bind the variable "*load-tests*" to false when loading or
   compiling code in production.  This will prevent any tests from
   being created by "with-test" or "deftest".


   FIXTURES

   Fixtures allow you to run code before and after tests, to set up
   the context in which tests should be run.

   A fixture is just a function that calls another function passed as
   an argument.  It looks like this:

   (defn my-fixture [f]
      Perform setup, establish bindings, whatever.
     (f)  Then call the function we were passed.
      Tear-down / clean-up code here.
    )

   Fixtures are attached to namespaces in one of two ways.  "each"
   fixtures are run repeatedly, once for each test function created
   with "deftest" or "with-test".  "each" fixtures are useful for
   establishing a consistent before/after state for each test, like
   clearing out database tables.

   "each" fixtures can be attached to the current namespace like this:
   (use-fixtures :each fixture1 fixture2 ...)
   The fixture1, fixture2 are just functions like the example above.
   They can also be anonymous functions, like this:
   (use-fixtures :each (fn [f] setup... (f) cleanup...))

   The other kind of fixture, a "once" fixture, is only run once,
   around ALL the tests in the namespace.  "once" fixtures are useful
   for tasks that only need to be performed once, like establishing
   database connections, or for time-consuming tasks.

   Attach "once" fixtures to the current namespace like this:
   (use-fixtures :once fixture1 fixture2 ...)

   Note: Fixtures and test-ns-hook are mutually incompatible.  If you
   are using test-ns-hook, fixture functions will *never* be run.


   SAVING TEST OUTPUT TO A FILE

   All the test reporting functions write to the var *test-out*.  By
   default, this is the same as *out*, but you can rebind it to any
   PrintWriter.  For example, it could be a file opened with
   clojure.java.io/writer.


   EXTENDING TEST-IS (ADVANCED)

   You can extend the behavior of the "is" macro by defining new
   methods for the "assert-expr" multimethod.  These methods are
   called during expansion of the "is" macro, so they should return
   quoted forms to be evaluated.

   You can plug in your own test-reporting framework by rebinding
   the "report" function: (report event)

   The 'event' argument is a map.  It will always have a :type key,
   whose value will be a keyword signaling the type of event being
   reported.  Standard events with :type value of :pass, :fail, and
   :error are called when an assertion passes, fails, and throws an
   exception, respectively.  In that case, the event will also have
   the following keys:

     :expected   The form that was expected to be true
     :actual     A form representing what actually occurred
     :message    The string message given as an argument to 'is'

   The "testing" strings will be a list in "*testing-contexts*", and
   the vars being tested will be a list in "*testing-vars*".

   Your "report" function should wrap any printing calls in the
   "with-test-out" macro, which rebinds *out* to the current value
   of *test-out*.

   For additional event types, see the examples in the code.

-------------------------
clojure.pprint  
  A Pretty Printer for Clojure

clojure.pprint implements a flexible system for printing structured data  
in a pleasing, easy-to-understand format. Basic use of the pretty printer is  
simple, just call pprint instead of println. More advanced users can use  
the building blocks provided to create custom output formats.

Out of the box, pprint supports a simple structured format for basic data  
and a specialized format for Clojure source code. More advanced formats,  
including formats that don't look like Clojure data at all like XML and  
JSON, can be rendered by creating custom dispatch functions.

In addition to the pprint function, this module contains cl-format, a text  
formatting function which is fully compatible with the format function in  
Common Lisp. Because pretty printing directives are directly integrated with  
cl-format, it supports very concise custom dispatch. It also provides  
a more powerful alternative to Clojure's standard format function.

See documentation for pprint and cl-format for more information or  
complete documentation on the the clojure web site on github.  
-------------------------
cljs.closure  
  Compile ClojureScript to JavaScript with optimizations from Google
   Closure Compiler producing runnable JavaScript.

   The Closure Compiler (compiler.jar) must be on the classpath.

   Use the 'build' function for end-to-end compilation.

   build = find-sources -> add-dependencies -> compile -> optimize -> output

   Two protocols are defined: IJavaScript and Compilable. The
   Compilable protocol is satisfied by something which can return one
   or more IJavaScripts.

   With IJavaScript objects in hand, calling add-dependencies will
   produce a sequence of IJavaScript objects which includes all
   required dependencies from the Closure library and ClojureScript,
   in dependency order. This function replaces the closurebuilder
   tool.

   The optimize function converts one or more IJavaScripts into a
   single string of JavaScript source code using the Closure Compiler
   API.

   The produced output is either a single string of optimized
   JavaScript or a deps file for use during development.

nil  

Grouping

Since I'm talking about function discoverability, here's another thing I complained about:

... the clojure.core namespace is huge...

How huge?

user=> (count (keys (ns-publics 'clojure.core)))  
621  

(I tried to figure this out on my own, but in the end I had to resort to StackOverflow)

This includes:

  • special forms
  • arithmetic, bitwise, boolean operators
  • global variables
  • some string functions (but others are in clojure.string
  • regex functions
  • flow control functions & macros
  • introspection & type stuff
  • concurrency stuff (though core.async is separate)
  • stuff that deal with functions (e.g. fn, defn, partial)
  • Java interop
  • Collections and related functions
  • IO
  • and much more — a more complete overview can be found on the ClojureDocs quickref.

I understand the reasoning behind this; you need most of those for day to day work, and making you require a namespace just to get map/filter would get old really quick. However, this makes it really difficult for a newcomer to discover what they are looking for.

Proposal

I believe that fixing the above stated problems is quite doable and can be even done in parallel:

  • Expand or add to the somewhat dry and too-concise function documentation. Use a format that can link to other functions, show in-line examples etc.
  • Group the various functions into related functionality. The ClojureDocs quick reference linked above goes a long way towards this, but needs to be officially adopted and maintained.
  • Link the API docs back to the Reference and Guides (the Reference already links to the API docs).
  • Do all this in a way that lends itself to better doc generation, incl. integration with 3rd-party tools like Dash.

Update: See also the 2017 ClojuTRE talk Towards Awesome Clojure Documentation by Bozhidar Batsov that goes into some more examples and proposals.

Meanwhile

I'd like to thank all the Clojure contributors for their work on the language. I hope I will have time in the future to contribute my own time towards some of those ideas, as this is the only feasible way to grow a language.

In the meantime, I advise people that might be bitten by all the shortcomings in the API docs, to do what I did: read a free book, read the Reference, then take some time to go over all the clojure.core functions once or twice. The last bit shouldn't take more than a couple of hours of focused work, and will be tough if you're not used to math-like precise writing, but it will pay off in many ways.