Errata

Clojure Programming

Errata for Clojure Programming

Submit your own errata for this product.

The errata list is a list of errors and their corrections that were found after the product was released.

The following errata were submitted by our customers and have not yet been approved or disproved by the author or editor. They solely represent the opinion of the customer.

Color Key: Serious technical mistake Minor technical mistake Language or formatting error Typo Question Note Update

Version Location Description Submitted by Date submitted
ePub Page Example 3-7
The ancillary code to the example.

In this example below from “Clojure Programming” (2012) in the second part of Example 3-7, the Clojure function `take` would be a lot better than `drop`, as `drop` forces the interpreter into an infinite operation. Without this correction to `take`, the `iterate` just keeps going until the computer user kills the process manually.

Existing:

(->> (iterate step #{[2 0] [2 1] [2 2] [1 2] [0 1]})
(drop 8)
first
(populate (empty-board 6 6))
pprint)

(->> (iterate step #{[2 0] [2 1] [2 2] [1 2] [0 1]})
(take 8)
first
(populate (empty-board 6 6))
pprint)

Chris M. Balz  Jan 28, 2014 
PDF Page Chap. 10
Example 10-1

When I try to run the example I get the following error:

CompilerException java.lang.RuntimeException: Expecting var, but JFrame is mappe
d to class javax.swing.JFrame, compiling:(NO_SOURCE_PATH:34:23)

I've triple-checked the source code (I typed it in manually), but I don't see any discrepancies from what's in the book. Could it be related to the particular version of Java I'm using, which is 1.7.0_55? I'm running under Windows 7 64-bit.

Thanks.

David Kettle  May 14, 2014 
ePub Page ?
Footnote 121

Foot note 121 says:

[121] A branch is a node that may have
children: a branch can have no children.

I believe this is supposed to say

[121] A branch is a node that may have children: a leaf can have no children.

Anonymous  Feb 09, 2015 
Printed Page 28
First sentence

In the May, 2014 book, the phrase "you will want evaluate" should be "you will want to evaluate".

Terry Phelps  Jan 21, 2015 
Printed, PDF Page 37
1st paragraph

I have quoted the function with the error below:

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

I presume that the "x" on 2nd line of the function was supposed to be a "+" because 10 + 1 is 11 and because the function is an adder not a multiplier.

Mar 27, 2021 
PDF Page 71
3

The regex to split camel case doesn't work for numbers.

The following fails:
(camel->keyword "fooBar1Bar2")

Instead use the following regex::
#"(?<=[a-z0-9])(?=[A-Z])"

John Asbaghi  Jul 21, 2014 
ePub Page 117
Footnote #70

Footnote [70] describes "idempotence" as always returning the same value with no side effects. To be clear, the term is also used for an operation that has the same side effects whether run once or multiple times.

This is a very desirable property. E.g. you want a web "Submit" button to have the same result if clicked multiple times, say, "submit order #88972" (again) rather than "submit a new order."

Cf. http://en.wikipedia.org/wiki/Idempotence#Computer_science_meaning
"In computer science, the term idempotent is used more comprehensively to describe an operation that will produce the same results if executed once or multiple times."

Jerry Morrison  Nov 04, 2013 
PDF Page 119
7th paragraph (I think)

The example code did not work until I made a minor modification to it. Here's a sample session:

user=> (into {} (for [[k v] (group-by :artist playlist)] [k (summarize v)]))
{"The White Stripes" " / / ", "Papas Fritas" " / / ", "PJ Harvey" " / / ", "Mardi Gras BB" " / / "}
user=> (into {} (for [[k v] (group-by :artist playlist)] [k (map summarize v)]))
{"The White Stripes" ("Elephant / The White Stripes / 2003"), "Papas Fritas" ("Helioself / Papas Fritas / 1997" "Buildings and Grounds / Papas Fritas / 2000"), "PJ Harvey" ("Stories from the City, Stories from the Sea / PJ Harvey / 2000"), "Mardi Gras BB" ("Zen Rodeo / Mardi Gras BB / 2002")}
user=>

One difference between the sample code from the book, and the code as I've typed it initially, is that I needed to specify ":artist", whereas the book left "key-fn" unspecified. But I needed to do this to get a concrete working example.

Paul DeLong  Feb 11, 2014 
Printed Page 141
definition indexed-step3

in source of
(defn indexed-step3
..........
at last stmt :
board (for [x (range h) y (range w)][x y]))))

the variables of range are swapped ?
may the correct stmt is:
board (for [x (range w) y (range h)] [x y]))))

