Tải bản đầy đủ

The joy of clojure, 2nd edition

MANNING

SECOND EDITION

Michael Fogus
Chris Houser
FOREWORD BY
William E. Byrd & Daniel P. Friedman

www.it-ebooks.info


Praise for the First Edition
The authors blaze through many of the classics of both functional programming and
industry programming in a whirlwind tour of Clojure that feels at times more like a
class-five tropical storm. You’ll learn fast!
—From the Foreword by Steve Yegge, Google
The Joy of Clojure wants to make you a better programmer, not just a better Clojure
programmer. I would absolutely recommend this to anyone I know who had an interest
in Clojure and/or functional programming.
—Rob Friesel

Dealer.com Websystems
Teaches the Tao of Clojure and, oh boy, it’s such a joy! Simply unputdownable!
—Baishampayan Ghose (BG)
Cofounder & CTO, Qotd, Inc.
The Clojure community, present and future, will be grateful for this book.
—Andrew Oswald
Chariot Solutions
Discover the why not just the how of Clojure
—Federico Tomassetti
Politecnico di Torino
The Joy of Clojure really lives up to its name! Every page oozes with the excitement
@fogus and @chrishouser have for the language and its community. This is exactly
what makes this book such an enjoyable read, it’s hard not to get drawn into the beauty
of Clojure when you have two convinced developers sharing their passion with you.
—Amazon Reader M.K.
What Irma Rombauer did for cooking, Fogus and Houser have done for Clojure!
By going beyond the basics, this book equips the reader to think like a native speaker
in Clojure-land.
—Phil Hagelberg
Creator of the Leiningen build tool, Heroku
A fun exploration of functional programming and Lisp.
—Matt Revelle
Cofounder, Woven, Inc.

www.it-ebooks.info


www.it-ebooks.info


The Joy of Clojure
SECOND EDITION
MICHAEL FOGUS
CHRIS HOUSER

MANNING
SHELTER ISLAND

www.it-ebooks.info



For online information and ordering of this and other Manning books, please visit
www.manning.com. The publisher offers discounts on this book when ordered in quantity.
For more information, please contact
Special Sales Department
Manning Publications Co.
20 Baldwin Road
PO Box 261
Shelter Island, NY 11964
Email: orders@manning.com

©2014 by Manning Publications Co. All rights reserved.

No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in
any form or by means electronic, mechanical, photocopying, or otherwise, without prior written
permission of the publisher.

Many of the designations used by manufacturers and sellers to distinguish their products are
claimed as trademarks. Where those designations appear in the book, and Manning
Publications was aware of a trademark claim, the designations have been printed in initial caps
or all caps.

Recognizing the importance of preserving what has been written, it is Manning’s policy to have
the books we publish printed on acid-free paper, and we exert our best efforts to that end.
Recognizing also our responsibility to conserve the resources of our planet, Manning books
are printed on paper that is at least 15 percent recycled and processed without the use of
elemental chlorine.

Manning Publications Co.
20 Baldwin Road
PO Box 261
Shelter Island, NY 11964

Development editor:
Copyeditor:
Proofreader:
Typesetter:
Cover designer:

ISBN 9781617291418
Printed in the United States of America
1 2 3 4 5 6 7 8 9 10 – EBM – 19 18 17 16 15 14

www.it-ebooks.info

Nermina Miller
Benjamin Berg
Tiffany Taylor
Dottie Marsico
Marija Tudor


To Timothy Hart—a hacker of the highest order.
Rest in peace.

www.it-ebooks.info


www.it-ebooks.info


brief contents
PART 1 FOUNDATIONS ..............................................................1
1
2
3





Clojure philosophy 3
Drinking from the Clojure fire hose
Dipping your toes in the pool 51

25

PART 2 DATA TYPES ................................................................67
4
5




On scalars 69
Collection types

84

PART 3 FUNCTIONAL PROGRAMMING .....................................115
6
7




Being lazy and set in your ways 117
Functional programming 136

