Professional Clojure - Jeremy Anderson - E-Book

Professional Clojure E-Book

Jeremy Anderson

0,0
38,99 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Clear, practical Clojure for the professional programmer

Professional Clojure is the experienced developer's guide to functional programming using the Clojure language. Designed specifically to meet the needs of professional developers, this book briefly introduces functional programming before skipping directly to the heart of using Clojure in a real-world setting. The discussion details the read—eval—print workflow that enables fast feedback loops, then dives into enterprise-level Clojure development with expert guidance on web services, testing, datomics, performance, and more. Read from beginning to end, this book serves as a clear, direct guide to Clojure programming—but the comprehensive coverage and detail makes it extraordinarily useful as a quick reference for mid-project snags. The author team includes four professional Clojure developers, ensuring professional-level instruction from a highly practical perspective.

Clojure is an open-source programming language maintained and supported by Cognitect., and quickly gaining use across industries at companies like Amazon, Walmart, Facebook, Netflix, and more. This guide provides a concise, yet thorough resource for professional developers needing to quickly put Clojure to work.

  • Parse the difference between functional and object-oriented programming
  • Understand Clojure performance and capabilities
  • Develop reactive web pages using ClojureScript
  • Adopt an REPL-driven development workflow

Clojure is a modern dialect of Lisp, designed for concurrency and Java compatibility. It can be used with the Java virtual machine, Microsoft's Common Language Runtime, and JavaScript engines, providing a level of both versatility and functionality that is appealing to more and more enterprise-level developers. As requirements grow increasingly complex, stepping away from imperative programming can dramatically streamline the development workflow. Professional Clojure provides the expert instruction that gets professionals up to speed and back to work quickly.

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 421

Veröffentlichungsjahr: 2016

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Table of Contents

Title Page

Introduction

What Is Clojure?

Who Is This Book For?

What Will You Learn?

Tools You Will Need

Conventions

Source Code

Errata

p2p.wrox.com

Chapter 1: Have a Beginner's Mind

Functional Thinking

Doing Object-Oriented Better

Persistent Data Structures

Shaping the Language

Summary

Chapter 2: Rapid Feedback Cycles with Clojure

REPL-Driven Development

Reloading Code

Summary

Chapter 3: Web Services

Project Overview

Elements of a Web Service

Example Service

Deployment

Summary

Chapter 4: Testing

Testing Basics with clojure.test

Testing Strategies

Measuring Code Quality

Testing Framework Alternatives

Summary

Chapter 5: Reactive Web Pages in ClojureScript

ClojureScript Is a Big Deal

A First Brush with ClojureScript

Reagent in Depth

Testing Components with Devcards

Interop with JavaScript

One Language, One Idiom, Many Platforms

Things to Know about the Closure Compiler and Library

Modeling State with DataScript

Go Routines in Your Browser with core.async

Summary

Chapter 6: The Datomic Database

Datomic Basics

Modeling Application Data

Datomic's Clojure API

Building Applications with Datomic

Summary

Chapter 7: Performance

What Is Performance?

Choosing the Right Data Structure Is a Prerequisite for Performance

Benchmarking

Parallelism

Memoization

Inlining

Safe Mutation with Transients

Profiling

Avoiding Reflection with Type Hinting

Java Flags

Math

Summary

End User License Agreement

Pages

iv

v

vi

vii

ix

xv

xvi

xvii

xviii

xix

xx

xxi

i

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

Guide

Cover

Table of Contents

Begin Reading

List of Illustrations

Chapter 1: Have a Beginner's Mind

Figure 1.1

Figure 1.2

Figure 1.3

Figure 1.4

Figure 1.5

Figure 1.6

Figure 1.7

Chapter 2: Rapid Feedback Cycles with Clojure

Figure 2.1

Chapter 3: Web Services

Figure 3.1

Figure 3.2

Chapter 4: Testing

Figure 4.1

Figure 4.2

Figure 4.3

Chapter 5: Reactive Web Pages in ClojureScript

Figure 5.1

Figure 5.2

Figure 5.3

Figure 5.4

Figure 5.5

Figure 5.6

Figure 5.7

Figure 5.8

Figure 5.9

Figure 5.10

Figure 5.11

Figure 5.12

Figure 5.13

Figure 5.14

Figure 5.15

Figure 5.16

Figure 5.17

Chapter 6: The Datomic Database

Figure 6.1

Chapter 7: Performance

Figure 7.1

List of Tables

Chapter 1: Have a Beginner's Mind

Table 1.1 deftypes and defrecords

Chapter 6: The Datomic Database

Table 6.1 Table of contacts

PROFESSIONALClojure

Jeremy AndersonMichael GaareJustin HolguínNick BaileyTimothy Pratley

 

INTRODUCTION

WHAT IS CLOJURE?

Clojure is a dynamic, general-purpose programming language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language, yet remains completely dynamic—every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.

Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system. Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. When mutable state is needed, Clojure offers a software transactional memory system and reactive Agent system that ensure clean, correct, multithreaded designs.

—Rich Hickey, author of Clojure

This quote from Rich Hickey, the creator of Clojure, captures what Clojure is. Many people equate Clojure with functional programming, but much like Lisp, its predecessor, it's a general-purpose language that will support you no matter what paradigm you decide to program in.

