I'm currently going through the 4clojure Problem 23
My current solution uses recursion to go through the list and append each element to the end of the result of the same function:
(fn self [x] (if (= x [])
x
(conj (self (rest x)) (first x))
))
But when I run it against [1 2 3] it gives me (1 2 3)
What I think it should be doing through recursion is:
(conj (conj (conj (conj (conj [] 5) 4) 3) 2) 1)
which does return
[5 4 3 2 1]
But it is exactly the opposite, so I must be missing something. Also, I don't understand why ones return a vector and the other one returns a list.
When you do (rest v) you're getting a list (not a vector), and then conj is appending to the front each time (not the back):
user=> (defn self [v] (if (empty? v) v (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
(1 2 3)
user=> (defn self [v] (if (empty? v) [] (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
[3 2 1]
user=>
user=> (rest [1])
()
user=> (conj '() 2)
(2)
user=> (conj '(2) 1)
(1 2)
user=>
Related
I am trying to rewrite this piece of code from https://github.com/lspector/gp/blob/master/src/gp/evolvefn_zip.clj
to use recur:
(defn random-code [depth]
(if (or (zero? depth)
(zero? (rand-int 2)))
(random-terminal)
(let [f (random-function)]
(cons f (repeatedly (get function-table f)
#(random-code (dec depth)))))))
The problem is, I have absolutely no idea how to do that.
The only thing I can think of is something like this:
(defn random-code [depth]
(loop [d depth t 0 c []]
(if (or (zero? depth)
(zero? (rand-int 2)))
(if (= t 0)
(conj c random-terminal)
(recur depth (dec t) (conj c (random-terminal))))
(let [f (random-function)]
(if (= t 0)
(recur (dec depth) (function-table f) (conj c f))
(recur depth (dec t) (conj c f)))))))
It's not a working piece of code, it's just to show the way I would try to solve it, it would only get more and more convoluted.
Is there a better way to convert normal recursion to tail recursion in clojure?
Here are 2 examples comparing a recursive algorithm and loop-recur:
(defn fact-recursion [n]
(if (zero? n)
1
(* n (fact-recursion (dec n)))))
(defn fact-recur [n]
(loop [count n
result 1]
(if (pos? count)
(recur (dec count) (* result count))
result )))
(fact-recursion 5) => 120
(fact-recur 5) => 120
(defn rangy-recursive [n]
(if (pos? n)
(cons n (rangy-recursive (dec n)))
[n]))
(defn rangy-recur [n]
(loop [result []
count n]
(if (pos? count)
(recur (conj result count) (dec count))
result)))
(rangy-recursive 5) => (5 4 3 2 1 0)
(rangy-recur 5) => [5 4 3 2 1]
The basic difference is that for loop-recur you need a 2nd loop "variable" (here named result) to accumulate the output of the algorithm. For plain recursion, the call stack accumulates the intermediate result.
I am trying to write up a simple Markovian state space models, that, as the name suggests iteratively looks back one step to predict the next state.
Here is what is supposed to be a MWE, though it is not because I cannot quite figure out how I am supposed to place (recur ... ) in the below code.
;; helper function
(defn dur-call
[S D]
(if (< 1 D)
(- D 1)
(rand-int S)))
;; helper function
(defn trans-call
[S D]
(if (< 1 D)
S
(rand-int 3)))
;; state space model
(defn test-func
[t]
(loop
[S (rand-int 3)]
(if (<= t 0)
[S (rand-int (+ S 1))]
(let [pastS (first (test-func (- t 1)))
pastD (second (test-func (- t 1)))
S (trans-call pastS pastD)]
(recur ...?)
[S (dur-call S pastD)]))))
My target is to calculate some a state at say time t=5 say, in which case the model needs to look back and calculate states t=[0 1 2 3 4] as well. This should, in my mind, be done well with loop/recur but could also be done with reduce perhaps (not sure how, still new to Clojure). My problem is really that it would seemt have to use recur inside let but that should not work given how loop/recur are designed.
your task is really to generate the next item based on the previous one, starting with some seed. In clojure it can be fulfilled by using iterate function:
user> (take 10 (iterate #(+ 2 %) 1))
(1 3 5 7 9 11 13 15 17 19)
you just have to define the function to produce the next value. It could look like this (not sure about the correctness of the computation algorithm, just based on what is in the question):
(defn next-item [[prev-s prev-d :as prev-item]]
(let [s (trans-call prev-s prev-d)]
[s (dur-call s prev-d)]))
and now let's iterate with it, starting from some value:
user> (take 5 (iterate next-item [3 4]))
([3 4] [3 3] [3 2] [3 1] [0 0])
now your test function could be implemented this way:
(defn test-fn [t]
(when (not (neg? t))
(nth (iterate next-item
(let [s (rand-int 3)]
[s (rand-int (inc s))]))
t)))
you can also do it with loop (but it is still less idiomatic):
(defn test-fn-2 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [results [[s d]]]
(if (< t (count results))
(peek results)
(recur (conj results (next-item (peek results)))))))))
here we pass all the accumulated results to the next iteration of the loop.
also you can introduce the loop's iteration index and just pass around the last result together with it:
(defn test-fn-3 [t]
(when (not (neg? t))
(let [s (rand-int 3)
d (rand-int (inc s))]
(loop [result [s d] i 0]
(if (= i t)
result
(recur (next-item result) (inc i)))))))
and one more example with reduce:
(defn test-fn-4 [t]
(when (not (neg? t))
(reduce (fn [prev _] (next-item prev))
(let [s (rand-int 3)
d (rand-int (inc s))]
[s d])
(range t))))
I want to add the values from a map on clojure with the next code:
(letfn [(r [l a]
(if (empty? l)
a
(if (map? l)
(r (first(vals l)) (+ a (first (vals l))))
(r (rest l) (+ a (first l))))))]
(r {:a 1 :b 2 :c 3} 0)
but I get the following error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
The problem is that in your code you are testing for empty on l, without being sure that l is a seq. You should look further in the stacktrace for that:
Don't know how to create ISeq from: java.lang.Long
RT.java: 528 clojure.lang.RT/seqFrom
RT.java: 509 clojure.lang.RT/seq
core.clj: 137 clojure.core/seq
core.clj: 5948 clojure.core/empty? <------
REPL: 13 user/eval19330/r
REPL: 16 user/eval19330/r
REPL: 21 user/eval19330
This happens because (first (vals l)) that is passed as the l parameter to the next iteration is a number and not a seq, in your case it is simply the value 1.
Your function r can only handle collections (as you call empty? and then test on map? and otherwise call rest). You probably want to recurse like this:
(letfn [(r [l a]
(if (empty? l)
a
(if (map? l)
(let [[key val] (first l)]
(r (dissoc l key) (+ a val)))
(r (rest l) (+ a (first l))))))]
(list (r {:a 1 :b 2 :c 3} 0)
(r [1 2 3] 0)))
This code will give the same error:
(empty? (first (vals {:a 1 :b 2 :c 3})))
Also
(empty? 2)
Also
(concat [3] 2 [4])
So I am trying to re-implement the reduce method, so it can add a couple of numbers that normally can be done using reduce, like:
(reduce + [1 2 3]) ;; 6
(newRd + [1 2 3]) ;; 6
So I thought maybe it can be done using a recursive function that adds the first element of the vector every time it is called and do it again for the rest of the vector. Something like this:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list))
(newRd (rest list))
)
)
)
I think I am not doing local storing correctly. Any suggestion or maybe a better approach?
there are two mistakes here in your code:
1) you don't add your current sum to the recursive call result
2) you should return zero when the list is empty
corrected variant:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list)
(newRd (rest list)))
sum)))
in repl:
user> (newRd [1 2 3 4])
10
next, you can update it a bit:
first you don't really need the sum in let statement, since the sum always = 0
second, there is a lib function empty? to check if list is empty.
(defn newRd [list]
(if-not (empty? list)
(+ (first list)
(newRd (rest list)))
0))
but remember: clojure doesnt'do tail call optimization, so it is easy to cause stack owerflow with a long list:
user> (newRd (repeat 1000000 1))
StackOverflowError user/newRd (form-init289434844644272272.clj:73)
so it's preferable to use loop/recur
(defn sum-list [list]
(loop [list list sum 0]
(if (empty? list)
sum
(recur (rest list) (+ sum (first list))))))
in repl:
user> (sum-list (repeat 1000000 1))
1000000
the other option is to make the function itself tail recursive:
(defn newRd [list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum))
user> (newRd (repeat 1000000 1) 0)
1000000
then you can add the additoinal arity, for not to pass the second parameter in every call:
(defn newRd
([list] (newRd list 0))
([list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum)))
Further to leetwinksi's answer ...
You might as well implement new-reduce (camel case is not idiomatic) in general:
(defn new-reduce
([f init coll]
(if (seq coll)
(recur f (f init (f init (first coll))) (rest coll))
init))
([f coll]
(if (seq coll)
(reduce f (first coll) (rest coll))
(f))))
Then
(new-reduce + [1 2 3]) ;; 6
This is more or less what the source code for reduce looked like until recently, if you stripped chunking out.
The two-argument version that you use leans on the three-argument version, which you can recur on directly, without an explicit loop. This entails passing f each time, but that's what it used to do. Presumably it's faster to carry an extra argument than to work in a local scope.
((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5)
For this code, the result is [5 4 3 2 1]
Why isn't is [1,2,3,4,5]?
I see we do conf from result of recursive foo call with a value.
For I thought it should be 1 2 3 4 5?
Need help to understand this.
Thanks.
From the documentation of conj:
clojure.core/conj
([coll x] [coll x & xs])
conj[oin]. Returns a new collection with the xs
'added'. (conj nil item) returns (item). The 'addition' may
happen at different 'places' depending on the concrete type.
The termination condition of your function yields nil, because the test is a when. So the deepest conj call will be:
(conj nil 1)
(1) <-- a list
The next one:
(conj (conj nil 1) 2)
(2 1)
So your result will be in decreasing order because conj appends at the front for lists. If you want it in increasing order, start with an empty vector like this:
((fn foo [x] (if (> x 0) (conj (foo (dec x)) x) [])) 5)
[1 2 3 4 5]
The recursive call expands to
(conj (conj (conj (conj (conj nil 1) 2) 3) 4) 5)
;(5 4 3 2 1)
The implicit nil returned by (foo 0) puns to ().