PART 4 LARGE-SCALE DESIGN................................................. 171
8
9
10
11






Macros 173
Combining data and code 194
Mutation and concurrency 224
Parallelism 262

vii

www.it-ebooks.info


viii

BRIEF CONTENTS

PART 5 HOST SYMBIOSIS .......................................................275
12
13




Java.next 277
Why ClojureScript? 310

PART 6 TANGENTIAL CONSIDERATIONS ..................................331
14
15
16
17






Data-oriented programming 333
Performance 363
Thinking programs 393
Clojure changes the way you think 423

www.it-ebooks.info


contents
foreword to the second edition xix
foreword to the first edition xxi
preface xxiii
acknowledgments xxv
about this book xxvii
about clojure xxxvii
about the cover illustration xxxix

PAT 1

1

FOUNDATIONS .....................................................1
Clojure philosophy
1.1

3

The Clojure way

4

Simplicity 4 Freedom to focus
Clarity 6 Consistency 7


5



Empowerment

5



1.2

Why a(nother) Lisp?
Beauty

1.3

9



8

But what’s with all the parentheses?

9

Functional programming 16
A workable definition of functional programming 16
The implications of functional programming 17

1.4

Why Clojure isn’t especially object-oriented 17
Defining terms 17 Imperative “baked in”
OOP gives you, Clojure provides 19


1.5

Summary

24
ix

www.it-ebooks.info

18



Most of what


x

CONTENTS

2

Drinking from the Clojure fire hose
2.1

25

Scalars: the base data types

26

Numbers 26 Integers 27 Floating-point numbers 27
Rationals 28 Symbols 28 Keywords 28 Strings 29
Characters 29






2.2



Putting things together: collections
Lists

2.3
2.4
2.5



29

Vectors

30

Maps

30

Making things happen: calling functions
Vars are not variables 31
Functions 32

31



30

29
Sets





Anonymous functions 32 Creating named functions with def
and defn 33 Functions with multiple arities 33 In-place
functions with #() 34




2.6

Locals, loops, and blocks
Blocks

2.7



35

Locals



35

35


Loops

36

Preventing things from happening: quoting 39
Evaluation 39 Quoting 40
splicing 42 Auto-gensym 42




Unquote

41



Unquote-



2.8

Using host libraries via interop 43
Accessing static class members (Clojure only) 43 Creating
instances 43 Accessing instance members with the .
operator 44 Setting instance fields 44 The .. macro 44
The doto macro 45 Defining classes 45










2.9

Exceptional circumstances
Throwing and catching

2.10

46

46

Modularizing code with namespaces

47

Creating namespaces using ns 47 Loading other namespaces
with :require 48 Loading and creating mappings with
:refer 48 Creating mappings with :refer 49 Loading Java
classes with :import 49






2.11

3

Summary



50

Dipping your toes in the pool
3.1

Truthiness

52

What’s truth? 52
nil vs. false 53

3.2

51

Nil pun with care



Don’t create Boolean objects

53

www.it-ebooks.info

52


xi

CONTENTS

3.3

Destructuring

55

Your assignment, should you choose to accept it 55
Destructuring with a vector 56 Destructuring with a map 57
Destructuring in function parameters 59 Destructuring vs.
accessor methods 59




3.4

Using the REPL to experiment 59
Experimenting with seqs 59 Experimenting with graphics 61
Putting it all together 63 When things go wrong 63 Just for
fun 65




3.5

Summary



66

PART 2 DATA TYPES ......................................................... 67

4

On scalars
4.1

69

Understanding precision

70

Truncation 70 Promotion 71 Overflow
Underflow 72 Rounding errors 72


71





4.2

Trying to be rational 73
Why be rational?
rationality 75

4.3
4.4



How to be rational 74

When to use keywords

75

Applications of keywords

76

Symbolic resolution
Metadata

4.5

73

79





Symbols and namespaces

80

Syntax 82 Regular-expression functions
mutable matchers 83

5

Collection types
5.1

77

78
Lisp-1