Clojure is, however, very opinionated and offers great support for programming in a functional manner, with its focus on immutable values and persistent data structures. You may be surprised to know that Clojure also offers the ability to do object-oriented programming, which we cover in this book.

WHO IS THIS BOOK FOR?

This book was written with the professional programmer in mind. This means you should have experience programming in a language, and you should know the basic syntax and concepts in Clojure, and be ready to take Clojure programming to the next level. Our goal is to take you from a Clojure beginner to being able to think like a Clojure developer. Learning Clojure is much more than just learning a new syntax. You must use tools and constructs much differentely than anything you may be familiar with.

DEMO APPLICATION SOURCE CODE

You can access the source code from the Wiley website at www.wiley.com/go/professionalclojure or at our demo application via Github at https://github.com/backstopmedia/clojurebook.

A powerful programming language is more than just a means for instructing a computer to perform tasks. The language also serves as a framework within which we organize our ideas about processes.

—Structure and Interpretation of Computer Programs

This book assumes some prior knowledge of Clojure and programming in general, but does not assume proficiency in Clojure. It will cover a broad scope of topics from changing the way you think and approach programming to how you integrate the REPL into your normal development routine to how you build real world applications using Ring and ClojureScript.

WHAT WILL YOU LEARN?

Our goal is to provide you with some real world examples of how to apply your Clojure knowledge to your day-to-day programming, not just theory and academia.

Chapter 1

In Chapter 1, you will learn about Clojure's unique view on designing programs. You'll discover some of the things that set Clojure apart from other languages, for example, how immutability is the default, and how Clojure qualifies as object-oriented programming.

Chapter 2

In Chapter 2, you will learn how to become proficient with the REPL and various tips and techniques for interacting with your actual application through the REPL. You'll learn how to run your code and tests from the REPL as well as how to write code that is easily reloaded from the REPL without having to restart it.

Chapter 3

In Chapter 3, you learn about building web services with Compojure, and the various concepts involved such as routes, handlers, and middleware. You will build a complete web service, and then learn various techniques for deploying your new application.

Chapter 4

Chapter 4 covers testing in Clojure, focusing primarily on the clojure.test testing library. You'll learn various techniques for many common testing scenarios, along with tools to help measure the quality of your code.

Chapter 5

In Chapter 5, you will learn how to build a task management web application similar to the popular Trello application in ClojureScript. You'll also learn the techniques for sharing functions between both your server-side and client-side applications.

Chapter 6

Chapter 6 takes a look at Datomic and how it applies the concept of immutability to databases. You'll learn the basics of how to model data in a Datomic database and how to extract that information. Then you'll apply this knowledge to building a database to support the task management application from Chapter 5.

Chapter 7

In Chapter 7, you'll take a look at performance and how to make your Clojure code execute faster. You'll discover how with a little work you can tweak your Clojure code to be as fast as Java code.

TOOLS YOU WILL NEED

Just as in any good adventure or journey, having the right tools makes things go much smoother. Fortunately, to work through the examples in this book, you only need three things: Java, Leiningen, and a good text editor.

Java

Most computers these days come with Java pre-installed, but in order to run the examples contained in this book you need to make sure you have installed a recent version. The code examples in this book were written with and confirmed to work with JDK 1.8.0_25. For instructions on how to download and install the proper JDK for your platform, see the documentation at Oracle's JDK download page: (http://www.oracle.com/technetwork/java/javase/downloads/index.html).

Leiningen

