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

The Clojure REPL

Many languages have REPLs, often also referred to as interpreters: Ruby has irb; Python has its command-line interpreter; Groovy has its console; even Java has something akin to a REPL in BeanShell. The “REPL” acronym is derived from a simple description of what it does:

  1. Read: code is read as text from some input (often stdin, but this varies if you’re using a REPL in an IDE or other nonconsole environment).

  2. Eval: the code is evaluated, yielding some value.

  3. Print: the value is printed to some output device (often stdout, sometimes preceded by other output if the code in question happened to print content itself).

  4. Loop: control returns to the read step.

Clojure has a REPL too, but it differs from many other languages’ REPLs in that it is not an interpreter or otherwise using a limited or lightweight subset of Clojure: all code entered into a Clojure REPL is compiled to JVM bytecode as part of its evaluation, with the same result as when code is loaded from a Clojure source file. In these two scenarios, compilation is performed entirely at runtime, and requires no separate “compile” step.[2] In fact, Clojure is never interpreted. This has a couple of implications:

  1. Operations performed in the REPL run at “full speed”; that is to say, there is no runtime penalty or difference in semantics associated with running code in the REPL versus running the same code as part of a “proper” application.

  2. Once you understand how Clojure’s REPL works (in particular, its read and eval phases), you’ll understand how Clojure itself works at the most fundamental level.

With this second point in mind, let’s dig into the Clojure REPL and see if we can find bedrock.

Note

The optimal workflow for programming in Clojure makes much more use of the REPL than is typical in other languages to make the development process as interactive as possible. Taking advantage of this is a significant source of the enhanced productivity—and really, fun!—that Clojure enables. We talk about this extensively in Chapter 10.

Example 1-1. Starting a Clojure REPL on the command line

% java -cp clojure-1.4.0.jar clojure.main
Clojure 1.4.0
user=>

This incantation starts a new JVM process, with a classpath that includes the clojure.jar file in the current directory, running the clojure.main class as its main entry point.[3] See A classpath primer if you don’t yet know what the classpath is; for now, you can just think of the classpath as the JVM’s analogue to Python’s PYTHONPATH, Ruby’s $:, and your shell’s PATH, the set of files and directories from which the JVM will load classes and resources.

When you see the user=> prompt, the REPL is ready for you to enter some Clojure code. The portion of the Clojure REPL prompt preceding => is the name of the current namespace. Namespaces are like modules or packages; we discuss them extensively later in this chapter in Namespaces. Clojure REPL sessions always start in the default user namespace.

Let’s look at some real code, a function that calculates the average of some numbers in Java, Ruby, and Python:

Example 1-2. Averaging numbers in Java, Ruby, and Python

public static double average (double[] numbers) {
  double sum = 0;
  for (int i = 0; i < numbers.length; i++) {
    sum += numbers[i];
  }
  return sum / numbers.length;
}

def average (numbers)
  numbers.inject(:+) / numbers.length
end

def average (numbers):
    return sum(numbers) / len(numbers)

Here is the Clojure equivalent:

(defn average                            1
  [numbers]                              2
  (/ (apply + numbers) (count numbers))) 3
1

defn defines a new function named average in the current namespace.

2

The average function takes one argument, referred to within its body as numbers. Note that there is no type declaration; this function will work equally well when provided with any collection or array of numbers of any type.

3

The body of the average function, which sums the provided numbers with (apply + numbers),[4] divides that sum by the number of numbers provided—obtained with (count numbers)—and returns the result of that division operation.

We can enter that defn expression at the REPL, and then call our function with a vector of numbers, which yields the expected result:

user=> (defn average
         [numbers]
         (/ (apply + numbers) (count numbers)))
#'user/average
user=> (average [60 80 100 400])
160


[2] If necessary, you can ahead-of-time compile Clojure to Java class files. See Ahead-of-Time Compilation for details.

[3] Alternatively, you can use java -jar clojure.jar, but the -cp flag and the clojure.main entry point are both important to know about; we talk about both in Chapter 8.

[4] Note that + here is not a special language operator, as in most other languages. It is a regular function, no different in type than the one we’re defining. apply is also a function, which applies a function it is provided with to a collection of arguments (numbers here); so, (apply + [a b c]) will yield the same value as (+ a b c).

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