Why doesn't this recur within a mapcat terminate? - recursion

Why doesn't this recur within mapcat terminate, whereas the named fn call version equivalent does?
(def tree [1 [2 [3 5]] [6 [[1 2] [8 [9 10]]]]])
(defn leaves
[node]
(mapcat #(if (vector? %) (leaves %) [%]) node))
(leaves tree)
;; => (1 2 3 5 6 1 2 8 9 10)
(defn leaves-with-recur
[node]
(mapcat #(if (vector? %) (recur %) [%]) node))
(leaves-with-recur tree)
;; Never terminates
If such use of recur is a straight-forward no-no, is there any reason why the Clojure compiler should not catch this scenario and warn the programmer, or refuse to compile it even? As is the case for non-tail position invocations of recur for instance.

#(if (vector? %) (recur %) [%])
is a shorthand for
(fn [%]
(if (vector? %)
(recur %)
[%]))
That recur will recurse to this anonymous function, not to any outer one, and since it doesn't change anything, this is an endless loop.
As for warning—the halting problem is known to be unsolvable, and there is a risk of falling into an endless loop at compile time even when just trying to put some heuristics into place.

Related

Clojure loop and recur or reduce in state space model

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))))

How can i recursively calculate the depth of a tree structure in Clojure?

So i've got a very basic understanding of Clojure and would like to calculate the depth of a tree defined using a vector containing vectors itself. For instance, [1 [2] [3 [4] ]] would represent a tree where 1 is the root while [2] is a child to 1 and [3 [4]] a subtree.
(defn height[tree]
(if(empty? tree)
(1); Base case
(inc (apply max (map height (next tree))))); Calculate the height for every subtree and return maximum
)
I was thinking that this method would work, as it's supposed to recursively calculate the depth of every subtree to return the maximum value. However, i get an Illegal argument exception when I try to run this method.
tail recursive variant with zippers:
(require '[clojure.zip :as z])
(defn height-2 [tree]
(loop [curr (z/zipper coll? seq nil tree) h 0]
(if (z/end? curr) h
(recur (z/next curr)
(if (z/branch? curr) h
(-> curr z/path count (max h)))))))
in repl:
user> (height-2 [1 [2] [3 [4] ]])
3
user> (height-2 (nth (iterate (partial vector 1) []) 1000))
1000
user> (height-2 (nth (iterate (partial vector 1) []) 100000))
100000
(1) is wrong. It tries to execute 1 as a function.
You need to be able to cope with leaves in the tree, which are not
vectors.
The next call is wrong - leave it out.
Try
(defn height [tree]
(if (vector? tree)
(if (empty? tree)
1
(inc (apply max (map height tree))))
0))
For example,
(height [1 [2] [3 [4] ]]) ; 3
A slightly simpler version is
(defn height [tree]
(if (vector? tree)
(inc (apply max 0 (map height tree)))
0))
By supplying an initial/default argument 0 to the max, we deal with an empty collection without a condition.

If the only non-stack-consuming looping construct in Clojure is "recur", how does this lazy-seq work?

The ClojureDocs page for lazy-seq gives an example of generating a lazy-seq of all positive numbers:
(defn positive-numbers
([] (positive-numbers 1))
([n] (cons n (lazy-seq (positive-numbers (inc n))))))
This lazy-seq can be evaluated for pretty large indexes without throwing a StackOverflowError (unlike the sieve example on the same page):
user=> (nth (positive-numbers) 99999999)
100000000
If only recur can be used to avoid consuming stack frames in a recursive function, how is it possible this lazy-seq example can seemingly call itself without overflowing the stack?
A lazy sequence has the rest of the sequence generating calculation in a thunk. It is not immediately called. As each element (or chunk of elements as the case may be) is requested, a call to the next thunk is made to retrieve the value(s). That thunk may create another thunk to represent the tail of the sequence if it continues. The magic is that (1) these special thunks implement the sequence interface and can transparently be used as such and (2) each thunk is only called once -- its value is cached -- so the realized portion is a sequence of values.
Here it is the general idea without the magic, just good ol' functions:
(defn my-thunk-seq
([] (my-thunk-seq 1))
([n] (list n #(my-thunk-seq (inc n)))))
(defn my-next [s] ((second s)))
(defn my-realize [s n]
(loop [a [], s s, n n]
(if (pos? n)
(recur (conj a (first s)) (my-next s) (dec n))
a)))
user=> (-> (my-thunk-seq) first)
1
user=> (-> (my-thunk-seq) my-next first)
2
user=> (my-realize (my-thunk-seq) 10)
[1 2 3 4 5 6 7 8 9 10]
user=> (count (my-realize (my-thunk-seq) 100000))
100000 ; Level stack consumption
The magic bits happen inside of clojure.lang.LazySeq defined in Java, but we can actually do the magic directly in Clojure (implementation that follows for example purposes), by implementing the interfaces on a type and using an atom to cache.
(deftype MyLazySeq [thunk-mem]
clojure.lang.Seqable
(seq [_]
(if (fn? #thunk-mem)
(swap! thunk-mem (fn [f] (seq (f)))))
#thunk-mem)
;Implementing ISeq is necessary because cons calls seq
;on anyone who does not, which would force realization.
clojure.lang.ISeq
(first [this] (first (seq this)))
(next [this] (next (seq this)))
(more [this] (rest (seq this)))
(cons [this x] (cons x (seq this))))
(defmacro my-lazy-seq [& body]
`(MyLazySeq. (atom (fn [] ~#body))))
Now this already works with take, etc., but as take calls lazy-seq we'll make a my-take that uses my-lazy-seq instead to eliminate any confusion.
(defn my-take
[n coll]
(my-lazy-seq
(when (pos? n)
(when-let [s (seq coll)]
(cons (first s) (my-take (dec n) (rest s)))))))
Now let's make a slow infinite sequence to test the caching behavior.
(defn slow-inc [n] (Thread/sleep 1000) (inc n))
(defn slow-pos-nums
([] (slow-pos-nums 1))
([n] (cons n (my-lazy-seq (slow-pos-nums (slow-inc n))))))
And the REPL test
user=> (def nums (slow-pos-nums))
#'user/nums
user=> (time (doall (my-take 10 nums)))
"Elapsed time: 9000.384616 msecs"
(1 2 3 4 5 6 7 8 9 10)
user=> (time (doall (my-take 10 nums)))
"Elapsed time: 0.043146 msecs"
(1 2 3 4 5 6 7 8 9 10)
Keep in mind that lazy-seq is a macro, and therefore does not evaluate its body when your positive-numbers function is called. In that sense, positive-numbers isn't truly recursive. It returns immediately, and the inner "recursive" call to positive-numbers doesn't happen until the seq is consumed.
user=> (source lazy-seq)
(defmacro lazy-seq
"Takes a body of expressions that returns an ISeq or nil, and yields
a Seqable object that will invoke the body only the first time seq
is called, and will cache the result and return it on all subsequent
seq calls. See also - realized?"
{:added "1.0"}
[& body]
(list 'new 'clojure.lang.LazySeq (list* '^{:once true} fn* [] body)))
I think the trick is that the producer function (positive-numbers) isn't getting called recursively, it doesn't accumulate stack frames as if it was called with basic recursion Little-Schemer style, because LazySeq is invoking it as needed for the individual entries in the sequence. Once a closure gets evaluated for an entry then it can be discarded. So stack frames from previous invocations of the function can get garbage-collected as the code churns through the sequence.

Getting index and size of collection when using the map function

I have this scenario. I use the map function in Clojure to apply a custom function on a collection. This function takes a while to execute and my collection is pretty large. I would like to be able to print something like this during each call of my function:
"Doing some stuff... (index/total)"
where index is the current element in the collection and total is the size. Is there a way to do this easily in clojure? I could send the size as a parameter to my collection. Also, I could, probably, use some kind of counter, but I was wondering if there was something built-in...
Thanks
user=> (map-indexed (fn [idx itm] [idx itm]) "foobar")
([0 \f] [1 \o] [2 \o] [3 \b] [4 \a] [5 \r])
map-indexed
(defn sebi [collection]
(map-indexed #(println (format "Doing some stuff with %s (%d/%d)"
%2 (inc %1) (count collection)))
collection))
(sebi ["Mary" "had" "a" "little" "lamb"])
You may pass lazy counter and sequence of size into map with collection.
(defn sebi [collection]
(map #(println (format "Doing some staff with %s (%d/%d)" %1 (inc %2) %3))
collection
(range)
(repeat (count collection)))
(sebi ["Mary" "had" "a" "little" "lamb"])
The other answers will work, but you might wan to modify them so the total is only calculated once (i.e. use a "(let [cnt (count collection)]...). Or you could look at clj-progress which is a full featured progress reporting lib.
(defn map-reporting
[msg f coll]
(let [c (count coll)]
(doall (map-indexed (fn [e i]
(println msg (str "[" (inc i) "/" c "]"))
(f e)) coll))))
user> (map-reporting "Doing some stuff" inc (range 5))
Doing some stuff [1/5]
Doing some stuff [2/5]
Doing some stuff [3/5]
Doing some stuff [4/5]
Doing some stuff [5/5]
(1 2 3 4 5)

Recursively reverse a sequence in Clojure

I want to reverse a sequence in Clojure without using the reverse function, and do so recursively.
Here is what I came up with:
(defn reverse-recursively [coll]
(loop [r (rest coll)
acc (conj () (first coll))]
(if (= (count r) 0)
acc
(recur (rest r) (conj acc (first r))))))
Sample output:
user> (reverse-recursively '(1 2 3 4 5 6))
(6 5 4 3 2 1)
user> (reverse-recursively [1 2 3 4 5 6])
(6 5 4 3 2 1)
user> (reverse-recursively {:a 1 :b 2 :c 3})
([:c 3] [:b 2] [:a 1])
Questions:
Is there a more concise way of doing this, i.e. without loop/recur?
Is there a way to do this without using an "accumulator" parameter in the loop?
References:
Whats the best way to recursively reverse a string in Java?
http://groups.google.com/group/clojure/browse_thread/thread/4e7a4bfb0d71a508?pli=1
You don't need to count. Just stop when the remaining sequence is empty.
You shouldn't pre-populate the acc, since the original input may be empty (and it's more code).
Destructuring is cool.
(defn reverse-recursively [coll]
(loop [[r & more :as all] (seq coll)
acc '()]
(if all
(recur more (cons r acc))
acc)))
As for loop/recur and the acc, you need some way of passing around the working reversed list. It's either loop, or add another param to the function (which is really what loop is doing anyway).
Or use a higher-order function:
user=> (reduce conj '() [1 2 3 4])
(4 3 2 1)
For the sake of exhaustivenes, there is one more method using into. Since into internally uses conj it can be used as follows :
(defn reverse-list
"Reverse the element of alist."
[lst]
(into '() lst))
Yes to question 1, this is what I came up with for my answer to the recursion koan (I couldn't tell you whether it was good clojure practice or not).
(defn recursive-reverse [coll]
(if (empty? coll)
[]
(conj (recursive-reverse (rest coll)) (first coll) )))
In current version of Clojure there's a built-in function called rseq. For anyone who passes by.
(defn my-rev [col]
(loop [ col col
result []]
(if (empty? col)
result
(recur (rest col) (cons (first col) result)))))
Q1.
The JVM can not optimize the recursion, a recursive function that would directly and stack overflow. Therefore, in Clojure, which uses the loop/recur. So, without using a function that recur deep recursion can not be defined. (which is also used internally to recur as a function trampoline.)
Q2.
a recursive function by recur, must be tail-recursive. If the normal recursive function change to tail-recursive function, so there is a need to carry about the value of a variable is required as the accumulator.
(defn reverse-seq [sss]
(if (not (empty? sss))
(conj (reverse-seq (rest sss)) (first sss))
)
)
(defn recursive-reverse [coll]
(if (empty? coll)
()
(concat (vector (peek coll)) (recursive-reverse (pop coll )))
)
)
and test:
user=> (recursive-reverse [1])
(1)
user=> (recursive-reverse [1 2 3 4 5])
(5 4 3 2 1)

Resources