Clojure closure not behaving as expected? - clojure

The repl returns 2 when expected to return 5.
(defn counter []
(let [count 1]
(fn []
(+ count 1)
)
)
)
(defn test-counter []
(let [increment (counter)]
(increment)
(increment)
(increment)
(increment)
)
)

count is not a mutable variable so (+ count 1) does not change its value. If you want mutation you can store the count in an atom and update it using swap!:
(defn counter []
(let [count (atom 0)]
(fn [] (swap! count inc))))

Related

clojure.lang.LazySeq cannot be cast to class clojure.lang.Associative

I'm new to Clojure and I tried to implement a genetic algorithm. Thus, I've got a problem, the implementation keeps throwing the following error:
class clojure.lang.LazySeq cannot be cast to class clojure.lang.Associative (clojure.lang.LazySeq and clojure.lang.Associative are in unnamed module
of loader 'app')
To be mentioned that each function is tested individually in REPL and returns the correct results but after putting them all together, the error is thrown, and I don't understand it since it doesn't seems to specify a line number.
The version of clojure is the one from master branch and built with maven, on Windows.
The full code:
(ns ga)
(defn new-individual
[genome-length]
{:genome (vec (repeatedly genome-length #(rand-int 2))) :fitness 0}
)
(defn fitness-function
[genome, target]
(Math/abs (- (reduce + genome) target))
)
(defn calculate-fitness
[population, target]
(defn fitness-function-helper
[individual, target]
(assoc individual :fitness (fitness-function (individual :genome) target))
)
(map (fn [individual] (#(fitness-function-helper individual target))) population)
)
(defn crossover
[first-individual, second-individual, crossover-rate, target]
(let [new-genome (map (fn [i1,i2] (let [crossover-probability (rand)]
(cond
(<= crossover-probability crossover-rate) i1
:else i2
)
)
)
(first-individual :genome) (second-individual :genome)
)]
{:genome new-genome :fitness (fitness-function new-genome target)}
)
)
(defn mutate
[individual, genome-length, target]
(let [new-genome (assoc (individual :genome) (rand-int genome-length) (rand-int 2))]
{:genome new-genome :fitness (fitness-function new-genome target)}
)
)
(defn better
[i1 i2]
(< (i1 :fitness) (i2 :fitness)))
(defn tournament-selection
[population, population-size, steps, tournament-size, new-population, target]
(if (< steps tournament-size)
(recur population population-size (inc steps) tournament-size (conj new-population (nth population ((comp rand-int -) population-size 2))) target
)
;(println new-population)
(first (sort better (calculate-fitness new-population target)))
)
)
(defn new-generation [population, population-size, crossover-rate, target, tournament-size]
(loop [steps 0 new-population ()]
(if (< steps population-size)
(let [i1 (tournament-selection population population-size 0 tournament-size () target)]
(let [i2 (tournament-selection population population-size 0 tournament-size () target)]
(let [offs (crossover i1 i2 crossover-rate target)]
(recur (inc steps) (conj new-population offs))
)
)
)
new-population
)
)
)
(defn new-mutated-generation [population, population-size, genome-length, target]
(loop [steps 0 new-population ()]
(if (< steps population-size)
(recur (inc steps) (conj new-population (mutate (nth population steps) genome-length target)))
new-population
)
)
)
(defn evolve [population-size, genome-length, target]
(let [population (calculate-fitness (repeatedly population-size #(new-individual genome-length)) target)]
(let [offsprings (new-generation population population-size 0.5 target 5)]
(println (new-mutated-generation offsprings population-size genome-length target))
)
)
)
(evolve 10 5 5)
A stacktrace reveals that the problematic code is the line
(let [new-genome (assoc (vec (individual :genome)) (rand-int genome-length) (rand-int 2))]
and more specifically, the call to assoc. If we edit the code by inserting the following line just above:
(println "Individual: " (individual :genome) ", " (class (individual :genome)))
it prints out
Individual: (0 1 1 0 1) , clojure.lang.LazySeq
The problem is that assoc cannot be used with lazy sequences (clojure.lang.LazySeq) because it does not implement the clojure.lang.Associative interface which is needed by assoc.
This lazy sequence is constructed by the call to map on this line:
(let [new-genome (map (fn [i1,i2] (let [crossover-probability (rand)]
If you replace map by mapv so that the code looks like this
(let [new-genome (mapv (fn [i1,i2] (let [crossover-probability (rand)]
the code will work.
Error happens in the function mutate. It has this source:
(defn mutate
[individual, genome-length, target]
(let [new-genome (assoc (individual :genome) (rand-int genome-length) (rand-int 2))]
{:genome new-genome :fitness (fitness-function new-genome target)}))
In one step, you are calling it with these arguments: {:genome (0 1 1 1 1), :fitness 1} 5 5 (genome can have different value, but it's always sequence of numbers).
(individual :genome) returns (0 1 1 1 1) (sequence) and then you used assoc, which is function for hash maps or vectors.
Genome is vector at the beginning, but it's converted into sequence in crossover function- use mapv instead of map here:
(defn crossover
[first-individual, second-individual, crossover-rate, target]
(let [new-genome (mapv (fn [i1, i2] (let [crossover-probability (rand)]
(if (<= crossover-probability crossover-rate) i1 i2)))
(first-individual :genome) (second-individual :genome))]
{:genome new-genome :fitness (fitness-function new-genome target)}))
By the way, all parentheses at the end of definition belong at the same line.

Lazy Sequence Clojure

I was trying to modify a vector of vector but ended up with lazy-seq inside. I am new to clojure. Can someone help me to get this correctly?
(require '[clojure.string :as str])
;;READ CUST.TXT
(def my_str(slurp "cust.txt"))
(defn esplit [x] (str/split x #"\|" ))
(def cust (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i cust] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH CUST
(defn cust_find [x] (for [i cust :when (= (first i) x )] (do (nth i 1))))
(type (cust_find "2"))
;;READ PROD.TXT
(def my_str(slurp "prod.txt"))
(def prod (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i prod] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH PROD
(defn prod_find [x y] (for [i prod :when (= (first i) x )] (nth i y)))
(prod_find "2" 1)
(def my_str(slurp "sales.txt"))
(def sales (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
; (for [i (range(count sales))] (cust_find (nth (nth sales i) 1)))
; (defn fill_sales_1 [x]
; (assoc x 1
; (cust_find (nth x 1))))
; (def sales(map fill_sales_1 (sales)))
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (str (cust_find (nth (nth sales i) 1)))))))
; (for [i (range(count sales))] (assoc (nth sales i) 2 (str (prod_find (nth (nth sales i) 2) 1))))
(for [i sales] (println i))
When I print sales vector I get
[1 clojure.lang.LazySeq#10ae5ccd 1 3]
[2 clojure.lang.LazySeq#a5d0ddf9 2 3]
[3 clojure.lang.LazySeq#a5d0ddf9 1 1]
[4 clojure.lang.LazySeq#d80cb028 3 4]
If you need the text files I will upload them as well.
In Clojure, for and map, as well as other functions and macros working with sequences, generate a lazy sequence instead of a vector.
In the REPL, lazy sequences are usually fully computed when printing - to have it printed, it's enough to remove the str in your second to last line:
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (cust_find (nth (nth sales i) 1))))))
Just in case, note that your code can be prettified / simplified to convey the meaning better. For example, you are just iterating over a sequence of sales - you don't need to iterate over the indices and then get each item using nth:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (nth rec 1)))))
Second, you can replace nth ... 1 with second - it will be easier to understand:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (second rec))))
Or, alternatively, you can just use update instead of assoc:
(def sales
(vec (for [rec sales])
(update rec 1 cust_find)))
And, do you really need the outer vec here? You can do most of what you intend without it:
(def sales
(for [rec sales])
(update rec 1 cust_find))
Also, using underscores in Clojure function names is considered bad style: dashes (as in cust-find instead of cust_find) are easier to read and easier to type.
(for [i sales] (println (doall i)))
doall realizes a lazy sequence. Bare in mind that if the sequence is huge, you might not want to do this.

Clojure: nth not supported on this type: Boolean"

I am trying to implement the dining philosopher example in clojure.
For some reasons my program always dies with an exception saying
"java.lang.UnsupportedOperationException: nth not supported on this
type: Boolean"
I can't understand this error message since I already tried to get boolean values from a list which worked perfectly with nth
I guess the error happens in the if statement in the function philosopher-thread
Console Prints:
3 is thinking
1 is thinking
4 is thinking
0 is thinking
2 is thinking
0 after sleep
0 after think
0 swap
0 is eating
3 after sleep
3 after think
Code:
(ns dining-philosphers.core
(:gen-class))
(defn think [n]
(println (str n " is thinking"))
(Thread/sleep (rand 1000))
(println (str n " after sleep"))
)
(defn eat [n]
(println (str n " is eating"))
(Thread/sleep (rand 1000))
)
(def isEating (atom '(false false false false false)))
(defn philosopher-thread [n]
(Thread. #(
(while true (do
(think n)
(println (str n " after think"))
(if (or (nth #isEating (mod (- n 1) 5)) (nth #isEating (mod (+ n 1) 5)))
(println "is waiting for neighbour")
(
do
(println (str n " swap"))
(swap! isEating (fn [l] assoc l n true))
(eat n)
(swap! isEating (fn [l] assoc l n true))
)
)
)
)
)
)
)
(defn -main [& args]
(let [threads (map philosopher-thread (range 5))]
(doseq [thread threads] (.start thread))
(doseq [thread threads] (.join thread))))
You're missing some parens here:
(swap! isEating (fn [l] assoc l n true))
should be
(swap! isEating (fn [l] (assoc l n true)))
The first will evaluate assoc, l, n and true in order, and return the value of the last expression (true)
There is still a problem, which is that you can't assoc onto a list. I suggest using a vector instead:
(def isEating (atom [false false false false false]))

Clojure AND / OR of Sets

(defn GetValuesFromWhereCommand
"return a list of values from Where command"
[Query tableName]
(let [values (re-seq #"[0-9a-zA-Z_=<>]+" ((re-find #"WHERE(.*)" Query) 1))
bitwise (re-find #"AND|OR" Query)
tempList (ref #{})
]
; first loop will look for the operators = < >
(doseq [item values]
(let [result (case (re-find #"[=><]" item)
"=" (GetRowsfromCondition tableName item = )
"<" (GetRowsfromCondition tableName item < )
">" (GetRowsfromCondition tableName item > )
nil (println "nothing")
)]
(when (not= nil result) (dosync (alter tempList conj result)) )
tempList)
)
(println tempList)
tempList) ; get the Where from Update ','
)
here is my output.
#<Ref#5a4e229e: #{#<Ref#3fc2e163: #{0}> #<Ref#63280c85: #{0 1}>}>
i would like to make implement AND operation that will return #{0}
and OR that will return #{0 1}.
my problem is how to access the lists i have created. I wasn't able to use union/intersection for some reason.
You should deref all the inner sets and apply union to the new set
it should look somthing like this:
(let [newList (ref #{})] (doseq [item #your_ref_to_set_of_refs] (dosync (alter newList conj #item))) (apply union #newList))

How to get a collection of return values from a function with side effects?

Looking for a way to generate a collection of return values from a function with side effects, so that I could feed it to take-while.
(defn function-with-side-effects [n]
(if (> n 10) false (do (perform-io n) true)))
(defn call-function-with-side-effects []
(take-while true (? (iterate inc 0) ?)))
UPDATE
Here is what I have after Jan's answer:
(defn function-with-side-effects [n]
(if (> n 10) false (do (println n) true)))
(defn call-function-with-side-effects []
(take-while true? (map function-with-side-effects (iterate inc 0))))
(deftest test-function-with-side-effects
(call-function-with-side-effects))
Running the test doesn't print anything. Using doall results in out of memory exception.
Shouldn't a map solve the problem?
(defn call-function-with-side-effects []
(take-while true? (map function-with-side-effects (iterate inc 0))))
If you want all side effects to take effect use doall. Related: How to convert lazy sequence to non-lazy in Clojure.
(defn call-function-with-side-effects []
(doall (take-while true? (map function-with-side-effects (iterate inc 0)))))
Mind that I replaced the true in the second line with true? assuming that this was what you meant.