Regular expressions—the second problem

Summary

Caveats of

Qualifying your keywords

83



4.6



80

81


Beware of

83

84

Persistence, sequences, and complexity

85

“You keep using that word. I do not think it means what you
think it means.” 85 Sequence terms and what they mean 86
Big-O 89


5.2

Vectors: creating and using them in all their varieties

91

Building vectors 91 Large vectors 92 Vectors as stacks 95
Using vectors instead of reverse 96 Subvectors 97 Vectors as
map entries 97 What vectors aren’t 98








www.it-ebooks.info




xii

CONTENTS

5.3

Lists: Clojure’s code-form data structure
Lists like Lisps like
aren’t 100

5.4

99



Lists as stacks

How to use persistent queues

100

99


What lists

101

A queue about nothing 101 Putting things on
Getting things 102 Taking things off 102


102



5.5

Persistent sets

103

Basic properties of Clojure sets 103 Keeping your sets in order
with sorted-set 104 The contains? function 105 The
clojure.set namespace 105




5.6

Thinking in maps



107

Hash maps 107 Keeping your keys in order with sorted
maps 108 Keeping your insertions in order with array
maps 109




5.7

Putting it all together: finding the position of items in a
sequence 110
Implementation

5.8

Summary

111

113

PART 3 FUNCTIONAL PROGRAMMING .............................. 115

6

Being lazy and set in your ways
6.1

On immutability: being set in your ways
What is immutability?

6.2
6.3

117

118



117

What is immutability for?

Structural sharing: a persistent toy
Laziness 123

119

120

Familiar laziness with logical-and 124 Understanding the lazyseq recipe 125 Losing your head 128 Employing infinite
sequences 129 The delay and force macros 130








6.4

Putting it all together: a lazy quicksort 132
The implementation

6.5

7

Summary

135

Functional programming
7.1

133

136

Functions in all their forms

136

First-class functions 137 Higher-order functions 140 Pure
functions 144 Named arguments 145 Constraining
functions with pre- and postconditions 146




www.it-ebooks.info






xiii

CONTENTS

7.2

On closures

148

Functions returning closures 149
Passing closures as functions 150

7.3

Thinking recursively




Closing over parameters 150
Sharing closure context 151

155

Mundane recursion 155 Tail calls and recur 158 Don’t
forget your trampoline 161 Continuation-passing style 163






7.4

Putting it all together: A* pathfinding 165
The world 165 Neighbors 165 The A*
implementation 167 Notes about the A* implementation






7.5

Summary

169

170

PART 4 LARGE-SCALE DESIGN ........................................171

8

Macros
8.1

173
Data is code is data

175

Syntax-quote, unquote, and splicing
thumb 177

8.2

Defining control structures

176



Macro rules of

178

Defining control structures without syntax-quote 178 Defining
control structures using syntax-quote and unquoting 179


8.3
8.4
8.5

Macros combining forms 180
Using macros to change forms 182
Using macros to control symbolic resolution time
Anaphora 186
capturing 188

8.6
8.7
8.8

9



(Arguably) useful selective name

Using macros to manage resources 188
Putting it all together: macros returning functions
Summary 193

Combining data and code
9.1

Namespaces

190

194

195

Creating namespaces 196 Expose only what’s needed
Declarative inclusions and exclusions 199


9.2

186

197

Exploring Clojure multimethods with the Universal
Design Pattern 200
The parts 201 Basic use of the Universal Design Pattern 202
Multimethods to the rescue 203 Ad hoc hierarchies for inherited




www.it-ebooks.info


xiv

CONTENTS

behaviors 203 Resolving conflict in hierarchies
Arbitrary dispatch for true maximum power 205

204



9.3

Types, protocols, and records
Records 206 Protocols
base with deftype 217

209



9.4

10

Summary

219

Building from a more primitive

Clojure implementation



221

223

Mutation and concurrency
10.1



Putting it all together: a fluent builder for chess
moves 219
Java implementation

9.5

206

When to use refs

224
226