Leiningen, according to their website (http://leiningen.org), is the most contributed-to Clojure project. For those of you coming from a background in Java, Leiningen fills a similar role that Maven does for the Java world, only without all of the XML, and you can avoid wanting to pull your hair out. It helps you manage the dependencies for your project and declaratively describe your project and configuration, and provides access to a wealth of plugins for everything from code analysis to automation, and more. Leiningen makes your Clojure experience much more enjoyable.

Fortunately, getting Leiningen up and running is a fairly simple task. You'll want to install the latest version available, which at the time of this writing is 2.5.3. Please refer to the Leiningen website for instructions particular to your programming environment.

Editors

Once you have Leiningen installed, the only thing left to do is to make sure you have a good text editor to efficiently edit your Clojure code. If you have a favorite editor, just use what you're already comfortable with. However, if your editor doesn't support basic things like parentheses balancing, integration with the REPL, syntax highlighting, or properly indenting Clojure code, you may want to consider one of the editors below.

Emacs

Emacs is the favored editor of many grizzled veterans. It has a long history with Lisp. Even though it has a steep learning curve, it is considered by many to be very powerful, and no other editor is as extensible. There are many custom Emacs configurations designed to help ease the learning curve, such as Emacs Prelude (https://github.com/bbatsov/prelude), which also contains a sensible default configuration for developing in many languages, including Clojure.

LightTable

LightTable (http://lighttable.com) began life as a Kickstarter project with a unique new vision of how to integrate the code editor, REPL, and documentation browser for Clojure. It has delivered on those promises and then some and has gained popularity among many in the Clojure community.

Cursive (IntelliJ)

If you're already comfortable with using any of the various JetBrains IDEs, you'll be happy to know that there is a plugin for IntelliJ called Cursive (https://cursive-ide.com). Besides having good integration with nREPL, it also stays true to its reputation and contains excellent refactoring support, as well as debugging and Java interop.

Counterclockwise (Eclipse)

For those who are familiar with Eclipse, there is Counterclockwise (http://doc.ccw-ide.org), which can be installed as either an Eclipse plugin or a standalone product. Counterclockwise boasts many of the same features as the previous editors, integration with the REPL, and ability to evaluate code inline.

CONVENTIONS

To help you get the most from the text and keep track of what's happening, we've used a number of conventions throughout the book.

NOTE

Notes indicates notes, tips, hints, tricks, and/or asides to the current discussion.

As for styles in the text:

We

highlight

new terms and important words when we introduce them.

We show code within the text like so:

persistence.properties

.

We show all code snippets in the book using this style:

FileSystem fs = FileSystem.get(URI.create(uri), conf); InputStream in = null; try {

URLs in text appear like this: http://<Slave Hostname>:50075.

SOURCE CODE

As you work through the examples in this book, you may choose either to type in all the code manually, or to use the source code files that accompany the book. All of the source code used in this book is available for download at www.wiley.com. Specifically for this book, the code download is on the Download Code tab at:

www.wiley.com/go/professionalclojure

You can also search for the book at www.wrox.com by ISBN (the ISBN for this book is 9781119267171 to find the code. And a complete list of code downloads for all current Wrox books is available at www.wiley.com/dynamic/books/download.aspx.

NOTE

Because many books have similar titles, you may find it easiest to search by ISBN; this book's ISBN is 978-1-119-26727-0.

Once you download the code, just decompress it with your favorite compression tool. Alternately, you can go to the main Wrox code download page at www.wrox.com/dynamic/books/download.aspx to see the code available for this book and all other Wrox books.

ERRATA

We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata, you may save another reader hours of frustration, and at the same time, you will be helping us provide even higher quality information.

To find the errata page for this book, go to www.wiley.com/go/ and click the Errata link. On this page you can view all errata that has been submitted for this book and posted by Wrox editors.

If you don't spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport.shtml and complete the form there to send us the error you have found. We'll check the information and, if appropriate, post a message to the book's errata page and fix the problem in subsequent editions of the book.

P2P.WROX.COM

For author and peer discussion, join the P2P forums at http://p2p.wrox.com. The forums are a web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums.

At http://p2p.wrox.com, you will find a number of different forums that will help you, not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:

Go to

http://p2p.wrox.com

and click the Register link.

Read the terms of use and click Agree.

Complete the required information to join, as well as any optional information you wish to provide, and click Submit.

You will receive an e-mail with information describing how to verify your account and complete the joining process.

NOTE

You can read messages in the forums without joining P2P, but in order to post your own messages, you must join.

Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to This Forum icon by the forum name in the forum listing.

For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works, as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.

Chapter 1Have a Beginner's Mind

WHAT'S IN THIS CHAPTER?

Understanding the differences between imperative and functional programming

Learning how to think more functionally

Discovering Clojure's unique perspective on object-oriented programming

If your mind is empty, it is always ready for anything, it is open to everything. In the beginner's mind there are many possibilities, but in the expert's mind there are few.

—Shunryu Suzuki

Over the past thirty years many popular programming languages have more in common with each other than they have differences. In fact, you could argue that once you have learned one language, it's not difficult to learn another. You merely have to master the subtle differences in syntax, and maybe understand a new feature that isn't present in the language that you're familiar with. It's not difficult to call yourself a polyglot programmer when many of the top languages in use today are all so similar.

Clojure, on the other hand, comes from a completely different lineage than most of the popular languages in use today. Clojure belongs to the Lisp family of programming languages, which has a very different syntax and programming style than the C-based languages you are probably familiar with. You must leave all of your programming preconceptions behind in order to gain the most from learning Clojure, or any Lisp language in general.

Forget everything you know, or think you know about programming, and instead approach it as if you were learning your very first programming language. Otherwise, you'll just be learning a new syntax, and your Clojure code will look more like Java/C/Ruby and less like Clojure is designed to look. Learning Clojure/Lisp will even affect the way you write in other languages, especially with Java 8 and Scala becoming more popular.

FUNCTIONAL THINKING

C, C++, C#, Java, Python, Ruby, and even to some extent Perl, all have very similar syntax. They make use of the same programming constructs and have an emphasis on an imperative style of programming. This is a style of programming well suited to the von Neumann architecture of computing that they were designed to execute in. This is probably most apparent in the C language, where you are responsible for allocating and de-allocating memory for variables, and dealing directly with pointers to memory locations. Other imperative languages attempt to hide this complexity with varying degrees of success.

In computer science, imperative programming is a programming paradigm that uses statements that change a program's state.

This C-style of programming has dominated the programming scene for a very long time, because it fits well within the dominant hardware architectural paradigm. Programs are able to execute very efficiently, and also make efficient use of memory, which up until recently had been a very real constraint. This efficiency comes at the cost of having more complex semantics and syntax, and it is increasingly more difficult to reason about the execution, because it is so dependent upon the state of the memory at the time of execution. This makes doing concurrency incredibly difficult and error prone. In these days of cheap memory and an ever growing number of multiple core architectures, it is starting to show its age.

Functional programming, however, is based on mathematical concepts, rather than any given computing architecture. Clojure, in the spirit of Lisp, calls itself a general-purpose language; however, it does provide a number of functional features and supports the functional style of programming very well. Clojure as a language not only offers simpler semantics than its imperative predecessors, but it also has arguably a much simpler syntax. If you are not familiar with Lisp, reading and understanding Clojure code is going to take some practice. Because of its heavy focus on immutability, it makes concurrency simple and much less error prone than having to manually manage locks on memory and having to worry about multiple threads reading values simultaneously. Not only does Clojure provide all of these functional features, but it also performs object-oriented programming better than its Java counterpart.

Value Oriented

Clojure promotes a style of programming commonly called “value-oriented programming.” Clojure's creator, Rich Hickey, isn't the first person to use that phrase to describe functional programming, but he does an excellent job explaining it in a talk titled The Value of Values that he gave at Jax Conf in 2012 (https://www.youtube.com/watch?v=-6BsiVyC1kM).

By promoting this style of value-oriented programming, we are focused more on the values than mutable objects, which are merely abstractions of places in memory and their current state. Mutation belongs in comic books, and has no place in programming. This is extremely powerful, because it allows you to not have to concern yourself with worrying about who is accessing your data and when. Since you are not worried about what code is accessing your data, concurrency now becomes much more trivial than it ever was in any of the imperative languages.

One common practice when programming in an imperative language is to defensively make a copy of any object passed into a method to ensure that the data does not get altered while trying to use it. Another side effect of focusing on values and immutability is that this practice is no longer necessary. Imagine the amount of code you will no longer have to maintain because you'll be using Clojure.

In object-oriented programming, we are largely concerned with information hiding or restricting access to an object's data through encapsulation. Clojure removes the need for encapsulation because of its focus on dealing with values instead of mutable objects. The data becomes semantically transparent, removing the need for strict control over data. This level of transparency allows you to reason about the code, because you can now simplify complex functions using the substitution model for procedure application as shown in the following canonical example. Here we simplify a function called sum-of-squares through substituting the values:

(defn square [a] (* a a)) (defn sum-of-squares [a b] (+ (square a) (square b)) ; evaluate the expression (sum-of-squares 4 5) (sum-of-squares 4 5) (+ (square 4) (square 5)) (+ (* 4 4) (* 5 5)) (+ 16 25) 41

By favoring functions that are referentially transparent, you can take advantage of a feature called memorization. You can tell Clojure to cache the value of some potentially expensive computation, resulting in faster execution. To illustrate this, we'll use the Fibonacci sequence, adapted for Clojure, as an example taken from the classic MIT text Structure and Interpretation of Computer Programs (SICP).

(defn fib [n] (cond (= n 0) 0 (= n 1) 1 :else (+ (fib (- n 1)) (fib (- n 2)))))

If you look at the tree of execution and evaluate the function for the value of 5, you can see that in order to calculate the fifth Fibonacci number, you need to call (fib 4) and (fib 3). Then, to calculate (fib 4), you need to call (fib 3) and (fib 2). That's quite a bit of recalculating values that you already know the answer to (see Figure 1.1).

Figure 1.1

Calculating for (fib 5) executes quickly, but when you try to calculate for (fib 42) you can see that it takes considerably longer.

(time (fib 42)) "Elapsed time: 11184.49583 msecs" 267914296

You can rewrite a function to leverage memorization to see a significant improvement in the execution time. The updated code is shown here:

(def memoized-fib (memoize (fn [n] (cond (= n 0) 0 (= n 1) 1 :else (+ (fib (- n 1)) (fib (- n 2)))))))

When you first run this function, you'll see how the execution doesn't happen any faster; however, each subsequent execution instantaneously happens.

user> (time (memoized-fib 42)) "Elapsed time: 10586.656667 msecs" 267914296 user> (time (memoized-fib 42)) "Elapsed time: 0.10272 msecs" 267914296 user> (time (memoized-fib 42)) "Elapsed time: 0.066446 msecs" 267914296

This is a risky enhancement if you do this with a function that relies on a mutable shared state. However, since our functions are focused on values, and are referentially transparent, you can leverage some cool features provided by the Clojure language.

Thinking Recursively

Recursion is not something that is taught much in most imperative languages. Contrast this with most functional languages, and how they embrace recursion, and you will think more recursively. If you are unfamiliar with recursion, or struggle to understand how to think recursively, you should read The Little Schemer, by Daniel P. Friedman and Matthias Felleisen. It walks you through how to write recursive functions using a Socratic style of teaching, where the two authors are engaged in a conversation and you get to listen in and learn.

Let's take a look at a trivial example of calculating a factorial. A typical example in Java might look like the code shown below. You start by creating a local variable to store the ultimate result. Then, loop over every number, one-by-one, until you reach the target number, multiplying the last result by the counter variable defined by the for loop, and mutating the local variable.

public long factorial(int n) { long product = 1; for ( int i = 1; i <= n; i++ ) { product *= i; } return product; }

Because of Clojure's focus on values and immutable structures, it relies on recursion for looping and iteration. A naïve recursive definition of a factorial in Clojure may look like the following:

(defn factorial [n] (if (= n 1) 1 (* n (factorial (- n 1)))))

If you trace the execution of the factorial program with an input of 6, as shown next, you see that the JVM needs to maintain each successive operation on the stack as n increases, until the factorial reaches a point where it returns a value instead of recurring. If you're not careful, you'll likely end up with a stack overflow. This style of recursion is often called linear recursion.

(factorial 6) (* 6 (factorial 5)) (* 6 (* 5 (factorial 4))) (* 6 (* 5 (* 4 (factorial 3)))) (* 6 (* 5 (* 4 (* 3 (factorial 2))))) (* 6 (* 5 (* 4 (* 3 (* 2 (factorial 1)))))) (* 6 (* 5 (* 4 (* 3 (* 2 1))))) (* 6 (* 5 (* 4 (* 3 2)))) (* 6 (* 5 (* 4 6))) (* 6 (* 5 24)) (* 6 120) 720

To resolve this dilemma, rewrite your function in a tail recursive style using the special operator called recur, which according to the documentation, “does constant-space recursive looping by rebinding and jumping to the nearest enclosing loop or function frame.” This means that it tries to simulate a tail call optimization, which the JVM doesn't support. If you rewrite the preceding factorial example using this style, it looks something like the following:

(defn factorial2 [n] (loop [count n acc 1] (if (zero? count) acc (recur (dec count) (* acc count)))))

In this version of the factorial function, you can define an anonymous lambda expression using the loop construct, thus providing the initial bindings for the local variables count to be the value passed into the factorial function to start the accumulator at 1. The rest of the function merely consists of a conditional that checks the base case and returns the current accumulator, or makes a recursive call using recur. Notice how in the tail position of the function this program doesn't require the runtime to keep track of any previous state, and can simply call recur with the calculated values. You can trace the execution of this improved version of the factorial as seen here:

(factorial2 6) (loop 6 1) (loop 5 6) (loop 4 30) (loop 3 120) (loop 2 360) (loop 1 720) 720

The call to factorial2 take fewer instructions to finish, but it doesn't need to place new calls on the stack for each iteration, like the first version of factorial did.

But what happens if you need to perform mutual recursion? Perhaps you want to create your own version of the functions for determining if a number is odd or even. You could define them in terms of each other. A number is defined as being even if the decrement of itself is considered odd. This will recursively call itself until it reaches the magic number of 0, so at that point if the number is even it will return true. If it's odd it will return false. The code for the mutually recursive functions for my-odd? and my-even? are defined here:

(declare my-odd? my-even?) (defn my-odd? [n] (if (= n 0) false (my-even? (dec n)))) (defn my-even? [n] (if (= n 0) true (my-odd? (dec n))))

This example suffers from the same issue found in the first example, in that each successive recursive call needs to store some sort of state on the stack in order to perform the calculation, resulting in a stack overflow for large values. The way you avoid this problem is to use another special operator called trampoline, and modify the original code to return functions wrapping the calls to your recursive functions, like the following example:

(declare my-odd? my-even?) (defn my-odd? [n] (if (= n 0) false #(my-even? (dec n)))) (defn my-even? [n] (if (= n 0) true *(my-odd? (dec n))))

Notice the declare function on the first line. We can call the function using the trampoline operator as shown here:

(trampoline my-even? 42)

If the call to a function, in this case my-even?, would return another function, trampoline will continue to call the returned functions until an atomic value gets returned. This allows you to make mutually recursive calls to functions, and not worry about blowing the stack. However, we're still left with one problem. If someone wishes to use the version of my-even? and my-odd?, they must have prior knowledge to know they must call them using trampoline. To fix that you can rewrite the functions:

(defn my-even? [n] (letfn [(e? [n] (if (= n 0) true #(o? (dec n)))) (o? [n] (if (= n 0) false #(e? (dec n))))] (trampoline e? n))) (defn my-odd? [n] (not (my-even? n)))

We've effectively hidden away the knowledge of having to use trampoline from our users.

Higher Order Functions

One of the many qualities that define a language as being functional is the ability to treat functions as first class objects. That means functions can not only take values as parameters and return values, but they can also take functions as parameters as well. Clojure comes with a number of commonly used higher order functions such as map, filter, reduce, remove and iterate, as well as providing you with the tools to create your own.

In Java, for example, if you want to filter a list of customers that live in a specific state, you need to create a variable to hold the list of filtered customers, manually iterate through the list of customers, and manually add them to the local variable you created earlier. You have to specify not only what you want to filter by, but also how to iterate through the list.

public List<Customer> filterByState(List<Customer> input, String state) { List<Customer> filteredCustomers = new ArrayList<>(); for(Customer customer : input) { if (customer.getState().equals(state)) { filteredCustomers.put(customer); } } return filteredCustomers; }

This Clojure example deals less with how to do the filtering, and is a bit more concise and declarative. The syntax may look a little strange, but you are simply calling the filter function with an anonymous function telling what you should filter on and finally the sequence you want to filter with.

(def customers [{:state "CA" :name "Todd"} {:state "MI" :name "Jeremy"} {:state "CA" :name "Lisa"} {:state "NC" :name "Rich"}]) (filter #(= "CA" (:state %)) customers)

One common design pattern that exists in object-oriented programming, the Command pattern, exists as a way to cope with the lack of first class functions and higher order functions. To implement the pattern, you first define an interface that defines a single method for executing the command, a sort of pseudo-functional object. Then you can pass this Command object to a method to be called at the appropriate time. The downfall of this is that you need to either define several concrete implementations to cover every possible piece of functionality you would need to execute, or define an anonymous inner class wrapping the functionality.

public void wrapInTransaction(Command c) throws Exception { setupDataInfrastructure(); try { c.execute(); completeTransaction(); } catch (Exception condition) { rollbackTransaction(); throw condition; } finally { cleanUp(); } } public void addOrderFrom(final ShoppingCart cart, final String userName, final Order order) throws Exception { wrapInTransaction(new Command() { public void execute() { add(order, userKeyBasedOn(userName)); addLineItemsFrom(cart, order.getOrderKey()); } }); }

In Clojure you have the ability to pass functions around the same as any other value, or if you just need to declare something inline you can leverage anonymous lambda expressions. You can rewrite the previous example in Clojure to look like this code:

(defn wrapInTransaction [f] (do (startTransaction) (f) (completeTransaction))) (wrapInTransaction #( (do (add order user) (addLineItemsFrom cart orderKey))))

To put it another way, with imperative languages you usually have to be more concerned with how you do things, and in Clojure you're able to focus more on the what you want to do. You can define abstractions at a different level than what is possible in most imperative languages.

Partials

In object-oriented programming there are many patterns for building up objects in steps by using the Builder Pattern, or many related types of objects using the Abstract Factory Pattern. In Clojure, since the primary method of abstraction is the function, you also have a mechanism to build new functions out of existing ones with some of the arguments fixed to a value by using partial.

The canonical example of how to use partial, shown here is a bit trivial.

(def add2 (partial + 2))

For a better example, we'll take a look at the clojure.java.jdbc library. In the following listing is an example showing a typical pattern for defining the connection properties for your database, and a few simple query wrappers. Notice how every call to jdbc/query and jdbc/insert! takes the spec as its first parameter.

(ns sampledb.data (:require [clojure.java.jdbc :as jdbc])) (def spec {:classname "org.postgresql.Driver" :subprotocol "postgresql" :subname "//localhost:5432/sampledb"}) (defn all-users [] (jdbc/query spec ["select * from login order by username desc"]))) (defn find-user [username] (jdbc/query spec ["select * from login where username = ?" username])) (defn create-user [username password] (jdbc/insert! spec :login {:username username :password password :salt "some_salt"}))

There is a bit too much repetition in this example, and it only contains three functions for querying the database. Imagine how many times this occurs in a non-trivial application. You can remove this duplication by using partial, and creating a new function with this first parameter already bound to the spec variable as shown here:

(ns sampledb.data (:require [clojure.java.jdbc :as jdbc])) (def spec {:classname "org.postgresql.Driver" :subprotocol "postgresql" :subname "//localhost:5432/sampledb"}) (def query (partial jdbc/query spec)) (def insert! (partial jdbc/insert! spec)) (defn all-users [] (query ["select * from login order by username desc"]))) (defn find-user [username] (query ["select * from login where username = ?" username])) (defn create-user [username password] (insert! :login {:username username :password password :salt "some_salt"}))

Another useful way to use partial is for one of the higher order functions such as map, which expects a function with exactly one argument to apply to the objects in a collection. You can use partial to easily take a function that would normally require more than one argument and create a new one specifying any number of them so that it now only requires one. For example, the * function used for multiplying numbers doesn't make much sense with only one argument, but you can use partial to specify what you want to multiply each item by as shown here:

(defn apply-sales-tax [items] ((map (partial * 1.06) items)))

The only real downside to partial is that you are only able to bind values to parameters in order, meaning that the parameter order is important. If you want to bind the last parameter to a function, you can't leverage partial. Instead, you can define another function that wraps the original function call or leverages a lambda expression.

Function Composition

Another useful piece of functionality is the ability to compose multiple functions together to make a new function. Once again, Clojure shows its functional roots based in mathematics. As an example, if you had a function called f and another called g, you could compose them together such that the output from f is fed as the input to g, in the same way you can leverage pipes and redirects on the Unix command line and compose several functions together. More specifically, if you have a function call that looks like (g (f (x)), you can rewrite it to read as ((comp g f) x).

To provide a more practical example, say you wanted to minify some JavaScript, or read in a JavaScript file and remove all of the new lines and extra whitespace, so that it requires less information to transfer from the server to the browser. You can accomplish this task by composing the common string functions provided by Clojure, str/join, str/trim, str/split-lines, as shown here:

(defn minify [input] (str/join (map str/trim (str/split-lines input))))

This can then be rewritten using the comp function to look like the following:

(def minify (comp str/join (partial map str/trim) str/split-lines))

Notice how the ordering of the functions passed to comp retain their original order of the last function being applied first, working your way back to the beginning of the list. Also we modified it a bit to leverage partial with the map and str/trim functions, to create a function that operates on a collection, since str/trim only operates on a single string.

Embracing Laziness

Clojure itself is not considered to be a lazy language in the same sense that a language like Haskell is; however, it does provide support for creating and using lazy sequences. In fact, most of the built in functions like map, filter, and reduce generate lazy sequences for you without you probably even knowing it. You can see this here:

user> (def result (map (fn [i] (println ".") (inc i)) '[0 1 2 3])) #'user/result user> result . . . . (1 2 3 4)

When you evaluate the first expression, you don't see any output printed to the console. Had this been a non-lazy sequence, you would have seen the output printed to the screen immediately, because it would have evaluated the println expression at the time of building the sequence. Instead, the output is not printed until you ask Clojure to show you what is in the result symbol, and it has to fully realize what's inside the sequence. This is exceptionally useful, because the computation inside the function that you pass to map may contain some fairly expensive operation, and that expensive operation by itself may not be an issue. Yet, when the operation is executed, the execution of your application can be slowed by several or even hundreds of times.

Another useful example of a lazy sequence in action is when representing an infinite set of numbers. If you have a set of all real numbers, or a set of all prime numbers, you can set all of these numbers in the Fibonacci sequence as shown here.

(def fib-seq (lazy-cat [1 1] (map + (rest fib-seq) fib-seq))) (take 10 fib-seq) -> (1 1 2 3 5 8 13 21 34 55)

This sequence is defined using a lazy sequence, and next you will ask Clojure to give you the first 10 numbers in a sequence. In a language that did not support this level of laziness, this type of data modeling would simply not be possible.

Another example of how this can be useful is by infinitely cycling through a finite collection. For example, if you want to assign an ordinal value to every value in a collection for an example group of a list of people into four groups, you can write something similar to the following:

(def names '["Christia" "Arline" "Bethann" "Keva" "Arnold" "Germaine" "Tanisha" "Jenny" "Erma" "Magdalen" "Carmelia" "Joana" "Violeta" "Gianna" "Shad" "Joe" "Justin" "Donella" "Raeann" "Karoline"]) user> (mapv #(vector %1 %2) (cycle '[:first :second :third :fourth]) names) [[:first "Christia"] [:second "Arline"] [:third "Bethann"] [:fourth "Keva"] [:first "Arnold"] [:second "Germaine"] [:third "Tanisha"] [:fourth "Jenny"] [:first "Erma"] [:second "Magdalen"] [:third "Carmelia"] [:fourth "Joana"] [:first "Violeta"] [:second "Gianna"] [:third "Shad"] [:fourth "Joe"] [:first "Justin"] [:second "Donella"] [:third "Raeann"] [:fourth "Karoline"]]

If you map over multiple collections, you will apply the function provided to the first item in the first collection, the first item in each successive collection, and then the second and so forth, until one of the collections is completely exhausted. So, in order to map the values :first, :second, :third, and :fourth repeatedly over all the names, without having to know how many names exist in the collection, you must find a way to cycle over and over repeatedly through the collection. This is what cycle and infinite lazy collections excel at.

When You Really Do Need to Mutate

Just because Clojure favors dealing with values doesn't mean you completely do away with mutable state. It just means you greatly limit mutable state, and instead use quarantine in your specific area of code. Clojure provides a few mechanisms to manage mutable state.

Atoms

Using Atoms is the first and simplest mechanism for handling mutable state provided by Clojure. Atoms provide you with a means to manage some shared state in a synchronous, uncoordinated, or independent manner. So, if you need to only manage a single piece of mutable state at a time, then Atoms are the tool you need.

Up to this point, we've primarily focused on values; however, Atoms are defined and used in a different way. Since Atoms represent something that can potentially change, out of necessity they must represent some reference to an immutable structure. An example of how to define an Atom is shown here.

user> (def app-state (atom {})) #'user/app-state user> app-state #atom[{} 0x1f5b7bd9]

We've defined an Atom containing an empty map with a stored reference in app-state. As you can see by the output in the repl, the Atom stores a memory location to the map. Right now it doesn't do a whole lot, so let's associate some values into the map.

user> (swap! app-state assoc :current-user "Jeremy") {:current-user "Jeremy"} user> app-state #atom[{:current-user "Jeremy"} 0x1f5b7bd9] user> (swap! app-state assoc :session-id "some-session-id") {:current-user "Jeremy", :session-id "some-session-id"} user> app-state #atom[{:current-user "Jeremy", :session-id "some-session-id"} 0x1f5b7bd9]

To modify app-state, Clojure provides you with two different functions called swap! and reset!, both of which atomically modify the value pointed to by the app-state reference. The swap! function is designed to take a function that will operate on the value stored in the reference, and will swap out the value with the value returned as a result of executing the function. In the preceding example we provided swap! with the assoc function to associate a new value into the map for a given keyword.

To simply replace the value referenced in app-state you can use the reset! function, and provide it with a new value to store in the Atom as shown here:

user> (reset! app-state {}) {} user> app-state #atom[{} 0x1f5b7bd9]

You can see that the app-state now references an empty map again.

Now that you know how to store the shared state in your Atom, you may be wondering how you get the values back out. In order to access the state stored in your Atom, use the deref/@ reader macro as shown here:

user> (swap! app-state assoc :current-user "Jeremy" :session-id "some-session-id") {:current-user "Jeremy", :session-id "some-session-id"} user> (:current-user @app-state) "Jeremy" user> (:session-id @app-state) "some-session-id" user> (:foo @app-state :not-found) :not-found

Once you de-reference your Atom using the deref/@ reader macro, you can then interact with your app-state, just as if it were a map again.

Refs

While Atoms provide you with a means to manage some shared mutable state for a single value, they are limited by the fact that if you need to coordinate changes between multiple objects, such as the classic example of transferring money from one account to another, you need to use transaction references or Refs for short. Transaction references operate similar to how you would expect database transactions to use a concurrency model called Software Transactional Memory, or STM. In fact, Refs fulfill the first three parts required for ACID compliancy: Atomicity, Consistency, and Isolation. Clojure does not concern itself with Durability, however, since the transactions occur in memory.

To illustrate why you can't just use Atoms for coordinated access, consider the following example.

user> (def savings (atom {:balance 500})) #'user/savings user> (def checking (atom {:balance 250})) #'user/checking user> (do (swap! checking assoc :balance 700) (throw (Exception. "Oops...")) (swap! savings assoc :balance 50)) Exception Oops... user/eval9580 (form-init1334561956148131819.clj:66) user> (:balance @checking) 700 user> (:balance @savings) 500

Here two Atoms called savings and checking are defined, and we attempt to modify both of them in a do block. We are, however, throwing an exception in between updating the two Atoms. This causes our two accounts to get out of sync. Next, let's look at the same example using Refs.

user> (def checking (ref {:balance 500})) #'user/checking user> (def savings (ref {:balance 250})) #'user/savings user> (dosync (commute checking assoc :balance 700) (throw (Exception. "Oops...")) (commute savings assoc :balance 50)) Exception Oops... user/eval9586/fn--9587 (form-init1334561956148131819.clj:6) user> (:balance @checking) 500 user> (:balance @savings) 250

As you can see, you create Refs and read values out of them similar to how we did that with Atoms earlier. There are a few minor differences, however, in how you update the value stored in the Ref. We use commute rather than swap!, and all update operations must perform on the Refs within a dosync block.

Nil Punning

If you're at all experienced in Java, you are very familiar with the dreaded NullPointerException. It's probably one of the most prolific errors encountered when developing in Java, so much so that the inventor of the Null reference, Tony Hoare, even gave a talk several years ago stating how big of a mistake it was (http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare). It seems odd that everything else, with the exception of primitive values, is an Object, except for null. This has led to several workarounds in languages, such as Optional in Java, null safe object navigation in Groovy, and even in Objective-C you send messages to nil and then just happily ignore them.

Clojure, being a Lisp, adopts the philosophy of nil punning. Unlike Java, nil has a value, and it simply means “no answer.” It can also mean different things in different contexts.

When evaluated as a Boolean expression, like many other dynamic typed languages, it will be equivalent to false.

user> (if nil "true" "false") "false"

nil can also be treated like an empty Seq. If you call first on nil, you get a returned nil, because there is no first element. If you then call last on nil, you also unsurprisingly get nil. However, don't assume that nil is a Seq, because when you call seq on nil you will get a false return.

user> (first nil) nil user> (last nil) nil user> (second nil) nil user> (seq? nil) false

Unlike many other Lisps, Clojure does not treat empty lists, vectors, and maps as nil.

user> (if '() "true" "false") "true" user> (if '[] "true" "false") "true" user> (if '{} "true" "false") "true"

Because nil can take on many meanings, you must be mindful to know when nil means false and when it means nil. For example, when looking for a value in a map, the value for a key can be nil. To determine whether or not it exists in the map, you have to return a default value.

user> (:foo {:foo nil :bar "baz"}) nil user> (:foo {:foo nil :bar "baz"} :not-found) nil user> (:foo {:bar "baz"} :not-found) :not-found

Unlike Java, nil is everywhere and for functions return nil. Most functions are/should be written to handle a passed in nil value. “Using nil where it doesn't make sense in Clojure code is usually a type error, not a NullPointerException, just as using a number as a function is a type error.” (http://www.lispcast.com/nil-punning)

The Functional Web

It's interesting to see how web programming has evolved over the years. Many different paradigms have come and gone, with some better than others, and yet we haven't seen the end of this evolution. In the early days of the dynamic web back in the 1990s we saw technologies such as CGI, and languages such as Perl, PHP, and ColdFusion come into popularity. Then, with the rise of object-oriented programming, distributed object technologies such as CORBA and EJB rose up, along with object-centric web service technology such as SOAP, as well as object-focused web programming frameworks such as ASP.NET and JSF.

Recent years have seen a shift toward a more RESTful, micro-service based architecture. Nobody uses CORBA anymore, and even SOAP is a dirty word in many circles. Instead, web programming has started to embrace HTTP and its stateless nature and focus on values. Similar to how functional programming has gained popularity because of the rise in number of cores in modern day computers and the necessity of concurrent programming, the web also needs ways to deal with scaling horizontally rather than just vertically.

So what qualities, if any, does web programming in recent years share with functional programming? At its heart, your endpoints can be thought of as functions that take an HTTP request and transform them into an HTTP response. The HTTP protocol itself is also stateless in nature. True, there are things like cookies and sessions, but those merely simulate some sort of state through a shared secret between the client and server. For the most part, the REST endpoints can be thought of as being referentially transparent, which is why caching technologies are so prevalent.

That's not to say there aren't aspects of web programming that are not very functional. Obviously, it would be very difficult to get anything done without modifying some state somewhere. However, it seems like web programming shares as much if not more in common with functional programming than it does with object-oriented programming. In fact, you may find that there's much more opportunity for composability and reuse than with the component-based technologies that have fallen out of favor.

DOING OBJECT-ORIENTED BETTER