Many times when I try to write some function I get exception. That is normal. In Java you can find place and reason why exception occures but in clojure exception texts just make me crazy. Is there some tips how to read exceptions in clojure and how to find where in code exception happens and why?
For example I will take some code:
(do
(list?)
(list? [])
(list? '(1 2 3))
(list? (defn f [] (do ())))
(list? "a"))
when I call this function in REPL I will get
java.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$list-QMARK- (NO_SOURCE_FILE:46)
which do not help me much to find the problem in second line. In little more complicated code it will give almost no information. (Of course it tells look at list? in some there is wrong number of arguments.) Is it wrong that I try to write code in REPL? How to read exception mesages in REPL? Is there way how to get better information about exceptions in REPL?
You can use clojure.stacktrace: http://richhickey.github.com/clojure/clojure.stacktrace-api.html
Usage:
(use 'clojure.stacktrace)
(/ 1 0)
(e)
Output:
java.lang.ArithmeticException: Divide by zero
at clojure.lang.Numbers.divide (Numbers.java:156)
clojure.lang.Numbers.divide (Numbers.java:3691)
user$eval954.invoke (NO_SOURCE_FILE:1)
clojure.lang.Compiler.eval (Compiler.java:6511)
clojure.lang.Compiler.eval (Compiler.java:6477)
clojure.core$eval.invoke (core.clj:2797)
clojure.main$repl$read_eval_print__6405.invoke (main.clj:245)
clojure.main$repl$fn__6410.invoke (main.clj:266)
nil
Acquire org.clojure/tools.trace.
user=> (use 'clojure.tools.trace)
Let's try a dotrace (changed up the order to make things more interesting):
user=> (dotrace [list?]
#_=> (do
#_=> (list? [])
#_=> (list? '(1 2 3))
#_=> (list?)
#_=> (list? (defn f [] (do ())))
#_=> (list? "a"))
#_=> )
IllegalStateException Can't dynamically bind non-dynamic var: clojure.core/list?
clojure.lang.Var.pushThreadBindings (Var.java:353)
Hmm...
user=> (.setDynamic #'list?)
#'clojure.core/list?
Let's try that again:
user=> (dotrace [list?]
#_=> (do
#_=> (list? [])
#_=> (list? '(1 2 3))
#_=> (list?)
#_=> (list? (defn f [] (do ())))
#_=> (list? "a")))
TRACE t1216: (list? [])
TRACE t1216: => false
TRACE t1217: (list? (1 2 3))
TRACE t1217: => true
TRACE t1218: (list?)
ArityException Wrong number of args (0) passed to: core$list-QMARK-
clojure.lang.AFn.throwArity (AFn.java:437)
Aha! Made it to (list?) before the exception.
Related
Hi everybody I've been recently trying to learn to a new language and I sort of bumped into Clojure which look like a real interesting language because I've never heard about functional programming, even though I had used JavaScript before that kind of leverages it, well I'm gonna stop with the small talk and get into the problem.
I've been working on solving the https://github.com/gigasquid/wonderland-clojure-katas and more specific on the doublets problem. I think I have came with a solution but it send me the error on the title of this post. I have read about this error and it seems that it triggers when you want the compiler expects a function but it doesn't. Here is the full code of my solution to see if you can help me out with this one:
(ns doublets.solver
(:require [clojure.java.io :as io]
[clojure.edn :as edn]
[clojure.set :as set]))
(def words (-> "words.edn"
(io/resource)
(slurp)
(read-string)))
(defn linked-word [word word-list]
(some #(when (= (count (set/difference (into #{} (seq %))
(into #{} (seq word)))) 1) %)
word-list))
(defn doublets [word1 word2]
(let [n (count word1) v (cons word1 (filter #(= (count %) n)
(remove #{word1} words)))]
(tree-seq #(and (linked-word (% 0) %) (not= (% 0) word2))
#(cons (linked-word (% 0) (rest %))
(remove #{(% 0)} (rest %))) v)))
As you can see cons is a function so the error doesn't seem to be the case described above.
I can reproduce the error after downloading the words.edn file and running with (doublets "bank" "loan"). I think the problem is these expressions:
(% 0)
which you have in a few places. I see that you are cons-ing some things, so that may be a clue. What is (% 0) supposed to do?
If you want the first char, just say (first xyz) or something.
I would also break out the anonymous functions #(...) and give them real names.
Update
My guess seems to be correct as this experiment shows:
(cons 1 [2 3]) => (1 2 3)
(class (cons 1 [2 3])) => clojure.lang.Cons
(vec (cons 1 [2 3])) => [1 2 3]
(class (vec (cons 1 [2 3]))) => clojure.lang.PersistentVector
OK, rewrite like:
(defn doublets [word1 word2]
(let [n (count word1)
v (vec (cons word1 (filter #(= (count %) n)
(remove #{word1} words))))]
(tree-seq
#(and
(linked-word (% 0) %)
(not= (% 0) word2))
#(vec (cons (linked-word (% 0) (rest %)))
(remove #{(% 0)} (rest %)))
v)))
new error: java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol
And there is the clue we needed!
We are evaluating things as symbols, not strings! The problem is read-string, which is how you read source code, not data like strings. Delete read-string:
(def words (-> "words.edn"
(io/resource)
(slurp)))
We now get a new error on this line:
v (vec (cons word1 (filter #(= (count %) n)
(remove #{word1} words))))]
ERROR in (dotest-line-40) (RT.java:664)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.UnsupportedOperationException:
count not supported on this type: Character
So your seq has created something like "foo" => [\f \o \o], and you then try to say (count \f). You can't count a single char, only a string.
I'll let you debug it from there.
Found some odd behavior in midje, not sure if it's midje related, or due to my misunderstanding of some clojure constructs, but it's puzzling:
Inside a facts statement, a for loop is not getting called:
(ns t1
(:require [midje.sweet :refer :all ] )
)
(facts
(println "ok") ; -- this prints fine
(for [val '(1 2 3)] (println val)) ; this does not
(fact "junk"
(> (.length "aaaaha") 3) => true ))
Thought maybe it had something to do with the for being overwritten in the ns but calling clojure.core/for behaves similarly.
clojure.core/for "...yields a lazy sequence..."
You need to realize the sequence to see its side effects.
(doall (for [val '(1 2 3)] (println val)))
I'd suggest using something more appropriate like clojure.core/doseq:
(doseq [val '(1 2 3)] (println val))
Hi I have this school project that I am almost done with so I don't need help with the code, problem is I've never coded in clojure but for this assignment had to do a try and catch macro in clojure with bound forms, there are some REPL commands that are expected to give different responses for the assignment to pass,,
Anyways Im getting an error that I've been googling but nothing is specific to this problem and most explanations basically need there own explanation nothing seems to be beginner adapted so it doesnt do much for me.
(defmacro safe [bindings & code]
(if (list? bindings)
`(try
~bindings
(catch Throwable except# except#))
(if (= (count bindings) 0)
`(try ~code
(catch Throwable except# except#))
`(let ~(subvec bindings 0 2)
(try
(safe ~(subvec bindings 2) ~#code)
(catch Throwable except# except#)
(finally
(. ~(bindings 0) close))))))) ;;safe
(def divider(safe (/ 1 0)))
(def reader (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))
So the error Im getting is
=> (def v (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))
#'myProject.core/v
=> v
#<ClassCastException java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn>
So kindly anyone that knows clojure please give me some hints on what is wrong, all the hints Im getting is that there should be a paranthesis missplaced, I've checked the code over and over but cant find any misstypes etc. Thank you !
Use macroexpand and friends to help debug
(def form (quote (safe [s (FileReader. (java.io.File. "test.txt"))] (. s read))))
(pprint (macroexpand form)) ;=>
(let*
[s (FileReader. (java.io.File. "test.txt"))]
(try
(user/safe [] (. s read)) ; <--- Macro is recursive
(catch java.lang.Throwable except__1104__auto__ except__1104__auto__)
(finally (. s user/close))))
Macro is recursive, so this is not the full expansion
(pprint (clojure.walk/macroexpand-all form)) ;=>
(let*
[s (new FileReader (new java.io.File "test.txt"))]
(try
(try
((. s read)) ; <-- Too many parenthesis!
(catch ...
The read call returns an integer, which is in turn being called as a function in the recursive macro expansion.
(FileReader. (java.io.File. "/tmp/text.txt"))
is giving you the value of the first character on the file
cat /tmp/text.txt => abcd
(let [s (FileReader. (java.io.File. "/tmp/text.txt"))] (. s read)) => 97
same as
(int \a)
and your macro expect a function. try:
(safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] #(+ 6)) or (safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] (fn [] (. s read)
Solved!
Missing unquote slicing in the third try block, causing exception
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn
this was caused due to extra paranthesis when reading s recursivly,
macroexpand ex.
(pprint (macroexpand-all form))
(let*[s
(new FileReader
(new File "test.txt"))]
(try
(try
((.s read)) ;<= here
Had to change the third try/catch from
(try
(safe ~(subvec bindings 2) ~#code)
to:
(try
(safe ~#(subvec bindings 2) ~#code)
To my understanding the problem was that I was returned a list with a paranthesis like (1(2 3)) causing exception when read, unquoting makes it look (1 2 3) and can be read or (in this case) casted from java to clojure.
reservations for misspellz or calling shit the wrong name! :)
Many thanks to A.Webb and patz.
I'm a Clojure beginner and I want to understand the -> macro
This code works:
(-> '(1 2 3) reverse)
But this doesn't even compile and I don't know how to deal with the error message:
user=> (-> '(1 2 3) (fn [x] (reverse x)))
CompilerException java.lang.IllegalArgumentException: Parameter declaration quote should be a vector, compiling:(NO_SOURCE_PATH:1:1)
How can I fix this?
I use macroexpand and friends a lot when unexpected things start happening. If you use these here it becomes really obvious what's going on.
user=> (macroexpand-1 '(-> '(1 2 3) (fn [x] (reverse x))))
(fn (quote (1 2 3)) [x] (reverse x))
I think seeing this it's pretty obvious that the (quote (1 2 3) should not be the first arg to fn.
We can also see that the ugly double-parens approach fixes it:
user=> (macroexpand-1 '(-> '(1 2 3) ((fn [x] (reverse x)))))
((fn [x] (reverse x)) (quote (1 2 3)))
Side note that tripped me up: you have to use macroexpand-1 to get a result here. If you use macroexpand or clojure.walk/macroexpand-all it'll blow up (with your exception) after the first expansion, since fn itself is a macro, and is being called with bad syntax after the first expansion.
I don't know how to implement this piece of Python code in Clojure
for i in range(3):
try:
......
except e:
if i == 2:
raise e
else:
continue
else:
break
I wonder why something so simple in Python is so hard in Clojure. I think the difficulty is because Clojure is a functional programming language and thus is not suitable for such an imperative task. This is my attempt:
(first
(remove #(instance? Exception %)
(for [i (range 3)]
(try (......)
(catch Exception e
(if (== i 2)
(throw e)
e)))))))
It is very ugly, and worse, it doesn't work as expected. The for loop is actually evaluated fully instead of lazily (I realized this when I put a println inside).
If anyone has a better idea to implement that, please enlighten me.
Similar to Marcyk's answer, but no macro trickery:
(defn retry
[retries f & args]
(let [res (try {:value (apply f args)}
(catch Exception e
(if (zero? retries)
(throw e)
{:exception e})))]
(if (:exception res)
(recur (dec retries) f args)
(:value res))))
Slightly complicated because you can't recur inside a catch clause. Note that this takes a function:
(retry 3 (fn []
(println "foo")
(if (zero? (rand-int 2))
(throw (Exception. "foo"))
2)))
=>
foo ;; one or two or three of these
foo
2
Here's one approach:
(defmacro retry
"Evaluates expr up to cnt + 1 times, retrying if an exception
is thrown. If an exception is thrown on the final attempt, it
is allowed to bubble up."
[cnt expr]
(letfn [(go [cnt]
(if (zero? cnt)
expr
`(try ~expr
(catch Exception e#
(retry ~(dec cnt) ~expr)))))]
(go cnt)))
Example from the REPL:
user> (retry 2 (do (println :foo) (throw (RuntimeException. "foo"))))
:foo
:foo
:foo
; Evaluation aborted.
(Passing 2 to retry asks expr to be retried twice it if fails the first time round, for a total of three attempts. Three :foos are printed, because the println occurs before the throw in the do form passed to retry. The final ; Evaluation aborted. means an exception was thrown.)
Also, about the for loop from your snippet:
If you try looping over a longer range (replace (range 3) with (range 10), say), the output will end after i reaches 3. Also, if you put in a println before the form which throws the exception, it will of course print out whatever you pass to it; if the println occurs after the exception-throwing form, there will be no printout. In any case, at most three calls to println will be executed (assuming an exception is thrown on every iteration).
(cond (every? nil? (for [x (range (inc retry)) :while (not #tmp-doc)]
...do sth) )
;all failed
:else
;at least one success
You can do like this:
(defn retry
"Tries at most n times, return first try satisfying pred or nil"
[times pred? lazy-seq]
(let [successful-trial (drop-while (complement pred?) (take times lazy-seq))]
(if (empty? successful-trial)
nil
(first successful-trial))))
Then you could use the function as such:
(when-not (retry 3 pos? (repeatedly #(rand-nth [-1 -2 -3 2 1]))
(throw (Exception. "my exception message"))
This would try at most three times to take a positive number at random from the vector and if it doesn't succeed, throws an exception.
Retry with sleep and another implementation based on this question's answers:
(defn retry [retries sleep-ms func url options]
(let [{:keys [status headers body error] :as resp} #(func url options)]
(if error
(do
(log/error (str "Retry " retries " returned error: " e))
(Thread/sleep sleep-ms)
(if (= retries 1)
resp
(retry (dec retries) sleep-ms func url options)))
resp)))