Using refs for a mutable game board 228 Transactions 230
Embedded transactions 232 The things that STM makes
easy 232 Potential downsides 233 The things that make
STM unhappy 234






10.2



Refactoring with refs

235

Fixing the game board example 235 Commutative change with
commute 237 Vulgar change with ref-set 238 Refs under
stress 239




10.3



When to use agents

240

In-process vs. distributed concurrency models 241 Controlling
I/O with an agent 243 The difference between send and
send-off 245 Error handling 246 When not to use
agents 248






10.4



When to use atoms

249

Sharing across threads

10.5

When to use locks

249



252

Safe mutation through locking
locks 254

10.6

11

Summary

Parallelism
11.1

253



Using Java’s explicit

Vars and dynamic binding 256
The binding macro 257
Creating anonymous vars

10.7

Using atoms in transactions



Creating a named var 257
258 Dynamic scope 259

260

262

When to use futures
Futures as callbacks

263
263

www.it-ebooks.info



250


xv

CONTENTS

11.2

When to use promises

268

Parallel tasks with promises 269 Callback API to blocking
API 270 Deterministic deadlocks 271




11.3

Parallel operations
The pvalues macro
function 273

11.4
11.5

271
272



The pmap function

272



The pcalls

A brief introduction to reducer/fold 273
Summary 274

PART 5 HOST SYMBIOSIS ..............................................275

12

Java.next
12.1

277

Generating objects on the fly with proxy
A simple dynamic web service

12.2

278

279

Clojure gen-class and GUI programming 285
Namespaces as class specifications 286 The guts of namespace
compilation 288 Exploring user interface design and
development with Clojure 289




12.3

Clojure’s relationship to Java arrays

292

Types of arrays: primitive and reference 292 Array
mutability 294 Arrays’ unfortunate naming convention 295
Multidimensional arrays 296 Variadic method/constructor
calls 297






12.4

All Clojure functions implement … 297
The java.util.Comparator interface 297 The java.lang.Runnable
interface 298 The java.util.concurrent.Callable interface 299




12.5

Using Clojure data structures in Java APIs

299

The java.util.List interface 300 The java.lang.Comparable
interface 300 The java.util.RandomAccess interface 301
The java.util.Collection interface 301 The java.util.Set
interface 302






12.6

The definterface macro

302

Generating interfaces on the fly 302

12.7

Be wary of exceptions

304

A bit of background regarding exceptions 305 Runtime vs.
compile-time exceptions 305 Handling exceptions 307
Custom exceptions 308




12.8

Summary

309
www.it-ebooks.info


xvi

CONTENTS

13

Why ClojureScript?
13.1
13.2

310

Implementation vs. interface 311
Compiler internals: analysis vs. emission

314

Stages of compilation 315 Web Audio 317 Advanced
compilation 321 Generating an externs.js file 324






13.3
13.4

Compile vs. run
Summary 330

326

PART 6 TANGENTIAL CONSIDERATIONS .........................331

14

Data-oriented programming
14.1

333

Code as code, and data as data

334

A strict line betwixt 334 ORMG 335 Common ways to
derive information from data 337 PLOP 337






14.2

Data as data

338

The benefits of value

14.3

338



Tagged literals

343

Data as code 347
The data-programmable engine 347 Examples of dataprogrammable engines 347 Case study: simple event
sourcing 348




14.4

Code as data as code

357

Hart’s discovery and homoiconicity 358 Clojure code is
data 358 Putting parentheses around the specification 358




14.5

15

Summary

Performance
15.1

362

363

Type hints

364

Advantages of type adornment 364 Type-hinting arguments
and returns 364 Type-hinting objects 366




15.2

Transients

366

Ephemeral garbage 366
mutable collections 367

15.3

Chunked sequences



Transients compare in efficiency to

368

Regaining one-at-a-time laziness

www.it-ebooks.info

370


xvii

CONTENTS

15.4

Memoization

370

Reexamining memoization 371 A memoization protocol
Abstraction-oriented programming 373

