In https://stackoverflow.com/a/2495105/261952 somebody claims it works like this:
(-> (clojure.lang.PersistentQueue/EMPTY)
(conj 1 2 3)
pop)
(2 3)
However when I try this in my REPL, I get this result:
=> #object[clojure.lang.PersistentQueue 0x11f5966 "clojure.lang.PersistentQueue#402"]
Since that post is 7 years old, behaviour may have changed.
How cat I get it working today (Clojure 1.8)?
It still works. Add seq to the threading to see what there is:
(-> (clojure.lang.PersistentQueue/EMPTY)
(conj 1 2 3)
pop
seq)
;(2 3)
Related
If I try this, I get back results I expect: a list of trues and falses for each entry in the vector.
(deftest test-weird
(let [x {:nums [1 2 3 4 5 6 7 8]}
res (update x :nums #(map even? %))]
(println res)))
results: {:nums (false true false true false true false true)}
If I try this with drop-while, I get back the vector unchanged, where as I was expecting to get back a list of just the odd entries.
(deftest test-weird
(let [x {:nums [1 2 3 4 5 6 7 8]}
res (update x :nums #(drop-while even? %))]
(println res)))
results: {:nums (1 2 3 4 5 6 7 8)}
What am I doing wrong?
The first item is 1, which is not even. Thus, no items are dropped from the sequence.
What you really want is #(remove even? %). However, I think it reads better to say #(filterv odd? %) (i.e. say what you want; don't say what you don't want).
Notice also that there is an eager (vector) version filterv that I always prefer (no such option for remove).
Please see this list of documentation. Especially study the Clojure CheatSheet every day!
While the names filter and remove are very traditional, I always have to think twice to remember if a true predicate is dropped or kept. The definition is:
- filter => "keep-if true ..."
- remove => "drop-if true ..."
In my own code, I usually prefer to use a simple alias to emphasize what is occurring (always eager, as well).
Instead of #(drop-while even? %) which removes all elements in collection until first true event and returns all rest:
either: #(filterv (comp not even?) %)
or: #(remove even? %)
This question already has answers here:
Why isn't my code printing like it should?
(3 answers)
Closed 2 years ago.
(defn f1 []
(for [a [1 2]]
a))
;user=>(f1)
;(1 2)
(defn f2 []
(for [a [1 2]]
(prn a)))
;user=>(f2)
;1
;2
;(nil nil)
(defn f3 []
(for [a [1 2]]
(prn a))
'something-else)
;user=>(f3)
;something-else
Why does f3 not print 1 and 2 before printing 'something-else?
i.e. I expected and had assumed (wrongly) it would print the following:
; 1
; 2
; something-else
Came across this when using a for with a lot of code inside it and this played havoc with
my attempt to use prn statements to trace the value of variables while debugging.
i.e. prn and println do not print out. I think it's only when the for block is not the
final form in its enclosing form, but i'm still not sure what's going on.
The point being that a side-effect such as prn or println, should not require to be in return value position for it to fire. So there's something deeper with list comprehensions that I don't understand.
A notion as I write this - maybe in f3 the list comprehension is simply never evaluated, due to laziness? ... oh [censored].
Yes, that is indeed it:
(defn f4 []
(doall
(for [a [1 2]]
(prn a)))
'something-else)
user=> (f4)
;1
;2
;something-else
So, even though mostly solved, I will still post this question to consolidate the learning - would anyone care to post some examples of their own gotchas re. laziness.
As you have documented here, the macro for is lazy, and doesn't execute until it has to. You can force it by wrapping it in a (vec ...) form or a doall.
For debugging purposes especially, I like to use spyx and forv from the Tupelo library to avoid all of these gotchas:
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn f5 []
(forv [a [1 2]]
(spyx a))
(spy :returning :something-else))
(dotest
(spyx (f5)))
With result:
-------------------------------
Clojure 1.10.1 Java 14
-------------------------------
Testing tst.demo.core
a => 1
a => 2
:returning => :something-else
(f5) => :something-else
Ran 2 tests containing 1 assertions.
0 failures, 0 errors.
So you can see printed nicely:
the labeled value of a at each step of the forv loop.
the return value of the function with a custom label
the explicit value of the function call (f5)
nothing anywhere is lazy
spy, spyx, et al always return the value printed for further use
a convenient unit test via is= confirms the output value.
There is a nice template project that you can clone to get you started quickly.
You may also be interested in with-result, or just doseq. Don't forget the Clojure CheatSheet.
I came across this macro definition for unless from the brave and true book
(defmacro unless
"Inverted 'if'"
[test & branches]
(conj (reverse branches) test 'if))
I believe the rest param is a sequence, and the conj returns a sequence, so this entire macro returns a sequence. I thought you needed to return a list for the return to be evaluated properly
On further investigation, why does (eval (sequence [+ 1 4 4])) do the same thing as (eval (list 1 4 4)). Where does it say that sequences are evaluated like lists? I don't see that in the docs. –
You have just proven that a list, a seq, and a sequence are all treated as function call sites by the Clojure compiler. That is your answer.
=> (def xxx [+ 2 3]) ; a function and 2 integers in a vector
=> (eval xxx) ; a vector doesn't work
[#object[clojure.core$_PLUS_ 0x375dfecb "clojure.core$_PLUS_#375dfecb"] 2 3]
=> (eval (seq xxx)) ; a seq works
5
=> (eval (sequence xxx)) ; a sequence works
5
=> (eval (apply list xxx)) ; converts xxx to a list (+ 2 3) which works
5
When the Clojure docs are ambiguous or are missing some detail, a small experiment like the above will answer your question.
If the answer applies to a specific area of the Clojure website, function docstring, or clojuredocs.org or clojure-doc.org, you may consider submitting a pull-request to update & improve the docs.
I am working through Functional Programming for the Object-Oriented Programmer by Brian Marick and am stuck on exercise 4. The solution I came up with is the same as that at the companion github site: https://github.com/marick/fp-oo/blob/master/solutions/just-enough-clojure.clj.
Here is my version.
(def factorial (fn [num] (apply * (range 1 (inc num)))))
The result of executing that in the repl is:
user=> factorial 5
#object[user$factorial 0x3cd52491 "user$factorial#3cd52491"]
5
I expected 120. I created an intermediate function:
(def range-to (fn [num] (range 1 (inc num))))
Which I then use in the following:
user=> (range-to 5)
(1 2 3 4 5)
user=> (apply * (range-to 5))
120
The results I am getting are totally unexpected and not understood. What am I doing wrong and what are my results actually saying?
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)