ugo  Jan 06, 2013 
PDF Page 143
Example 3-7

The original neighbours function is used within example 3-7 without mentioning that no boundary checking is performed, and therefore off-grid locations may be included in the result, e.g.

(def blinker #{[0 0][0 1][0 2]})
;;#'user/blinker
(def blinker-game (iterate step blinker))
;;#'user/blinker-game
;;(defn blink [n] (pprint (-> blinker-game (nth n))))
;;#'user/blink
(blink 1)
#{[1 1] [-1 1] [0 1]}

This does not affect the glider pattern as set-up in the book, but shouldn't it be mentioned (or accounted for) nevertheless?

Thanks for a great book..

KingCode  Apr 16, 2015 
PDF Page 144
United States

As shown in the hex-grid diagram at https://www.dropbox.com/s/ywm8np2wbk0dr8d/hex-1.png (from `user> (hex-neighbours [2 3])`), the `hex-neighbors` function for Life-like automaton H.B2/S34 (with a hexagonal grid) should be implemented as:

(defn hex-neighbours
[[x y]]
(for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [1 0])]
[(+ dx x) (+ dy y)]))

The above hex-neighbors function yields the correct neighbors, shown in green at the diagram linked above.

Instead, the current implementation from the book yields the neighbors marked in red on the diagram linked above:

(defn hex-neighbours
[[x y]]
(for [dx [-1 0 1] dy (if (zero? dx) [-2 2] [-1 1])]
[(+ dx x) (+ dy y)]))

because the latter function computes three neighbors that are off-by-one in their 'y' value.

Chris M. Balz  Feb 08, 2014 
PDF Page 147
line 1

"(keys path)" → "(keys paths)"

Daniel Gerigk  Dec 13, 2015 
PDF Page 152
footnote 49

"49. A branch is a node that *may* have children: a branch can have no children."
→ "49. A branch is a node that *must* have children: a branch can't have no children."

Daniel Gerigk  Dec 13, 2015 
PDF Page 184
Figure 4-2 and 3rd paragraph

http://clojure.org/refs says "All reads of Refs will see a consistent snapshot of the 'Ref world' as of the starting point of the transaction (its 'read point')."

It explicitly states that a transaction's point of reading all refs is at the start of the transaction.

However, Figure 4-2 makes it look as if t1 would succeed if t1 modified ref 'a' after t2 committed, and the third paragraph on page 184 adds to the confusion.

The paragraph reads "The unique semantic of alter is that, when the transaction is to be committed, the value of the ref outside of the transaction must be the same as it was prior to the first in-transaction application of alter. Otherwise, the transaction is restarted from the
beginning with the new observed values of the refs involved."

From the figure and the paragraph, I was led to think the value of the ref outside of the transaction must be the same as the one right before the first in-transaction application of alter, which causes a big trouble for the function, 'heal'.

(defn heal
[healer target]
(dosync
(let [aid (min (* (rand 0.1) (:mana @healer))
(- (:max-health @target) (:health @target)))]
(when (pos? aid)
(commute healer update-in [:mana] - (max 5 (/ aid 5)))
(alter target update-in [:health] + aid)))))

If the value of 'target' changed between the time it was read for the calculation of 'aid' and the time alter was invoked in the transaction, alter wouldn't cause the transaction to retry, but validator could throw exception due to exceeding max health.

You should modify Figure4-2 and the paragraph to not confuse readers.

crocket  Jun 28, 2015 
PDF Page 188
Output of sample code under "Now we can have duels:"

The definition of the `attack` function seems to preclude a target's max health being updated with a numerically negative value:

`(commute target update-in [:health] #(max 0 (- % damage)))`

However, the output of the sample code under "Now we can have duels:" shows target `bilbo` to have a negative `:health` value following a series of attacks:

`(map (comp :health deref) [smaug bilbo]) ;= (488.80755445030337 -12.0394908759935)`

I tried running the same code a number of times, and the lowest value of `:health` for `bilbo` was always zero.

Can the authors check whether their sample output is erroneous? Perhaps it was generated with an implementation of `attack` differing from the one given in the book?

Michael Bradley  May 31, 2012 
Printed Page 192
Footnote 22

"effectively mutable" should probably be "effectively immutable"

Daniel Schuler  May 06, 2014 
PDF Page 249
United States

The correct form is below, to follow "This behavior is obvious if you look at the macro expansion:"