371



15.5

Understanding coercion

374

Using primitive longs 375
Using auto-promotion 377

15.6

Reducibles



Using primitive doubles

376

378

An example reducible collection 379 Deriving your first
reducing function transformer 380 More reducing function
transformers 383 Reducible transformers 385 Performance
of reducibles 386 Drawbacks of reducibles 387
Integrating reducibles with Clojure reduce 387 The fold
function: reducing in parallel 389












15.7

16

Summary

392

Thinking programs
16.1

393

A problem of search

394

A brute-force Sudoku solver

16.2

16.3



Thinking data via unification

Declarative is the goal
400

An introduction to core.logic

407

Constraints

407

399

400

Potential equality, or satisfiability
Unification 405
It’s all about unification
Subgoals 411

16.4

394





Substitution

Relations

404

408

414

An introduction to constraint programming 414 Limiting
binding via finite domains 416 Solving Sudoku with finite
domains 418




16.5

17

Summary

421

Clojure changes the way you think
17.1

Thinking in the domain

423

424

A ubiquitous DSL 424 Implementing a SQL-like DSL to
generate queries 426 A note about Clojure’s approach to
DSLs 432




www.it-ebooks.info


xviii

CONTENTS

17.2

Testing 432
Some useful unit-testing techniques
programming 435

17.3

Invisible design patterns

437

Clojure’s first-class design patterns

17.4

437

Error handling and debugging 447
Error handling

17.5

433

Fare thee well

447



Debugging

454

resources 455
index 461

www.it-ebooks.info

450



Contracts


foreword to the second edition
In this second edition of The Joy of Clojure, Michael Fogus and Chris Houser present a
cornucopia of programming concepts, including many of the topics from the
programming languages course we taught together for many years. Fundamental programming languages concepts close to our hearts that appear in this book include
higher-order functions, lexical scope, closures, tail recursion, mutual recursion, continuations and continuation-passing style, trampolining, lazy sequences, macros, and
relational programming. Most important, Fogus and Houser teach you how to define
your own little languages.
Alan J. Perlis, brilliant language designer and inaugural Turing Award recipient,
famously wrote, “There will always be things we wish to say in our programs that in all
known languages can only be said poorly.” No existing programming language can
express precisely those concepts and abstractions needed for your specific application. The only person who can design a language to solve your exact problem is you.
Creating a little language to solve a specific problem is the most effective technique
yet devised for reducing complexity in software.1 Two well-known examples are database query languages and the formula languages of spreadsheet applications. These
examples are as notable for what they exclude as for what they include, illustrating
another of Perlis’s epigrams: “A programming language is low level when its programs
require attention to the irrelevant.” By only including features relevant to the problem, a well-designed little language is inherently high level.
Database query languages illustrate another fundamental aspect of little languages: writing a complete application requires addressing problems in more than
1

Jon Bentley popularized the concept of little languages in his article “Programming Pearls: Little Languages,”
Communications of the ACM 29, no. 8 (1986):711-21.

xix

www.it-ebooks.info


xx

FOREWORD TO THE SECOND EDITION

