Why call map in macro will fail in my Clojure code? - clojure

I want to transfer code from
("AAA" ("BB" 11 #"XXX"))
to
("AAA" ("BB" 11 "YYY"))
I just want to change #"XXX" to "YYY".
I write a function it works.
(defn tt [clause]
(cond (not (sequential? clause)) clause
(and (sequential? clause)
(= 2 (count clause))
(= `deref (first clause))
(string? (second clause)))
"YYY"
:else (map tt clause)))
there is my result:
(tt '("AAA" ("BB" 11 #"XXX"))) --> ("AAA" ("BB" 11 "YYY"))
But when I change the function to macro , it raise exception.
(defmacro test [& clause]
(let [f (fn tt [clause]
(cond (not (sequential? clause)) clause
(and (sequential? clause)
(= 2 (count clause))
(= `deref (first clause))
(string? (second clause)))
"YYY"
:else (map tt clause)))]
(f clause)))
and it raise exception like this
(test "AAA" ("BB" 11 #"XXX")) --> ClassCastException java.lang.String cannot be cast to clojure.lang.IFn
I have test map for prewalk function. Both of them raise exception.
I have no idea what is wrong with it and how to fix this error in macro??

Related

Clojure functions which perform symbolic simplification using 'and'

I am new to Clojure and I'm learning how to write a program that can simplify logical expressions (just 'and' for now to figure out how things work first). For example:
(and-simplify '(and true)) => true
(and-simplify '(and x true)) => x
(and-simplify '(and true false x)) => false
(and-simplify '(and x y z true)) => (and x y z)
I already knew how to simplify two arguments, that everything I can do right now is:
(defn and-simplify []
(def x (and true false))
println x)
(and-simplify)
I've read this post and tried to modify my code a little bit but it doesn't seem to get me anywhere:
(defn and-simplify [&expr]
(def (and &expr))
)
What is the correct way that I should have done?
Here's my take on it.
(defn simplify-and
[[op & forms]]
(let [known-falsy? #(or (false? %) (nil? %))
known-truthy? #(and (not (symbol? %))
(not (seq? %))
(not (known-falsy? %)))
falsy-forms (filter known-falsy? forms)
unknown-forms (remove known-truthy? forms)]
(if (seq falsy-forms)
(first falsy-forms)
(case (count unknown-forms)
0 true
1 (first unknown-forms)
(cons op unknown-forms)))))
(comment (simplify-and `(and true 1 2 a)))
However, we can write a more generic simplify that uses multimethods to simplify lists, so that we can add more optimisations without modifying existing code. Here's that, with optimisations for and, or and + from clojure.core. This simplify only optimises lists based on namespace qualified names.
Check out the examples in the comment form. Hope it makes sense.
(defn- known-falsy? [form]
(or (false? form) (nil? form)))
(defn- known-truthy? [form]
(and (not (symbol? form))
(not (seq? form))
(not (known-falsy? form))))
(declare simplify)
(defmulti simplify-list first)
(defmethod simplify-list :default [form] form)
(defmethod simplify-list 'clojure.core/and
[[op & forms]]
(let [forms (mapv simplify forms)
falsy-forms (filter known-falsy? forms)
unknown-forms (remove known-truthy? forms)]
(if (seq falsy-forms)
(first falsy-forms)
(case (count unknown-forms)
0 true
1 (first unknown-forms)
(cons op unknown-forms)))))
(defmethod simplify-list 'clojure.core/or
[[op & forms]]
(let [forms (mapv simplify forms)
truthy-forms (filter known-truthy? forms)
unknown-forms (remove known-falsy? forms)]
(if (seq truthy-forms)
(first truthy-forms)
(case (count unknown-forms)
0 nil
1 (first unknown-forms)
(cons op unknown-forms)))))
(defmethod simplify-list 'clojure.core/+
[[op & forms]]
(let [{nums true non-nums false} (group-by number? (mapv simplify forms))
sum (apply + nums)]
(if (seq non-nums)
(cons op (cons sum non-nums))
sum)))
(defn simplify
"takes a Clojure form with resolved symbols and performs
peephole optimisations on it"
[form]
(cond (set? form) (into #{} (map simplify) form)
(vector? form) (mapv simplify form)
(map? form) (reduce-kv (fn [m k v] (assoc m (simplify k) (simplify v)))
{} form)
(seq? form) (simplify-list form)
:else form))
(comment
(simplify `(+ 1 2))
(simplify `(foo 1 2))
(simplify `(and true (+ 1 2 3 4 5 foo)))
(simplify `(or false x))
(simplify `(or false x nil y))
(simplify `(or false x (and y nil z) (+ 1 2)))
)

Return an else value when using recur

I am new to Clojure, and doing my best to forget all my previous experience with more procedural languages (java, ruby, swift) and embrace Clojure for what it is. I am actually really enjoying the way it makes me think differently -- however, I have come up against a pattern that I just can't seem to figure out. The easiest way to illustrate, is with some code:
(defn char-to-int [c] (Integer/valueOf (str c)))
(defn digits-dont-decrease? [str]
(let [digits (map char-to-int (seq str)) i 0]
(when (< i 5)
(if (> (nth digits i) (nth digits (+ i 1)))
false
(recur (inc i))))))
(def result (digits-dont-decrease? "112233"))
(if (= true result)
(println "fit rules")
(println "doesn't fit rules"))
The input is a 6 digit number as a string, and I am simply attempting to make sure that each digit from left to right is >= the previous digit. I want to return false if it doesn't, and true if it does. The false situation works great -- however, given that recur needs to be the last thing in the function (as far as I can tell), how do I return true. As it is, when the condition is satisfied, I get an illegal argument exception:
Execution error (IllegalArgumentException) at clojure.exercise.two/digits-dont-decrease? (four:20).
Don't know how to create ISeq from: java.lang.Long
How should I be thinking about this? I assume my past training is getting in my mental way.
This is not answering your question, but also shows an alternative. While the (apply < ...) approach over the whole string is very elegant for small strings (it is eager), you can use every? for an short-circuiting approach. E.g.:
user=> (defn nr-seq [s] (map #(Integer/parseInt (str %)) s))
#'user/nr-seq
user=> (every? (partial apply <=) (partition 2 1 (nr-seq "123")))
true
You need nothing but
(apply <= "112233")
Reason: string is a sequence of character and comparison operator works on character.
(->> "0123456789" (mapcat #(repeat 1000 %)) (apply str) (def loooong))
(count loooong)
10000
(time (apply <= loooong))
"Elapsed time: 21.006625 msecs"
true
(->> "9123456789" (mapcat #(repeat 1000 %)) (apply str) (def bad-loooong))
(count bad-loooong)
10000
(time (apply <= bad-loooong))
"Elapsed time: 2.581750 msecs"
false
(above runs on my iPhone)
In this case, you don't really need loop/recur. Just use the built-in nature of <= like so:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(def true-samples
["123"
"112233"
"13"])
(def false-samples
["10"
"12324"])
(defn char->int
[char-or-str]
(let [str-val (str char-or-str)] ; coerce any chars to len-1 strings
(assert (= 1 (count str-val)))
(Integer/parseInt str-val)))
(dotest
(is= 5 (char->int "5"))
(is= 5 (char->int \5))
(is= [1 2 3] (mapv char->int "123"))
; this shows what we are going for
(is (<= 1 1 2 2 3 3))
(isnt (<= 1 1 2 1 3 3))
and now test the char sequences:
;-----------------------------------------------------------------------------
; using built-in `<=` function
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (apply <= digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (apply <= digit-vals))))
if you want to write your own, you can like so:
(defn increasing-equal-seq?
"Returns true iff sequence is non-decreasing"
[coll]
(when (< (count coll) 2)
(throw (ex-info "coll must have at least 2 vals" {:coll coll})))
(loop [prev (first coll)
remaining (rest coll)]
(if (empty? remaining)
true
(let [curr (first remaining)
prev-next curr
remaining-next (rest remaining)]
(if (<= prev curr)
(recur prev-next remaining-next)
false)))))
;-----------------------------------------------------------------------------
; using home-grown loop/recur
(doseq [true-samp true-samples]
(let [digit-vals (mapv char->int true-samp)]
(is (increasing-equal-seq? digit-vals))))
(doseq [false-samp false-samples]
(let [digit-vals (mapv char->int false-samp)]
(isnt (increasing-equal-seq? digit-vals))))
)
with result
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
Testing tst.demo.core
Ran 2 tests containing 15 assertions.
0 failures, 0 errors.
Passed all tests
Finished at 23:36:17.096 (run time: 0.028s)
You an use loop with recur.
Assuming you require following input v/s output -
"543221" => false
"54321" => false
"12345" => true
"123345" => true
Following function can help
;; Assuming char-to-int is defined by you before as per the question
(defn digits-dont-decrease?
[strng]
(let [digits (map char-to-int (seq strng))]
(loop [;;the bindings in loop act as initial state
decreases true
i (- (count digits) 2)]
(let [decreases (and decreases (>= (nth digits (+ i 1)) (nth digits i)))]
(if (or (< i 1) (not decreases))
decreases
(recur decreases (dec i)))))))
This should work for numeric string of any length.
Hope this helps. Please let me know if you were looking for something else :).
(defn non-decreasing? [str]
(every?
identity
(map
(fn [a b]
(<= (int a) (int b)))
(seq str)
(rest str))))
(defn non-decreasing-loop? [str]
(loop [a (seq str) b (rest str)]
(if-not (seq b)
true
(if (<= (int (first a)) (int (first b)))
(recur (rest a) (rest b))
false))))
(non-decreasing? "112334589")
(non-decreasing? "112324589")
(non-decreasing-loop? "112334589")
(non-decreasing-loop? "112324589")

What is the "name?" argument in Clojure's fn?

I am reading the book "Getting Clojure" by Russ Olsen. In chapter 8, "Def, Symbols, and Vars", there is the following function definition:
(def second (fn second [x] (first (next x))))
^^^^^^
My question is regarding the underlined second, which comes second.
At first, I thought this syntax is wrong as anonymous functions don't need a name. But as it turnes out, this syntax is correct.
Usage: (fn name? [params*] exprs*)
(fn name? ([params*] exprs*) +)
I tried comparing the following two function calls.
user> (fn second [x] (first (rest x)))
#function[user/eval5642/second--5643]
user> (fn [x] (first (rest x)))
#function[user/eval5646/fn-5647]
Besides the name of the function, there does not seem to be a difference.
Why would there be a name? argument to fn?
You can use it when creating multiple arities:
(fn second
([x] (second x 1))
([x y] (+ x y)))
or if you need to make a recursive call:
(fn second [x] (when (pos? x)
(println x)
(second (dec x))))
There are two main usages:
recursive functions (you now know the name)
user=> ((fn foo [x] (when (pos? x) (println x) (foo (dec x)))) 3)
3
2
1
nil
better stacktraces (the name will give you a better hint, where things went wrong)
user=> (map (fn bar [x] (inc x)) ["a"])
Error printing return value (ClassCastException) at clojure.lang.Numbers/inc (Numbers.java:137).
java.lang.String cannot be cast to java.lang.Number
user=> (pst)
ClassCastException java.lang.String cannot be cast to java.lang.Number
clojure.lang.Numbers.inc (Numbers.java:137)
user/eval8020/bar--8021 (NO_SOURCE_FILE:1)
clojure.core/map/fn--5866 (core.clj:2753)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
clojure.lang.RT.seq (RT.java:535)
clojure.core/seq--5402 (core.clj:137)
clojure.core/seq--5402 (core.clj:137)
puget.printer.PrettyPrinter (printer.clj:529)
puget.printer/iseq-handler--1663 (printer.clj:314)
puget.printer/iseq-handler--1663 (printer.clj:312)
puget.printer/format-doc* (printer.clj:223)
(note user/eval8020/bar--8021)

Strange error when using atoms inside deftype

I have the following code, defining a type that has an atom in there.
(defprotocol IDeck
(vec-* [dk] "Output to a persistent vector")
(count-* [dk] "Number of elements in the deck")
(conj1-* [dk & es] "Adding multiple elements to the deck"))
(deftype ADeck [#^clojure.lang.Atom val]
IDeck
(vec-* [dk] (->> (.val dk) deref (map deref) vec))
(count-* [dk] (-> (.val dk) deref count))
(conj1-* [dk & es]
(try
(loop [esi es]
(let [e (first esi)]
(cond
(nil? e) dk
:else
(do
(swap! (.val dk) #(conj % (atom e)))
(recur (rest esi))))))
(catch Throwable t (println t)))))
(defn new-*adeck
([] (ADeck. (atom [])))
([v] (ADeck. (atom (vec (map atom v))))))
(defn conj2-* [dk & es]
(try
(loop [esi es]
(let [e (first esi)]
(cond
(nil? e) dk
:else
(do
(swap! (.val dk) #(conj % (atom e)))
(recur (rest esi))))))
(catch Throwable t (println t))))
;; Usage
(def a (new-*adeck [1 2 3 4]))
(count-* a)
;=> 4
(vec-* a)
;=> [1 2 3 4]
(conj1-* a 1 2) ;; The deftype case
;=> IllegalArgumentException java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
(vec-* a)
;=> [1 2 3 4]
(conj2-* a 1 2) ;; The defn case
(vec-* a)
;=> [1 2 3 4 1 2]
Even though the two conj-* methods are exactly the same, except that one is in a deftype and the other is a normal defn, the first gives an error while the second succeeds. Why is this?
This is because protocols doesn't support variable number of arguments.
What you can do is make:
(conj1-* [dk & es] "Adding multiple elements to the deck"))
into
(conj1-* [dk es] "Adding multiple elements to the deck"))
such that the es param will be vector and called like:
(conj1-* a [1 2])

Clojure: How to to recur upon exception?

I am trying to execute a func several times before giving up upon exceptions.
But it is not valid in Clojure to recur from catch block.
How can this be achieved ?
(loop [tries 10]
(try
(might-throw-exception)
(catch Exception e
(when (pos? tries) (recur (dec tries))))))
java.lang.UnsupportedOperationException: Cannot recur from catch/finally
The best I could find is the following clumsy solution (wrapping in func and calling it)
(defn do-it []
(try
(might-throw-exception)
(catch Exception e nil)))
(loop [times 10]
(when (and (nil? (do-it)) (pos? times))
(recur (dec times))))
Macros are calling...
How about this:
(defn try-times*
"Executes thunk. If an exception is thrown, will retry. At most n retries
are done. If still some exception is thrown it is bubbled upwards in
the call chain."
[n thunk]
(loop [n n]
(if-let [result (try
[(thunk)]
(catch Exception e
(when (zero? n)
(throw e))))]
(result 0)
(recur (dec n)))))
(defmacro try-times
"Executes body. If an exception is thrown, will retry. At most n retries
are done. If still some exception is thrown it is bubbled upwards in
the call chain."
[n & body]
`(try-times* ~n (fn [] ~#body)))
kotarak's idea is the way to go, but this question tickled my fancy so I'd like to provide a riff on the same theme that I prefer because it doesn't use loop/recur:
(defn try-times* [thunk times]
(let [res (first (drop-while #{::fail}
(repeatedly times
#(try (thunk)
(catch Throwable _ ::fail)))))]
(when-not (= ::fail res)
res)))
And leave the try-times macro as it is.
If you want to allow the thunk to return nil, you can drop the let/when pair, and let ::fail represent "the function failed n times", while nil means "the function returned nil". This behavior would be more flexible but less convenient (the caller has to check for ::fail to see if it worked rather than just nil), so perhaps it would be best implemented as an optional second parameter:
(defn try-times* [thunk n & fail-value]
(first (drop-while #{fail-value} ...)))
A try-times macro is elegant, but for a one-off, just pull your when out of the try block:
(loop [tries 10]
(when (try
(might-throw-exception)
false ; so 'when' is false, whatever 'might-throw-exception' returned
(catch Exception e
(pos? tries)))
(recur (dec tries))))
My proposal:
(defmacro try-times
"Retries expr for times times,
then throws exception or returns evaluated value of expr"
[times & expr]
`(loop [err# (dec ~times)]
(let [[result# no-retry#] (try [(do ~#expr) true]
(catch Exception e#
(when (zero? err#)
(throw e#))
[nil false]))]
(if no-retry#
result#
(recur (dec err#))))))
Will print "no errors here" once:
(try-times 3 (println "no errors here") 42)
Will print "trying" 3 times, then throw Divide by zero:
(try-times 3 (println "trying") (/ 1 0))
One more solution, without macro
(defn retry [& {:keys [fun waits ex-handler]
:or {ex-handler #(log/error (.getMessage %))}}]
(fn [ctx]
(loop [[time & rem] waits]
(let [{:keys [res ex]} (try
{:res (fun ctx)}
(catch Exception e
(when ex-handler
(ex-handler e))
{:ex e}))]
(if-not ex
res
(do
(Thread/sleep time)
(if (seq rem)
(recur rem)
(throw ex))))))))
This allows catching multiple more then one exception and provides some feedback about the causes for the retries.
(defmacro try-n-times
"Try running the body `n` times, catching listed exceptions."
{:style/indent [2 :form :form [1]]}
[n exceptions & body]
`(loop [n# ~n
causes# []]
(if (> n# 0)
(let [result#
(try
~#body
~#(map (partial apply list 'catch) exceptions (repeat `(e# e#))))]
(if (some #(instance? % result#) ~exceptions)
(recur (dec n#) (conj causes# result#))
result#))
(throw (ex-info "Maximum retries exceeded!"
{:retries ~n
:causes causes#})))))
If you add a result arg to your loop, you can nest the (try) block inside of the (recur). I solved it like this:
(loop [result nil tries 10]
(cond (some? result) result
(neg? tries) nil
:else (recur (try (might-throw-exception)
(catch Exception e nil))
(dec tries))))
Here's yet another approach:
(loop [tries 10]
(let [res (try
(might-throw-exception)
(catch Exception e
(if (pos? tries)
::retry
(throw e))))]
(if (#{::retry} res)
(recur (dec tries))
res)))
But may I also recommend a cool little trick, instead of having a number of retries, provide a seq of times to sleep for:
(loop [tries [10 10 100 1000]]
(let [res (try
(might-throw-exception)
(catch Exception e
(if tries
::retry
(throw e))))]
(if (#{::retry} res)
(do
(Thread/sleep (first tries))
(recur (next tries)))
res)))
And finally put it all into a macro if you want it to be less verbose:
(defmacro with-retries
[retries & body]
`(loop [retries# ~retries]
(let [res# (try ~#body
(catch Exception e#
(if retries#
'retry#
(throw e#))))]
(if (= 'retry# res#)
(do (Thread/sleep (first retries#))
(recur (next retries#)))
res#))))
(with-retries [10 10 100 1000]
(might-throw-exception))