(macroexpand-1 '(spy (rand-int 10)))
(do (clojure.core/println "spied" (quote (rand-int 10)) (rand-int 10)) (rand-int
10))

art gittleman  Aug 15, 2012 
PDF Page 249-50
United States

The correct expansion is

user=> (macroexpand-1 '(spy (rand-int 10)))
(clojure.core/let [x__725__auto__ (rand-int 10)] (clojure.core/println "spied" (quote (rand-int 10)) x__725__auto__) x__725__auto__)

art gittleman  Aug 15, 2012 
Printed Page 250
first line

The macroexpand-1 listing reads (this is the second line of the listing, the first line is at the end of the preceding page):

;= (println x__725__auto__ '(rand-int 10))

but it should read:

;= (println "spied" '(rand-int 10) x__725__auto__)

Mike Weaver  Jan 28, 2020 
ePub Page 273
quote block

The link to Library Coding Standards is outdated and should be: http://dev.clojure.org/display/community/Library+Coding+Standards (instead of http://dev.clojure.org/display/design/Library+Coding+Standards).

shotwave  Jun 02, 2015 
ePub Page 280
Persistence and Structural Sharing, 1st paragraph

“This is because the data structures are persistent, an implementation technique where collections reuse internal structure to minimize the number of operations needed to represent altered versions of an instance of a collection while ensuring that all versions of a collection will maintain the same efficiency guarantees.”

Maybe I misread the sentence above incorrectly, but it sounds like it implies that persistent data structures imply re-use, which is misleading. In fact persistence is just a property of preserving data structures upon modification.

shotwave  Jun 02, 2015 
PDF, Other Digital Version Page 286
(fn [x] (map #(lookup pt x y) (range 0 w)))

(fn [x] (map #(lookup pt x y) (range 0 w)))
should be:
(fn [x] (map #(lookup pt x (:y pt)) (range 0 w)))

Wrong also in:
https://github.com/clojurebook/ClojureProgramming/blob/7521bcfb52cdf7e598bca3c4e7860d795a67992c/ch06-datatypes-repl-interactions.clj#L558

Roberto Mannai  May 04, 2012 
PDF Page 286
definition of abstract-matrix-impl

Even though this is besides the point of demonstrating the usefulness of implementation maps with this excellent example, there are three issues with (def abstract-matrix-impl ...):

1) A compile error due to the use of 'y' free variable (instead of '%' as required by an anon. fn) on the 5th line

2) The representation of :rows and :cols is the opposite of what is previously done by (extend-protocol Matrix Point...) on pp. 280-281:

(cols (Point. 10 20)) yields
=> ((10) (20))
as opposed to the expected
=> ((10 20))
and vice versa for (rows p)

3) This is minor, but we probably want vectors as opposed to generic seqs, e.g. [[10 20]] vs ((10 20))?

The following seems to fix all of the above:

(def abstract-matrix-impl
{:cols (fn [pt]
(let [[h w] (dims pt)]
(-> (fn [x] (-> (map #(lookup pt x %) (range 0 w)) vec))
(map (range 0 h))
vec)))
:rows (fn [pt]
(-> (apply map vector (cols pt)) vec))})

Thanks for a great book!

JF Rompre  Sep 07, 2014 
Other Digital Version 301
Australia

Maze example in Ch 3 has a casting issue:

Exception in thread "main" java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
at user$grid.invoke(maze.clj:22)

(defn grid
[w h]
(set concat(
(for [i (range (dec w)) j (range h)] #{[i j]
[(inc i) j]})
(for [i (range w) j (range (dec h))] #{[i j]
[i (inc j)]}))))

Where line 22 is the first for loop above.

The example code for the project on github also doesn't include this particular example - it supplies source code for the first example of the chapter, Conway's Game of Life, but then stops.

Nicholas Faiz  Jun 30, 2012 
Printed, PDF Page 426
last paragraph and last-but-one paragraph

I think the mentions of BigInteger should instead be BigInt.

Simon Katz  Sep 02, 2014 
Printed Page 451
render-image function

I believe the parameters for the modulo function are switched in the following invocation:

(palette (mod (dec (count palette)) (inc escape-iter)))

It should instead read:

(palette (mod (inc escape-iter) (dec (count palette))))

so that we get x modulo the size of the palette

Kyle Mahan  Jun 24, 2012 
Printed Page 464
last line of Java code example

The line should be:

chain.runChain("data123");

instead of:

chain.run("data123");

The run method does not exist for the FooProcessor class or its parent class.

Andrew T. Flower  Aug 21, 2015