one domain. An application that performs database queries will also make use of
other languages. A single little language can’t address the exact needs of a nontrivial
application any more than can a single general-purpose language.
For this reason, little languages work best in concert. The ideal technique for writing
a complex program is to slice it into multiple problem-specific pieces and then define
a language for each problem slice. If we slice the program vertically, the result is a
“tower” of languages, layered atop one another. Regardless of how we slice the overall
problem, we can use the right language, and the right paradigm, for each subproblem.
As with recursion, the art of defining little languages encourages—and rewards—
wishful thinking. You might think to yourself, “If only I had a language for expressing
the rules for legal passwords for my login system.” A more involved example—a story,
really—started several years ago, when we thought to ourselves, “If only we had the
right relational language, we could write a Lisp interpreter that runs backward.”2
What does this mean?
An interpreter can be thought of as a function that maps an input expression, such
as (+ 5 1), onto a value—in this case, 6. We wanted to write an interpreter in the style
of a relational database, in which either the expression being interpreted or the value
of that expression, or both, can be treated as unknown variables. We can run the interpreter forward using the query (interpret ‘(+ 5 1) x), which associates the query variable x with the value 6. Better yet, we can run the interpreter backward with the query
(interpret x 6), which associates x with an infinite stream of expressions that evaluate to 6, including (+ 5 1) and ((lambda (n) (* n 2)) 3). (Brainteaser: determine the
behavior of the query (interpret x x).)
Implementing a relational interpreter is tricky, but doing so can be made easier by
using a little language specifically designed for relational programming. In the end,
our wishful thinking led us to build a tower of languages: a relational Lisp interpreter,
on top of a rich relational language, on top of a minimal relational language, on top
of a rich functional language, on top of a minimal functional language.3 (The Lisp
interpreter accepts a minimal functional language, turning the tower of languages
into a circle!) Given the power of this approach, it isn’t surprising that many Lisp
implementations—including the Clojure compiler—are built as layers of languages.
Using what you’ll learn from Fogus and Houser in The Joy of Clojure, you can begin
building your own towers of languages, each with its own syntactic forms and evaluation rules, tailored to your specific problem domains. No technique for software
development is more expressive or more joyful.
WILLIAM E. BYRD AND DANIEL P. FRIEDMAN
Authors of The Reasoned Schemer (MIT Press, 2005)
2

We use Lisp to refer to any member of a large family of languages that includes Scheme, Racket, Common
Lisp, Dylan, and, of course, Clojure. To us, a Lisp must be homoiconic, have first-class functions, and have
some form of macros. (All three concepts are described in this book.)
3 By relational language, we mean a pure logic programming language; or, as in this example, a pure constraint
logic programming language.

www.it-ebooks.info


foreword to the first edition
The authors of this book have taken an ambitious and aggressive approach to teaching Clojure. You know how everyone loves to say they teach using the “drinking from a
fire hydrant” method? Well, at times it feels like these guys are trying to shove that fire
hydrant right up ... let’s just say it’s a place where you don’t normally put a fire
hydrant. This isn’t intended as a first book on programming, and it may not be an
ideal first book on Clojure either. The authors assume you’re fearless and, importantly, equipped with a search engine. You’ll want to have Google handy as you go
through the examples. The authors blaze through many of the classics of both functional programming and industry programming in a whirlwind tour of Clojure that
feels at times more like a class-five tropical storm. You’ll learn fast!
Our industry, the global programming community, is fashion-driven to a degree
that would embarrass haute couture designers from New York to Paris. We’re slaves to
fashion. Fashion dictates the programming languages people study in school, the languages employers hire for, the languages that get to be in books on shelves. A naive
outsider might wonder if the quality of a language matters a little, just a teeny bit at
least, but in the real world fashion trumps all.
So nobody could be more surprised than I that a Lisp dialect has suddenly become
fashionable again. Clojure has only been out for three years, but it’s gaining momentum at a rate that we haven’t seen in a new language in decades. And it doesn’t even
have a “killer app” yet, in the way that browsers pushed JavaScript into the spotlight,
or Rails propelled Ruby. Or maybe the killer app for Clojure is the JVM itself. Everyone’s fed up with the Java language, but understandably we don’t want to abandon
our investment in the Java Virtual Machine and its capabilities: the libraries, the configuration, the monitoring, and all the other entirely valid reasons we still use it.

xxi

www.it-ebooks.info


xxii

FOREWORD TO THE FIRST EDITION

