Is there an errata list for the book 'Quick Clojure' by Mark McDonnell ?
I went to the publisher website and could not find one there : https://www.apress.com/gp/book/9781484229514
specifically i think there is an error in the following on page 50:
(defn add-n [n, coll]
(lazy-seq (cons
(+ n (first coll))
(add-n n (rest coll)))))
(type (add-n (range)))
;; clojure.lang.LazySeq
(take 10 (add-n (range))) ;; <--- Error here: `add-n` requires 2 arguments ?
;; (5 6 7 8 9 10 11 12 13 14)
Let's see if we can't figure out what was meant. We know from the comment that
(take 10 (add-n (range)))
is meant to return (5 6 7 8 9 10 11 12 13 14). It also appears that the missing argument is the n, which at first guess should be a number, and so the invocation of add-n should look something like
(add-n _ (range)))
So what value could we use to replace the _ to make it return the expected value? The obvious answer is 5. And so we test it by evaluating
(take 10 (add-n 5 (range)))
which returns
(5 6 7 8 9 10 11 12 13 14)
So there you have it. Now you can go to the Apress errata page and submit this as a correction. (I can't because I don't own the book, don't know what page it's on, etc).
Related
this setup is straight outta the docs here:
https://clojuredocs.org/clojure.core/commute
I'll just copy the code as is, with my comments:
(def counter (ref 0))
(defn alter-inc! [counter]
(dosync (Thread/sleep 100) (alter counter inc)))
(defn commute-inc! [counter]
(dosync (Thread/sleep 100) (commute counter inc)))
(defn bombard-counter! [n f counter]
(apply pcalls (repeat n #(f counter))))
(dosync (ref-set counter 0))
Running with the alter produces the randomly ordered list and takes 2000 ms, like in the example:
> (time (doall (bombard-counter! 20 alter-inc! counter)))
"Elapsed time: 2078.859995 msecs"
(7 6 1 5 4 2 3 9 12 10 8 14 11 13 15 18 16 17 20 19)
But running with commute does something very different from the claim in the official doc - I get duplicates:
> (time (doall (bombard-counter! 20 commute-inc! counter)))
"Elapsed time: 309.615195 msecs"
(5 1 1 6 5 4 1 8 8 10 10 12 14 13 15 16 17 18 19 20)
And that's definitely not the result promised in the docs! The difference in the running time is as advertised, but what with the duplicates? I'm prone to typos, so I've re-done it from scratch - same problem.
“commute returns the new value of the ref. However, the last in-transaction value you see from a commute will not always match the end-of-transaction value of a ref, because of reordering. If another transaction sneaks in and alters a ref that you are trying to commute, the STM will not restart your transaction. Instead, it will simply run your commute function again, out of order. Your transaction will never even see the ref value that your commute function finally ran against."
Since Clojure’s STM can reorder commutes behind your back, you can use
them only when you do not care about ordering.”
Excerpt From: Stuart Halloway. “Programming Clojure.”
This is the reason you see out of order update results in your output.
I am wondering get a sublist in a list,like:
user=> (findsublst '(hello world (10 clock)))
(10 clock)
what function can I use or how to define the functioin findsublst. Thank you so much!
With very little to go on, the following will return all first level list/sequences contained by the primary:
(filter seq? '(1 2 3 (4 5 6)))
=> ((4 5 6))
I am working on some Lisp exercises using Clojure. I am trying to work these exercises without taking advantage of vectors and some Clojure functions.
This function
(defn rev-seq
[s1]
(concat (pop s1) (list (peek s1))))
puts the first element of a list at the end. I want to call this function as many times as it takes to reverse the list (without calling Clojure's reverse function).
I am not sure what to use in its place. I have experimented with map, apply, and repeat with no success. I would rather have a way to think differently about this than a straight answer, but I am not asking for a discussion.
Firstly, I think you'll need to convert rev-seq to use first/rest rather than peek/pop if you want to work on general sequences - at leas in Clojure 1.4 peek/pop seems to require a PersistentStack:
(defn rev-seq
[s1]
(concat (rest s1) (list (first s1))))
Then you should probably note that applying this function repeatedly will "cycle" a list rather than reversing it. You can see that if you look at the result of a small number of applications using iterate:
(def s '(1 2 3 4 5 6 7 8 9))
(nth (iterate rev-seq s) 3)
=> (4 5 6 7 8 9 1 2 3)
An option that would work is to reverse with a recursive function:
(defn reverse-seq [s]
(concat (reverse (next s)) (list (first s))))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Or alternatively you can do a reverse using the technique in clojure.core:
(defn reverse-seq [s]
(reduce conj () s))
(reverse-seq s)
=> (9 8 7 6 5 4 3 2 1)
Hope this gives you some ideas!
Recursion is powerful!
I translated
the solution
into Clojure.
(defn- inverte-aux
[lista resto]
(if lista
(recur (next lista) (cons (first lista) resto))
resto))
(defn inverte
[lista]
(inverte-aux lista nil))
user> (inverte [4 3 2 1 3])
(3 1 2 3 4)
For example
(map #(+ 10 %1) [ 1 3 5 7 ])
Will add 10 to everything
Suppose I want to map everything to the constant 1. I have tried
(map #(1) [ 1 3 5 7 ])
But I don't understand the compiler error.
(map #(1) [ 1 3 5 7 ])
Won't work for two reasons:
#(1) is a zero-argument anonymous function, so it won't work with map (which requires a one-argument function when used with one input sequence).
Even if it had the right arity, it wouldn't work because it is trying to call the constant 1 as a function like (1) - try (#(1)) for example if you want to see this error.
Here are some alternatives that will work:
; use an anonymous function with one (ignored) argument
(map (fn [_] 1) [1 3 5 7])
; a hack with do that ignores the % argument
(map #(do % 1) [1 3 5 7])
; use a for list comprehension instead
(for [x [1 3 5 7]] 1)
; use constantly from clojure.core
(map (constantly 1) [1 3 5 7])
Of the above, I think the versions using constantly or for should be preferred - these are clearer and more idiomatic.
The anonymous function #(+ 10 %1) is equivalent to:
(fn [%1]
(+ 10 %1))
Whereas #(1) is equivalent to:
(fn []
(1))
And trying to call 1 as a function with no args just won't work.
I got this from clojure.org
by googling the words "clojure constant function" as I am just beginning to look at clojure
(map (constantly 9) [1 2 3])
cheers
I'm looking for an elegant way to generate a sequence of the rolling average of a sequence of numbers. Hopefully something more elegant than using lazy-seq
Without any consideration of efficiency:
(defn average [lst] (/ (reduce + lst) (count lst)))
(defn moving-average [window lst] (map average (partition window 1 lst)))
user> (moving-average 5 '(1 2 3 4 5 6 7 8))
(3 4 5 6)
If you need it to be fast, there are some fairly obvious improvements to be made!
But it will get less elegant.
There's a very similar question on SO: Calculating the Moving Average of a List. It's more general -- a number of FP-friendly languages are represented, with the accepted answer using Scala -- but there are a few nice Clojure solutions.
I've posted my own solution over there. Note that it does use lazy-seq, but that's because I wanted it to perform well for large periods (which means adjusting the average at each step rather than calculating a separate average for each window of size = period into the input list). Look around that Q for nice solutions which made the other tradeoff, resulting in shorter code with a somewhat more declarative feel, which actually performs better for very short periods (although suffers significant slowdowns for longer periods, as is to be expected).
This version is a bit faster, especially for long windows, since it keeps a rolling sum and avoids repeatedly adding the same things.
Because of the lazy-seq, it's also perfectly general and won't blow stack
(defn partialsums [start lst]
(lazy-seq
(if-let [lst (seq lst)]
(cons start (partialsums (+ start (first lst)) (rest lst)))
(list start))))
(defn sliding-window-moving-average [window lst]
(map #(/ % window)
(let [start (apply + (take window lst))
diffseq (map - (drop window lst) lst)]
(partialsums start diffseq))))
;; To help see what it's doing:
(sliding-window-moving-average 5 '(1 2 3 4 5 6 7 8 9 10 11))
start = (+ 1 2 3 4 5) = 15
diffseq = - (6 7 8 9 10 11)
(1 2 3 4 5 6 7 8 9 10 11)
= (5 5 5 5 5 5)
(partialsums 15 '(5 5 5 5 5 5) ) = (15 20 25 30 35 40 45)
(map #(/ % 5) (20 25 30 35 40 45)) = (3 4 5 6 7 8 9)
;; Example
(take 20 (sliding-window-moving-average 5 (iterate inc 0)))
Instead of the partialsums fn (which is helpful to see what's going on), you can use reductions in clojure.core:
(defn sliding-window-moving-average [window lst]
(map #(/ % window)
(let [start (apply + (take window lst))
diffseq (map - (drop window lst) lst)]
(reductions + start diffseq))))