Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure function argument syntax

Tags:

clojure

I'm trying to understand the syntax for calling use to load a library:

(use 'clojure.contrib.duck-streams)

Makes sense to me as it applies the quote reader macro to clojure.contrib.duck-streams so that the reader doesn't attempt to evaluate that string.

Now, if I want to use the :only tag to only load reader, why is this correct:

(use '[clojure.contrib.duck-streams :only (reader)])

instead of:

(use '[clojure.contrib.duck-streams :only reader])

I read this to mean pass in this vector of arguments to use but the REPL complains with Don't know how to create ISeq from Symbol. Why the parens around reader?

This is also equivalent to the first line and valid:

(use '[clojure.contrib.duck-streams])

So it seems that 'string are '[string] are equivalent arguments which I don't understand either.

like image 722
Pedro Estrada Avatar asked Oct 23 '09 18:10

Pedro Estrada


2 Answers

:only wants a list of symbols. That's just how the function is written. Note the docstring for refer, which use uses.

 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

It's written this way so that you can specify more than one symbol if you want.

(use '[clojure.contrib.duck-streams :only (reader writer)])

As discussed in this recent post, if you're writing a function that takes or returns a variable number of arguments, it's a good idea to have it always take/return a list or vector or set, even if it's taking/returning a single item. Because:

  • nil, often used to represent "zero items", is seqable. Empty collections are also seqable.
  • Two or more items in a list are seqable.
  • It only makes sense to also have one item be seqable by putting it into a list itself.

It would be awkward to have the one-item case be a special case. It's more consistent and easier to program around when you treat one-item as a sort of degenerate case and throw it into a list.

Note that all use cares about is whether the :only argument is a seqable collection of symbols. That means lists, vectors and sets all work.

(use '[clojure.contrib.duck-streams :only [reader writer]])
(use '[clojure.contrib.duck-streams :only #{reader writer}])

A single Symbol however is not seqable which is why you get the exception you do.

Look in core.clj if you want to see how this is all implemented.

like image 98
Brian Carper Avatar answered Oct 17 '22 03:10

Brian Carper


Those aren't just "parens" — parens are the syntax for creating a list. It would appear the item after the :only tag is expected to be a list of things it applies to.

like image 1
Chuck Avatar answered Oct 17 '22 02:10

Chuck