For those of us using the JVM or .NET, Clojure feels like a minor miracle. It’s an
astoundingly high-quality language, sure—in fact, I’m beginning to think it’s the best
I’ve ever seen—yet somehow it has still managed to be fashionable. That’s quite a
trick. It gives me renewed hope for the overall future of productivity in our industry.
We might just dig ourselves out of this hole we’re in and get back to where every project feels like a legacy-free startup, just like it was in the early days of Java.
There are still open questions about Clojure’s suitability for production shops,
especially around the toolchain. That’s normal and expected for a new language. But
Clojure shows so much promise, such beautiful and practical design principles, that
everyone seems to be jumping in with both feet anyway. I certainly am. I haven’t had
this much fun with a new language since Java arrived on the scene 15 years ago. There
have been plenty of pretenders to the JVM throne, languages that promised to take
the Java platform to unprecedented new levels. But until now, none of them had the
right mix of expressiveness, industrial strength, performance, and just plain fun.
I think maybe it’s the “fun” part that’s helped make Clojure fashionable.
In some sense, all this was inevitable, I think. Lisp—the notion of writing your code
directly in tree form—is an idea that’s discovered time and again. People have tried all
sorts of crazy alternatives, writing code in XML or in opaque binary formats or using
cumbersome code generators. But their artificial Byzantine empires always fall into
disrepair or crush themselves into collapse, while Lisp, the road that wanders through
time, remains simple, elegant, and pure. All we needed to get back on that road was a
modern approach, and Rich Hickey has given it to us in Clojure.
The Joy of Clojure just might help make Clojure as fun for you as it is for us.
STEVE YEGGE
Google
steve-yegge.blogspot.com

www.it-ebooks.info


preface
This book is about the programming language Clojure. Specifically, this book is about
how to write Clojure code “The Clojure Way.” Even more specifically, this book is
about how experienced, successful Clojure programmers write Clojure code, and how
the language itself influences the way they create software.
You may be asking yourself, “Who are these guys, and why should I listen to them?”
Rather than simply appealing to an authority that you know nothing about, allow us to
take a few moments to explain how this book came about, who we are, and why we
wrote this book in the first place.
Both of us discovered Clojure early on in its life. It’s safe to say that there were
times when the Clojure IRC channel #clojure (on Freenode) contained only ourselves
along with Clojure’s designer—Rich Hickey—and a handful of other people. Our
story in finding the language is similar to the story of many of its early adopters. That
is, our path runs from modern object-oriented languages4 like Java and C++, through
(seemingly) simpler languages like JavaScript and Python, and then into more powerful languages like Scala and Common Lisp before finding Clojure. The precise details
of how we found Clojure are unimportant; the point is that we were both searching
for something that none of the other languages provided.
What does Clojure provide that none of the other languages can or do? In a nutshell, we think that when you understand Clojure’s nature and write code harmonious
to this nature, a new perspective on the art of programming and systems construction
is revealed. Therefore, the answer to what Clojure provides that those other languages
4

And indeed the younger versions of ourselves were both deeply influenced by the public ponderings of Steve
Yegge and Paul Graham.

xxiii

www.it-ebooks.info


xxiv

PREFACE

don’t is enlightenment (so to speak). We’re not the only ones who feel this way; there
are projects being developed right now that are deeply influenced by Clojure’s nature.
From Datomic to Om5 to Avout to Pedestal, Clojure’s influence is apparent. The
Clojure Way is starting to spread to other programming languages, including (but not
limited to) Scala, Elixir, and Haskell.
In addition to Clojure’s influence in the language design arena, many programmers are using the language every day in their work. The use of Clojure and systems
written in Clojure to solve hard business problems is growing every day. Since we
wrote the first edition, we too have spent our work lives using and learning from
Clojure, and naturally this learning prompted a desire to update this book. Although
the first edition is still relevant from a factual perspective, we felt that a second edition
should include the lessons of our professional use of this amazing language. Nothing
in this book is speculative. Instead, we’ve used every technique and library, from
reducibles to core.logic to data-oriented design, to solve real systems problems.
This book is about the Way of Clojure, written by two programmers who use the
language on a daily basis and have thought long and hard about its nature. We hope
that by thoughtfully reading this book, you can come to an appreciation of Clojure’s
power and importance.

5

Om is also deeply influenced by the works and ideas of Alan Kay and Bret Victor.

www.it-ebooks.info


Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay

×