You are previewing Clojure Programming.

Clojure Programming

Cover of Clojure Programming by Chas Emerick... Published by O'Reilly Media, Inc.
  1. Clojure Programming
  2. SPECIAL OFFER: Upgrade this ebook with O’Reilly
  3. Preface
    1. Who Is This Book For?
      1. Engaged Java Developers
      2. Ruby, Python, and Other Developers
    2. How to Read This Book
      1. Start with Practical Applications of Clojure
      2. Start from the Ground Up with Clojure’s Foundational Concepts
    3. Who’s “We”?
      1. Chas Emerick
      2. Brian Carper
      3. Christophe Grand
    4. Acknowledgments
      1. And Last, but Certainly Far from Least
    5. Conventions Used in This Book
    6. Using Code Examples
    7. Safari® Books Online
    8. How to Contact Us
  4. 1. Down the Rabbit Hole
    1. Why Clojure?
    2. Obtaining Clojure
    3. The Clojure REPL
    4. No, Parentheses Actually Won’t Make You Go Blind
    5. Expressions, Operators, Syntax, and Precedence
    6. Homoiconicity
    7. The Reader
      1. Scalar Literals
      2. Comments
      3. Whitespace and Commas
      4. Collection Literals
      5. Miscellaneous Reader Sugar
    8. Namespaces
    9. Symbol Evaluation
    10. Special Forms
      1. Suppressing Evaluation: quote
      2. Code Blocks: do
      3. Defining Vars: def
      4. Local Bindings: let
      5. Destructuring (let, Part 2)
      6. Creating Functions: fn
      7. Conditionals: if
      8. Looping: loop and recur
      9. Referring to Vars: var
      10. Java Interop: . and new
      11. Exception Handling: try and throw
      12. Specialized Mutation: set!
      13. Primitive Locking: monitor-enter and monitor-exit
    11. Putting It All Together
      1. eval
    12. This Is Just the Beginning
  5. I. Functional Programming and Concurrency
    1. 2. Functional Programming
      1. What Does Functional Programming Mean?
      2. On the Importance of Values
      3. First-Class and Higher-Order Functions
      4. Composition of Function(ality)
      5. Pure Functions
      6. Functional Programming in the Real World
    2. 3. Collections and Data Structures
      1. Abstractions over Implementations
      2. Concise Collection Access
      3. Data Structure Types
      4. Immutability and Persistence
      5. Metadata
      6. Putting Clojure’s Collections to Work
      7. In Summary
    3. 4. Concurrency and Parallelism
      1. Shifting Computation Through Time and Space
      2. Parallelism on the Cheap
      3. State and Identity
      4. Clojure Reference Types
      5. Classifying Concurrent Operations
      6. Atoms
      7. Notifications and Constraints
      8. Refs
      9. Vars
      10. Agents
      11. Using Java’s Concurrency Primitives
      12. Final Thoughts
  6. II. Building Abstractions
    1. 5. Macros
      1. What Is a Macro?
      2. Writing Your First Macro
      3. Debugging Macros
      4. Syntax
      5. When to Use Macros
      6. Hygiene
      7. Common Macro Idioms and Patterns
      8. The Implicit Arguments: &env and &form
      9. In Detail: -> and ->>
      10. Final Thoughts
    2. 6. Datatypes and Protocols
      1. Protocols
      2. Extending to Existing Types
      3. Defining Your Own Types
      4. Implementing Protocols
      5. Protocol Introspection
      6. Protocol Dispatch Edge Cases
      7. Participating in Clojure’s Collection Abstractions
      8. Final Thoughts
    3. 7. Multimethods
      1. Multimethods Basics
      2. Toward Hierarchies
      3. Hierarchies
      4. Making It Really Multiple!
      5. A Few More Things
      6. Final Thoughts
  7. III. Tools, Platform, and Projects
    1. 8. Organizing and Building Clojure Projects
      1. Project Geography
      2. Build
      3. Final Thoughts
    2. 9. Java and JVM Interoperability
      1. The JVM Is Clojure’s Foundation
      2. Using Java Classes, Methods, and Fields
      3. Handy Interop Utilities
      4. Exceptions and Error Handling
      5. Type Hinting for Performance
      6. Arrays
      7. Defining Classes and Implementing Interfaces
      8. Using Clojure from Java
      9. Collaborating Partners
    3. 10. REPL-Oriented Programming
      1. Interactive Development
      2. Tooling
      3. Debugging, Monitoring, and Patching Production in the REPL
      4. Limitations to Redefining Constructs
      5. In Summary
  8. IV. Practicums
    1. 11. Numerics and Mathematics
      1. Clojure Numerics
      2. Clojure Mathematics
      3. Equality and Equivalence
      4. Optimizing Numeric Performance
      5. Visualizing the Mandelbrot Set in Clojure
    2. 12. Design Patterns
      1. Dependency Injection
      2. Strategy Pattern
      3. Chain of Responsibility
      4. Aspect-Oriented Programming
      5. Final Thoughts
    3. 13. Testing
      1. Immutable Values and Pure Functions
      2. clojure.test
      3. Growing an HTML DSL
      4. Relying upon Assertions
    4. 14. Using Relational Databases
      1. clojure.java.jdbc
      2. Korma
      3. Hibernate
      4. Final Thoughts
    5. 15. Using Nonrelational Databases
      1. Getting Set Up with CouchDB and Clutch
      2. Basic CRUD Operations
      3. Views
      4. _changes: Abusing CouchDB as a Message Queue
      5. À la Carte Message Queues
      6. Final Thoughts
    6. 16. Clojure and the Web
      1. The “Clojure Stack”
      2. The Foundation: Ring
      3. Routing Requests with Compojure
      4. Templating
      5. Final Thoughts
    7. 17. Deploying Clojure Web Applications
      1. Java and Clojure Web Architecture
      2. Running Web Apps Locally
      3. Web Application Deployment
      4. Going Beyond Simple Web Application Deployment
  9. V. Miscellanea
    1. 18. Choosing Clojure Type Definition Forms Wisely
    2. 19. Introducing Clojure into Your Workplace
      1. Just the Facts…
      2. Emphasize Productivity
      3. Emphasize Community
      4. Be Prudent
    3. 20. What’s Next?
      1. (dissoc Clojure 'JVM)
      2. 4Clojure
      3. Overtone
      4. core.logic
      5. Pallet
      6. Avout
      7. Clojure on Heroku
  10. Index
  11. About the Authors
  12. Colophon
  13. SPECIAL OFFER: Upgrade this ebook with O’Reilly
O'Reilly logo

Special Forms

Ignoring Java interoperability for a moment, symbols in function position can evaluate to only two things:

  1. The value of a named var or local, as we’ve already seen.

  2. A Clojure special form.[18]

Special forms are Clojure’s primitive building blocks of computation, on top of which all the rest of Clojure is built. This foundation shares a lineage with the earliest Lisps, which also defined a limited set of primitives that define the fundamental operations of the runtime, and are taken as sufficient to describe any possible computation.[19] Further, special forms have their own syntax (e.g., many do not take arguments per se) and evaluation semantics.

As you’ve seen, things that are often described as primitive operations or statements in most languages—including control forms like when and operators like addition and negation—are not primitives in Clojure. Rather, everything that isn’t a special form is implemented in Clojure itself by bootstrapping from that limited set of primitive operations.[20] The practical effect of this is that, if Clojure doesn’t provide a language construct that you want or need, you can likely build it yourself.[21]

Though all of Clojure is built on top of its special forms, you need to understand what each one does—as you’ll use many of them constantly. Let’s now discuss each one in turn.

Suppressing Evaluation: quote

quote suppresses evaluation of a Clojure expression. The most obvious impact of this relates to symbols, which, if they name a var, evaluate to that var’s value. With quote, evaluation is suppressed, so symbols evaluate to themselves (just like strings, numbers, and so on):

(quote x)
;= x
(symbol? (quote x))
;= true

There is reader syntax for quote; prefixing any form with a quote character (') will expand into a usage of quote:

'x
;= x

Any Clojure form can be quoted, including data structures. Doing so returns the data structure in question, with evaluation recursively suppressed for all of its elements:

'(+ x x)
;= (+ x x)
(list? '(+ x x))
;= true

While lists are usually evaluated as calls, quoting a list suppresses that evaluation, yielding the list itself; in this case, a list of three symbols: '+, 'x, and 'x. Note that this is exactly what we get if we “manually” construct the list without using a list literal:

(list '+ 'x 'x)
;= (+ x x)

Tip

You can usually have a peek at what the reader produces by quoting a form. Let’s go meta for a moment and try it first on quote itself:

''x
;= (quote x)

It’s informative to use this trick on other reader sugars:

'@x
;= (clojure.core/deref x)
'#(+ % %)
;= (fn* [p1__3162792#] (+ p1__3162792# p1__3162792#))
'`(a b ~c)
;= (seq (concat (list (quote user/a))
;=              (list (quote user/b))
;=              (list c)))                  1
1

clojure.core namespace-prefixes elided for legibility.

Code Blocks: do

do evaluates all of the expressions provided to it in order and yields the last expression’s value as its value. For example:

(do
  (println "hi")
  (apply * [4 5 6]))
; hi
;= 120

The values of all but the last expression are discarded, although their side effects do occur (such as printing to standard out as we’re doing here, or manipulations of a stateful object available in the current scope).

Note that many other forms (including fn, let, loop, and try—and any derivative of these, such as defn) wrap their bodies in an implicit do expression, so that multiple inner expressions can be evaluated. For example, let expressions—like this one that defines two locals—provide an implicit do context to their bodies:

(let [a (inc (rand-int 6))
      b (inc (rand-int 6))]
  (println (format "You rolled a %s and a %s" a b))
  (+ a b))

This allows any number of expressions to be evaluated within the context of the let form, with only the final one determining its ultimate result. If let didn’t wrap its body with a do form, you would have to add it explicitly:[22]

(let [a (inc (rand-int 6))
      b (inc (rand-int 6))]
  (do
    (println (format "You rolled a %s and a %s" a b))
    (+ a b)))

Defining Vars: def

We’ve already seen def in action;[23] it defines (or redefines) a var (with an optional value) within the current namespace:

(def p "foo")
;= #'user/p
p
;= "foo"

Many other forms implicitly create or redefine vars, and therefore use def internally. It is customary for such forms to be prefixed with “def,” such as defn, defn-, defprotocol, defonce, defmacro, and so on.

Warning

Although forms that create or redefine vars have names that start with “def,” unfortunately not all forms that start with “def” create or redefine vars. Examples of the latter include deftype, defrecord, and defmethod.

Local Bindings: let

let allows you to define named references that are lexically scoped to the extent of the let expression. Said another way, let defines locals. For example, this rudimentary static method in Java:

public static double hypot (double x, double y) {
    final double x2 = x * x;
    final double y2 = y * y;
    return Math.sqrt(x2 + y2);
}

is equivalent to this Clojure function:

(defn hypot
  [x y]
  (let [x2 (* x x)
        y2 (* y y)]
    (Math/sqrt (+ x2 y2))))

The x2 and y2 locals in the respective function/method bodies serve the same purpose: to establish a named, scoped reference to an intermediate value.

Note

There are many terms used to talk about named references established by let in Clojure parlance:

  • locals

  • local bindings

  • particular values are said to be let-bound

Bindings and bound used in connection with let are entirely distinct from the binding macro, which controls scoped thread-local variables; see Dynamic Scope for more about the latter.

Note that let is implicitly used anywhere locals are required. In particular, fn (and therefore all other function-creation and function-definition forms like defn) uses let to bind function parameters as locals within the scope of the function being defined. For example, x and y in the hypot function above are let-bound by defn. So, the vector that defines the set of bindings for a let scope obeys the same semantics whether it is used to define function parameters or an auxiliary local binding scope.

Note

Occasionally, you will want evaluate an expression in the binding vector provided to let, but have no need to refer to its result within the context of the let’s body. In these cases, it is customary to use an underscore as the bound name for such values, so that readers of the code will know that results of such expressions are going unused intentionally.

This is only ever relevant when the expression in question is side-effecting; a common example would be printing some intermediate value:

(let [location (get-lat-long)
      _ (println "Current location:" location)
      location (find-city-name location)]
  …display city name for current location in UI…)

Here we’re retrieving our current latitude and longitude using a hypothetical API, and we’d like to print that out before converting the location data to a human-recognizable city name. We might want to rebind the same name a couple of times in the course of the let’s binding vector, paving over those intermediate values. To print out that intermediate value, we add it to the binding vector prior to rebinding its name, but we indicate that we are intentionally ignoring the return value of that expression by naming it _.

let has two particular semantic wrinkles that are very different from locals you may be used to in other languages:

  1. All locals are immutable. You can override a local binding within a nested let form or a later binding of the same name within the same binding vector, but there is no way to bash out a bound name and change its value within the scope of a single let form. This eliminates a source of common errors and bugs without sacrificing capability:

    • The loop and recur special forms provide for looping cases where values need to change on each cycle of a loop; see Looping: loop and recur.

    • If you really need a “mutable” local binding, Clojure provides a raft of reference types that enforce specific mutation semantics; see Clojure Reference Types.

  2. let’s binding vector is interpreted at compile time to provide optional destructuring of common collection types. Destructuring can aid substantially in eliminating certain types of verbose (and frankly, dull) code often associated with working with collections provided as arguments to functions.

Destructuring (let, Part 2)

A lot of Clojure programming involves working with various implementations of data structure abstractions, sequential and map collections being two of those key abstractions. Many Clojure functions accept and return seqs and maps generally—rather than specific implementations—and most Clojure libraries and applications are built up relying upon these abstractions instead of particular concrete structures, classes, and so on. This allows functions and libraries to be trivially composed around the data being handled with a minimum of integration, “glue code,” and other incidental complexity.

One challenge when working with abstract collections is being able to concisely access multiple values in those collections. For example, here’s a collection, a Clojure vector:

(def v [42 "foo" 99.2 [5 12]])
;= #'user/v

Consider a couple of approaches for accessing the values in our sample vector:

(first v)    1
;= 42
(second v)
;= "foo"
(last v)
;= [5 12]
(nth v 2)    2
;= 99.2
(v 2)        3
;= 99.2
(.get v 2)   4
;= 99.2
1

Clojure provides convenience functions for accessing the first, second, and last values from a sequential collection.

2

The nth function allows you pluck any value from a sequential collection using an index into that collection.

3

Vectors are functions of their indices.

4

All of Clojure’s sequential collections implement the java.util.List interface, so you can use that interface’s .get method to access their contents.

All of these are perfectly fine ways to access a single “top-level” value in a vector, but things start getting more complex if we need to access multiple values to perform some operation:

(+ (first v) (v 2))
;= 141.2

Or if we need to access values in nested collections:

(+ (first v) (first (last v)))
;= 47

Clojure destructuring provides a concise syntax for declaratively pulling apart collections and binding values contained therein as named locals within a let form. And, because destructuring is a facility provided by let, it can be used in any expression that implicitly uses let (like fn, defn, loop, and so on).

There are two flavors of destructuring: one that operates over sequential collections, and another that works with maps.

Sequential destructuring

Sequential destructuring works with any sequential collection, including:

  • Clojure lists, vectors, and seqs

  • Any collection that implements java.util.List (like ArrayLists and LinkedLists)

  • Java arrays

  • Strings, which are destructured into their characters

Here’s a basic example, where we are destructuring the same value v discussed above:

Example 1-3. Basic sequential destructuring

(def v [42 "foo" 99.2 [5 12]])
;= #'user/v
(let [[x y z] v]
  (+ x z))
;= 141.2

In its simplest form, the vector provided to let contains pairs of names and values, but here we’re providing a vector of symbols—[x y z]—instead of a scalar symbol name. What this does is cause the value v to be destructured sequentially, with the first value bound to x within the body of the let form, the second value bound to y, and the third value bound to z. We can then use those destructured locals like any other locals. This is equivalent to:

(let [x (nth v 0)
      y (nth v 1)
      z (nth v 2)]
  (+ x z))
;= 141.2

Note

Python has something similar to Clojure’s sequential destructuring, called unpacking. The equivalent to the preceding code snippet in Python would be something like:

>>> v = [42, "foo", 99.2, [5, 12]]
>>> x, y, z, a = v
>>> x + z
141.19999999999999

The same goes for Ruby:

>> x, y, z, a = [42, "foo", 99.2, [5, 12]]
[42, "foo", 99.2, [5, 12]]
>> x + z
141.2

Clojure, Python, and Ruby all seem pretty similar on their face; but, as you’ll see as we go along, Clojure goes quite a long ways beyond what Python and Ruby offer.

Destructuring forms are intended to mirror the structure of the collection that is being bound.[24] So, we can line up our destructuring form with the collection being destructured and get a very accurate notion of which values are going to be bound to which names:[25]

[x  y     z]
[42 "foo" 99.2 [5 12]]

Destructuring forms can be composed as well, so we can dig into the nested vector in v with ease:[26]

(let [[x _ _ [y z]] v]
  (+ x y z))
;= 59

If we visually line up our destructuring form and the source vector again, the work being done by that form should again be very clear:

[x  _     _    [y z ]]
[42 "foo" 99.2 [5 12]]

Warning

If our nested vector had a vector inside of it, we could destructure it as well. The destructuring mechanism has no limit to how far it can descend into a deeply nested data structure, but there are limits to good taste. If you’re using destructuring to pull values out of a collection four or more levels down, chances are your destructuring form will be difficult to interpret for the next person to see that code—even if that next person is you!

There are two additional features of sequential destructuring forms you should know about:

Gathering extra-positional sequential values

You can use & to gather values that lay beyond the positions you’ve named in your destructuring form into a sequence; this is similar to the mechanism underlying varargs in Java methods and is the basis of rest arguments in Clojure functions:

(let [[x & rest] v]
  rest)
;= ("foo" 99.2 [5 12])

This is particularly useful when processing items from a sequence, either via recursive function calls or in conjunction with a loop form. Notice that the value of rest here is a sequence, and not a vector, even though we provided a vector to the destructuring form.

Retaining the destructured value

You can establish a local binding for the original collection being destructured by specifying the name it should have via the :as option within the destructuring form:

(let [[x _ z :as original-vector] v]
  (conj original-vector (+ x z)))
;= [42 "foo" 99.2 [5 12] 141.2]

Here, original-vector is bound to the unchanged value of v. This comes in handy when you are destructuring a collection that is the result of a function call, but you need to retain a reference to that unaltered result in addition to having the benefit of destructuring it. Without this feature, doing so would require something like this:

(let [some-collection (some-function …)
      [x y z [a b]] some-collection]
  …do something with some-collection and its values…)

Map destructuring

Map destructuring is conceptually identical to sequential destructuring—we aim to mirror the structure of the collection being bound. It works with:

  • Clojure hash-maps, array-maps, and records[27]

  • Any collection that implements java.util.Map

  • Any value that is supported by the get function can be map-destructured, using indices as keys:

    • Clojure vectors

    • Strings

    • Arrays

Let’s start with a Clojure map and a basic destructuring of it:

(def m {:a 5 :b 6
        :c [7 8 9]
        :d {:e 10 :f 11}
        "foo" 88
        42 false})
;= #'user/m
(let [{a :a b :b} m]
  (+ a b))
;= 11

Here we’re binding the value for :a in the map to a, and the value for :b in the map to b. Going back to our visual alignment of the destructuring form with the (in this case, partial) collection being destructured, we can again see the structural correspondence:

{a  :a b  :b}
{:a 5  :b 6}

Note that there is no requirement that the keys used for map lookups in destructuring be keywords; any type of value may be used for lookup:

(let [{f "foo"} m]
  (+ f 12))
;= 100
(let [{v 42} m]
  (if v 1 0))
;= 0

Indices into vectors, strings, and arrays can be used as keys in a map destructuring form.[28] One place where this can be helpful is if you are representing matrices by using vectors, but only need a couple of values from one. Using map destructuring to pull out two or three values from a 3×3 matrix can be much easier than using a potentially nine-element sequential destructuring form:

(let [{x 3 y 8} [12 0 0 -18 44 6 0 0 1]]
  (+ x y))
;= -17

Just as sequential destructuring forms could be composed, so can the map variety:

(let [{{e :e} :d} m]
 (* 2 e))
;= 20

The outer map destructuring—{{e :e} :d}—is acting upon the top-level source collection m to pull out the value mapped to :d. The inner map destructuring—{e :e}—is acting on the value mapped to :d to pull out its value for :e.

The coup de grâce is the composition of both map and sequential destructuring, however they are needed to effectively extract the values you need from the collections at hand:

(let [{[x _ y] :c} m]
  (+ x y))
;= 16
(def map-in-vector ["James" {:birthday (java.util.Date. 73 1 6)}])
;= #'user/map-in-vector
(let [[name {bd :birthday}] map-in-vector]
  (str name " was born on " bd))
;= "James was born on Thu Feb 06 00:00:00 EST 1973"

Map destructuring also has some additional features.

Retaining the destructured value. Just like sequential destructuring, adding an :as pair to the destructuring form to hold a reference to the source collection, which you can use like any other let-bound value:

(let [{r1 :x r2 :y :as randoms}
      (zipmap [:x :y :z] (repeatedly (partial rand-int 10)))]
  (assoc randoms :sum (+ r1 r2)))
;= {:sum 17, :z 3, :y 8, :x 9}

Default values. You can use an :or pair to provide a defaults map; if a key specified in the destructuring form is not available in the source collection, then the defaults map will be consulted:

(let [{k :unknown x :a
       :or {k 50}} m]
  (+ k x))
;= 55

This allows you to avoid either merging the source map into a defaults map ahead of its destructuring, or manually setting defaults on destructured bindings that have nil values in the source collection, which would get very tiresome beyond one or two bindings with desired default values:

(let [{k :unknown x :a} m
      k (or k 50)]
  (+ k x))
;= 55

Furthermore, and unlike the code in the above example, :or knows the difference between no value and a false (nil or false) value:

(let [{opt1 :option} {:option false}
      opt1 (or opt1 true)
      {opt2 :option :or {opt2 true}} {:option false}]
  {:opt1 opt1 :opt2 opt2})
;= {:opt1 true, :opt2 false}

Binding values to their keys’ namesThere are often stable names for various values in maps, and it’s often desirable to bind those values by using the same names in the scope of the let form as they are mapped to in the source map. However, doing this using “vanilla” map destructuring can get very repetitive:

(def chas {:name "Chas" :age 31 :location "Massachusetts"})
;= #'user/chas
(let [{name :name age :age location :location} chas]
  (format "%s is %s years old and lives in %s." name age location))
;= "Chas is 31 years old and lives in Massachusetts."

Having to type the content of each key twice is decidedly contrary to the spirit of destructuring’s concision. In such cases, you can use the :keys, :strs, and :syms options to specify keyword, string, and symbol keys (respectively) into the source map and the names the corresponding values should be bound to in the let form without repetition. Our sample map uses keywords for keys, so we’ll use :keys for it:

(let [{:keys [name age location]} chas]
  (format "%s is %s years old and lives in %s." name age location))
;= "Chas is 31 years old and lives in Massachusetts."

…and switch to using :strs or :syms when we know that the source collection is using strings or symbols for keys:

(def brian {"name" "Brian" "age" 31 "location" "British Columbia"})
;= #'user/brian
(let [{:strs [name age location]} brian]
  (format "%s is %s years old and lives in %s." name age location))
;= "Brian is 31 years old and lives in British Columbia."

(def christophe {'name "Christophe" 'age 33 'location "Rhône-Alpes"})
;= #'user/christophe
(let [{:syms [name age location]} christophe]
  (format "%s is %s years old and lives in %s." name age location))
;= "Christophe is 31 years old and lives in Rhône-Alpes."

You will likely find yourself using :keys more than :strs or :syms; keyword keys are by far the most common key type in Clojure maps and keyword arguments, and are the general-purpose accessor by dint of their usage in conjunction with records.

Destructuring rest sequences as map key/value pairsWe’ve already seen how extra-positional values in sequential destructuring forms can be gathered into a “rest” seq, and map and sequential destructuring can be composed as needed to drill into any given data structure. Here’s a simple case of a vector that contains some positional values, followed by a set of key/value pairs:

(def user-info ["robert8990" 2011 :name "Bob" :city "Boston"])
;= #'user/user-info

Data like this isn’t uncommon, and handling it is rarely elegant. The “manual” approach in Clojure is tolerable as these things go:

(let [[username account-year & extra-info] user-info     1
      {:keys [name city]} (apply hash-map extra-info)]   2
  (format "%s is in %s" name city))
;= "Bob is in Boston"
1

We can destructure the original vector into its positional elements, gathering the remainder into a rest seq.

2

That rest seq, consisting of alternating keys and values, can be used as the basis for creating a new hashmap, which we can then destructure as we wish.

However, “tolerable” isn’t a very high bar given the prevalence of sequences of key/value pairs in programming. A better alternative is a special variety of the compositional behavior offered by let’s destructuring forms: map destructuring of rest seqs. If a rest seq has an even number of values—semantically, key/value pairs—then it can be destructured as a map of those key/value pairs instead of sequentially:

(let [[username account-year & {:keys [name city]}] user-info]
  (format "%s is in %s" name city))
;= "Bob is in Boston"

That is a far cleaner notation for doing exactly the same work as us manually building a hash-map out of the rest seq and destructuring that map, and is the basis of Clojure functions’ optional keyword arguments described in “Keyword arguments”.

Creating Functions: fn

Functions are first-class values in Clojure; creating them falls to the fn special form, which also folds in the semantics of let and do.

Here is a simple function that adds 10 to the number provided as an argument:

(fn [x]     1
  (+ 10 x)) 2
1

fn accepts a let-style binding vector that defines the names and numbers of arguments accepted by the function; the same optional destructuring forms discussed in Destructuring (let, Part 2) can be applied to each argument here.

2

The forms following the binding vector constitute the body of the function. This body is placed in an implicit do form, so each function’s body may contain any number of forms; as with do, the last form in the body supplies the result of the function call that is returned to the caller.

The arguments to a function are matched to each name or destructuring form based on their positions in the calling form. So in this call:

((fn [x] (+ 10 x)) 8)
;= 18

8 is the sole argument to the function, and it is bound to the name x within the body of the function. This makes the function call the equivalent of this let form:

(let [x 8]
  (+ 10 x))

You can define functions that accept multiple arguments:

((fn [x y z] (+ x y z))
 3 4 12)
;= 19

In this case, the function call is the equivalent of this let form:

(let [x 3
      y 4
      z 12]
  (+ x y z))

Functions with multiple arities can be created as well; here, we’ll put the function in a var so we can call it multiple times by only referring to the var’s name:

(def strange-adder (fn adder-self-reference
                     ([x] (adder-self-reference x 1))
                     ([x y] (+ x y))))
;= #'user/strange-adder
(strange-adder 10)
;= 11
(strange-adder 10 50)
;= 60

When defining a function with multiple arities, each arity’s binding vector and implementation body must be enclosed within a pair of parentheses. Function calls dispatch based on argument count; the proper arity is selected based on the number of arguments that we provide in our call.

In this last example, notice the optional name that we’ve given to the function, adder-self-reference. This optional first argument to fn can be used within the function’s bodies to refer to itself—in this case, so that the single-argument arity can call the two-argument arity with a default second argument without referring to or requiring any containing var.

Mutually recursive functions with letfn

Named fns (like the above adder-self-reference) allow you to easily create self-recursive functions. What is more tricky is to create mutually recursive functions.

For such rare cases, there is the letfn special form, which allows you to define several named functions at once, and all these functions will know each other. Consider these naive reimplementations of odd? and even?:

(letfn [(odd? [n]
          (even? (dec n)))
        (even? [n]
          (or (zero? n)
            (odd? (dec n))))]  1
  (odd? 11))
;= true
1

The vector consists of several regular fn bodies, only the fn symbol is missing.

defn builds on fnWe’ve already seen defn used before, and the example above should look familiar; defn is a macro that encapsulates the functionality of def and fn so that you can concisely define functions that are named and registered in the current namespace with a given name. For example, these two definitions are equivalent:

(def strange-adder (fn strange-adder
                     ([x] (strange-adder x 1))
                     ([x y] (+ x y))))

(defn strange-adder
  ([x] (strange-adder x 1))
  ([x y] (+ x y))))

and single-arity functions can be defined, with the additional parentheses eliminated as well; these two definitions are also equivalent:

(def redundant-adder (fn redundant-adder
                       [x y z]
                       (+ x y z)))

(defn redundant-adder
  [x y z]
  (+ x y z))

We’ll largely use defn forms to illustrate fn forms for the rest of this section, simply because calling functions bound to named vars is easier to read than continually defining the functions to be called inline.

Destructuring function arguments

defn supports the destructuring of function arguments thanks to it reusing let for binding function arguments for the scope of a function’s body. You should refer to the prior comprehensive discussion of destructuring to remind yourself of the full range of options available; here, we’ll discuss just a couple of destructuring idioms that are particularly common in conjunction with functions.

Variadic functionsFunctions can optionally gather all additional arguments used in calls to it into a seq; this uses the same mechanism as sequential destructuring does when gathering additional values into a seq. Such functions are called variadic, with the gathered arguments usually called rest arguments or varargs. Here’s a function that accepts one named positional argument, but gathers all additional arguments into a remainder seq:

(defn concat-rest
  [x & rest]
  (apply str (butlast rest)))
;= #'user/concat-rest
(concat-rest 0 1 2 3 4)
;= "123"

The seq formed for the rest arguments can be destructured just like any other sequence; here we’re destructuring rest arguments to make a function behave as if it had an explicitly defined zero-arg arity:

(defn make-user
  [& [user-id]]
  {:user-id (or user-id
              (str (java.util.UUID/randomUUID)))})
;= #'user/make-user
(make-user)
;= {:user-id "ef165515-6d6f-49d6-bd32-25eeb024d0b4"}
(make-user "Bobby")
;= {:user-id "Bobby"}

Keyword argumentsIt is often the case that you would like to define a function that can accept many arguments, some of which might be optional and some of which might have defaults. Further, you would often like to avoid forcing a particular argument ordering upon callers.[29]

fn (and therefore defn) provides support for such use cases through keyword arguments, which is an idiom built on top of the map destructuring of rest sequences that let provides. Keyword arguments are pairs of keywords and values appended to any strictly positional arguments in a function call, and if the function was defined to accept keyword arguments, those keyword/value pairs will be gathered into a map and destructured by the function’s map destructuring form that is placed in the same position as the rest arguments seq:

(defn make-user
  [username & {:keys [email join-date]                1
               :or {join-date (java.util.Date.)}}]    2
  {:username username
   :join-date join-date
   :email email
   ;; 2.592e9 -> one month in ms
   :exp-date (java.util.Date. (long (+ 2.592e9 (.getTime join-date))))})
;= #'user/make-user
(make-user "Bobby")                                   3
;= {:username "Bobby", :join-date #<Date Mon Jan 09 16:56:16 EST 2012>,
;=  :email nil, :exp-date #<Date Wed Feb 08 16:56:16 EST 2012>}
(make-user "Bobby"                                    4
  :join-date (java.util.Date. 111 0 1)
  :email "bobby@example.com")
;= {:username "Bobby", :join-date #<Date Sun Jan 01 00:00:00 EST 2011>,
;=  :email "bobby@example.com", :exp-date #<Date Tue Jan 31 00:00:00 EST 2011>}
1

The make-user function strictly requires only one argument, a username. The rest of the arguments are assumed to be keyword/value pairs, gathered into a map, and then destructured using the map destructuring form following &.

2

In the map destructuring form, we define a default of “now” for the join-date value.

3

Calling make-user with a single argument returns the user map, populated with defaulted join- and expiration-date values and a nil email value since none was provided in the keyword arguments.

4

Additional arguments provided to make-user are interpreted by the keyword destructuring map, without consideration of their order.

Note

Because keyword arguments are built using let’s map destructuring, there’s nothing stopping you from destructuring the rest argument map using types of key values besides keywords (such as strings or numbers or even collections). For example:

(defn foo
  [& {k ["m" 9]}]
  (inc k))
;= #'user/foo
(foo ["m" 9] 19)
;= 20

["m" 9] is being treated here as the name of a “keyword” argument.

That said, we’ve never actually seen non-keyword key types used in named function arguments. Keywords are overwhelmingly the most common argument key type used, thus the use of keyword arguments to describe the idiom.

Pre- and postconditionsfn provides support for pre- and postconditions for performing assertions with function arguments and return values. They are valuable features when testing and for generally enforcing function invariants; we discuss them in Preconditions and Postconditions.

Function literals

We mentioned function literals briefly in Miscellaneous Reader Sugar. Equivalent to blocks in Ruby and lambdas in Python, Clojure function literals’ role is straightforward: when you need to define an anonymous function—especially a very simple function—they provide the most concise syntax for doing so.

For example, these anonymous function expressions are equivalent:

(fn [x y] (Math/pow x y))

#(Math/pow %1 %2)

The latter is simply some reader sugar that is expanded into the former; we can clearly see this by checking the result of reading the textual code:[30]

(read-string "#(Math/pow %1 %2)")
;= (fn* [p1__285# p2__286#] (Math/pow p1__285# p2__286#))

The differences between the fn form and the shorter function literal are:

No implicit do form. “Regular” fn forms (and all of their derivatives) wrap their function bodies in an implicit do form, as we discussed in Creating Functions: fn. This allows you to do things like:

(fn [x y]
  (println (str x \^ y))
  (Math/pow x y))

The equivalent function literal requires an explicit do form:

#(do (println (str %1 \^ %2))
     (Math/pow %1 %2))

Arity and arguments specified using unnamed positional symbols. The fn examples above use the named symbols x and y to specify both the arity of the function being defined, as well as the names of the arguments passed to the function at runtime. In contrast, the literal uses unnamed positional % symbols, where %1 is the first argument, %2 is the second argument, and so on. In addition, the highest positional symbol defines the arity of the function, so if we wanted to define a function that accepted four arguments, we need only to refer to %4 within the function literal’s body.

There are two additional wrinkles to defining arguments in function literals:

  1. Function literals that accept a single argument are so common that you can refer to the first argument to the function by just using %. So, #(Math/pow % %2) is equivalent to #(Math/pow %1 %2). You should prefer the shorter notation in general.

  2. You can define a variadic function[31] and refer to that function’s rest arguments using the %& symbol. These functions are therefore equivalent:

(fn [x & rest]
  (- x (apply + rest)))

#(- % (apply + %&))

Function literals cannot be nestedSo, while this is perfectly legal:

(fn [x]
  (fn [y]
    (+ x y)))

This is not:

#(#(+ % %))
;= #<IllegalStateException java.lang.IllegalStateException:
;=   Nested #()s are not allowed>

Aside from the fact that the bodies of function literals are intended to be terse, simple expressions, making the prospect of nested function literals a readability and comprehension nightmare, there’s simply no way to disambiguate which function’s first argument % is referring to.

Conditionals: if

if is Clojure’s sole primitive conditional operator. Its syntax is simple: if the value of the first expression in an if form is logically true, then the result of the if form is the value of the second expression. Otherwise, the result of the if form is the value of the third expression, if provided. The second and third expressions are only evaluated as necessary.

Clojure conditionals determine logical truth to be anything other than nil or false:

(if "hi" \t)
;= \t
(if 42 \t)
;= \t
(if nil "unevaluated" \f)
;= \f
(if false "unevaluated" \f)
;= \f
(if (not true) \t)
;= nil

Note that if a conditional expression is logically false, and no else expression is provided, the result of an if expression is nil.[32]

Many refinements are built on top of if, including:

  • when, best used when nil should be returned (or no action should be taken) if a condition is false.

  • cond—similar to the else if construction in Java and Ruby, and elif in Python—allows you to concisely provide multiple conditions to check, along with multiple then expressions if a given conditional is true.

  • if-let and when-let, which are compositions of let with if and when, respectively: if the value of the test expression is logically true, it is bound to a local for the extent of the then expression.

Warning

Clojure provides true? and false? predicates, but these are unrelated to if conditionals. For example:

(true? "string")
;= false
(if "string" \t \f)
;= \t

true? and false? check for the Boolean values true and false, not the logical truth condition used by if, which is equivalent to (or (not (nil? x)) (true? x)) for any value x.

Looping: loop and recur

Clojure provides a number of useful imperative looping constructs, including doseq and dotimes, all of which are built upon recur. recur transfers control to the local-most loop head without consuming stack space, which is defined either by loop or a function. Let’s take a look at a very simple countdown loop:

(loop [x 5]            1
  (if (neg? x)
    x                  2
    (recur (dec x))))  3
;= -1
1

loop establishes bindings via an implicit let form, so it takes a vector of binding names and initial values.

2

If the final expression within a loop form consists of a value, that is taken as the value of the form itself. Here, when x is negative, the loop form returns the value of x.

3

A recur form will transfer control to the local-most loop head, in this case the loop form, resetting the local bindings to the values provided as arguments to recur. In this case, control jumps to the beginning of the loop form, with x bound to the value (dec x).

Loop heads are also established by functions, in which case recur rebinds the function’s parameters using the values provided as arguments to recur:

(defn countdown
  [x]
  (if (zero? x)
    :blastoff!
    (do (println x)
        (recur (dec x)))))
;= #'user/countdown
(countdown 5)
; 5
; 4
; 3
; 2
; 1
;= :blastoff!

Appropriate use of recurrecur is a very low-level looping and recursion operation that is usually not necessary:

  • When they can do the job, use the higher-level looping and iteration forms found in Clojure’s core library, doseq and dotimes.

  • When “iterating” over a collection or sequence, functional operations like map, reduce, for, and so on are almost always preferable.

Because recur does not consume stack space (thereby avoiding stack overflow errors), recur is critical when implementing certain recursive algorithms. In addition, because it allows you to work with numerics without the overhead of boxed representations, recur is very useful in the implementation of many mathematical and data-oriented operations. See Visualizing the Mandelbrot Set in Clojure for a live example of recur within such circumstances.

Finally, there are scenarios where the accumulation or consumption of a collection or set of collections is complicated enough that orchestrating things with a series of purely functional operations using map, reduce, and so on is either difficult or inefficient. In these cases, the use of recur (and sometimes loop in order to set up intermediate loop heads) can provide an important escape hatch.

Referring to Vars: var

Symbols that name a var evaluate to that var’s value:

(def x 5)
;= #'user/x
x
;= 5

However, there are occasions when you’d like to have a reference to the var itself, rather than the value it holds. The var special form does this:

(var x)
;= #'user/x

You’ve seen a number of times now how vars are printed in the REPL: #', followed by a symbol. This is reader syntax that expands to a call to var:

#'x
;= #'user/x

You’ll learn a lot more about vars in Vars.

Java Interop: . and new

All Java interoperability—instantiation, static and instance method invocation, and field access—flows through the new and . special forms. That said, the Clojure reader provides some syntactic sugar on top of these primitive interop forms that makes Java interop more concise in general and more syntactically consistent with Clojure’s notion of function position for method calls and instantiation. Thus, it’s rare to see . and new used directly, but you will nevertheless come across them out in the wild at some point:

Table 1-3. Sugared Java interop forms and their fully expanded equivalents

OperationJava codeSugared interop formEquivalent special form usage

Object instantiation

new java.util.ArrayList(100)

(java.util.ArrayList. 100)

(new java.util.ArrayList 100)

Static method invocation

Math.pow(2, 10)

(Math/pow 2 10)

(. Math pow 2 10)

Instance method invocation

"hello".substring(1, 3)

(.substring "hello" 1 3)

(. "hello" substring 1 3)

Static field access

Integer.MAX_VALUE

Integer/MAX_VALUE

(. Integer MAX_VALUE)

Instance field access

someObject.someField

(.someField some-object)

(. some-object some-field)

The sugared syntax shown in Table 1-3 is idiomatic and should be preferred in every case over direct usage of the . and new special forms. Java interop is discussed in depth in Chapter 9.

Exception Handling: try and throw

These special forms allow you to participate in and use the exception-handling and -throwing mechanisms in Java from Clojure. They are explained in Exceptions and Error Handling.

Specialized Mutation: set!

While Clojure emphasizes the use of immutable data structures and values, there are contexts where you need to effect an in-place mutation of state. The most common settings for this involve the use of setter and other stateful methods on Java objects you are using in an interop setting; for the remaining cases, Clojure provides set!, which can be used to:

  • Set the thread-local value of vars that have a non-root binding, discussed in Dynamic Scope

  • Set the value of a Java field, demonstrated in “Accessing object fields”

  • Set the value of mutable fields defined by deftype; see Types for details of that usage

Primitive Locking: monitor-enter and monitor-exit

These are lock primitives that allow Clojure to synchronize on the monitor associated with every Java object. You should never need to use these special forms, as there’s a macro, locking, that ensures proper acquisition and release of an object’s monitor. See Locking for details.



[18] Special forms are always given precedence when resolving symbols in function position. For example, you can have a var or local named def, but you will not be able to refer to the value of that var or local in function position—though you can refer to that value anywhere else.

[19] Paul Graham’s The Roots of Lisp (http://www.paulgraham.com/rootsoflisp.html) is a brief yet approachable precis of the fundamental operations of computation, as originally discovered and enumerated by John McCarthy. Though that characterization of computation was made more than 50 years ago, you can see it thriving in Clojure today.

[20] If you were to open the core.clj file from Clojure’s source repository, you will see this bootstrapping in action: everything from when and or to defn and = is defined in Clojure itself. Indeed, if you were so motivated, you could implement Clojure (or another language of your choosing) from scratch, on your own, on top of Clojure’s special forms.

[21] This sort of syntactic extension generally requires macros, which are treated in detail in Chapter 5.

[22] The other alternative would be for let (and all other forms that utilize do) to (re?) implement its own semantics of “do several things and return the value of the last expression”: hardly a reasonable thing to do.

[23] See Namespaces for a discussion of the typical usage of vars as stable references to values in namespaces; see Vars for more a more comprehensive treatment of them, including esoteric usages related to dynamic scope and thread-local references.

[24] Thus the term: destructuring is undoing (de-) the creation of the data structure.

[25] Values in the source collection that have no corresponding bound name are simply not bound within the context of the let form; you do not need to fully match the structure of the source collection, but sequential destructuring forms do need to be “anchored” at the beginning of the source.

[26] Again, note the use of underscores (_) in this destructuring form to indicate an ignored binding, similar to the idiom discussed in the note earlier in this chapter.

[27] See Records to learn more about records.

[28] This is due to the polymorphic behavior of get, which looks up values in a collection given a key into that collection; in the case of these indexable sequential values, get uses indices as keys. For more about get, see Associative.

[29] Python is a language that supports this usage pervasively, where every argument may be named and provided in any order in a function call, and argument defaults can be provided when a function is defined.

[30] Since the name of the arguments to the function is irrelevant, the function literal generates a unique symbol for each argument to refer to them; in this case, p1__285# and p2__286#.

[32] when is far more appropriate for such scenarios.

The best content for your career. Discover unlimited learning on demand for around $1/day.