Why does this usage of recur in Clojure cause a crash? - recursion

I have this data structure:
(def initial-map {:name "Root"
:children [{:name "Child1" :children [{:name "Grandchild1"}]}
{:name "Child2"}
{:name "Child3"}]})
And I need to turn it into something like this:
[["Root" 0] ["Child1" 1] ["Child2" 1] ["Child3" 1] ["Grandchild1" 2]]
Where the numbers represent the depth of the node in the data structure.
I've written this function to try and go from the first to the second:
(defn node-xform [ret nodes depth]
(if empty? nodes)
ret
(recur (conj ret (map #(vector (:name %) depth) nodes))
(flatten (map #(:children %) nodes))
(inc depth)))
And am calling it like this
(node-xform [] (vector initial-map) 0)
But when I do, it either times out or crashes my computer... What am I doing wrong?

The if form should look like this:
(if conditional-expr true-expr false-expr)
The false-expr is actually optional, with a default value of nil if it's left off—but I don't think that's what you want. It looks like you want to return ret when nodes is empty, and recur otherwise:
(defn node-xform [ret nodes depth]
(if (empty? nodes) ; <-- fixed this line
ret
(recur (conj ret (map #(vector (:name %) depth) nodes))
(flatten (map #(:children %) nodes))
(inc depth)))) ; <-- added another close-paren here for the "if"
I didn't actually test to see if that returns your expected answer, but that will at least get rid of your infinite recursion problem.
Your code results in an infinite loop because node-xform always executes the recur form, which results in infinite tail recursion. Correcting the syntax for the if form makes it so that the recur expression is only executed when nodes is non-empty.

Related

Clojure: Vector is not immutable

I'm running into a problem where immutability suddenly doesn't hold for my vectors. I was wondering if there was a way to create fresh, immutable vector copies of a given set.
Clojuredocs suggested "aclone" but that is giving me an error stating that there's no such method.
(defn stripSame [word wordList]
(def setVec (into #{} wordList))
(def wordSet word)
(def wordVec (into #{} [wordSet]))
(def diffSet (set/difference setVec wordVec))
(def diffVec (into [] diffSet))
diffVec)
(defn findInsOuts [word passList]
(def wordList (stripSame word passList))
(println word wordList)
(def endLetter (subs word (dec (count word))))
(def startLetter (subs word 0 1))
(println startLetter endLetter)
(def outs (filter (partial starts endLetter) wordList))
(def ins (filter (partial ends startLetter) wordList))
;(println ins outs)
(def indexes [ (count ins) (count outs)])
indexes)
(defn findAll [passList]
(def wordList (into [] passList) ))
(println wordList)
(loop [n 0 indexList []]
(println "In here" (get wordList n) wordList)
(if (< n (count wordList))
(do
(def testList wordList)
(def indexes (findInsOuts (get wordList n) testList))
(println (get wordList n) indexes)
(recur (inc n) (conj indexList [(get wordList n) indexes]))))))
passList is a list of words like so (lol at good) which is then cast into a vector.
So basically findAll calls findInsOuts which goes through every word in the list and sees how many other words start with its last letter but which first removes the search word from the vector before performing some function to prevent duplicates. The problem is that somehow this vector is actually mutable, so the copy of the vector in findAll also has that value permanently stripped.
When I try to create a new vector and then act on that vector the same thing still happens, which implies that they're aliased/sharing the same memory location.
How can I create a fresh vector for use that is actually immutable?
Any help is appreciated
I'm afraid your code is riddled with misunderstandings. For a start, don't use def within defn. Use let instead. This turns your first function into ...
(defn stripSame [word wordList]
(let [setVec (into #{} wordList)
wordSet word
wordVec (into #{} [wordSet])
diffSet (clojure.set/difference setVec wordVec)
diffVec (into [] diffSet)]
diffVec))
For example,
=> (stripSame 2 [1 2 :buckle-my-shoe])
[1 :buckle-my-shoe]
The function can be simplified to ...
(defn stripSame [word wordList]
(vec (disj (set wordList) word)))
... or, using a threading macro, to ...
(defn stripSame [word wordList]
(-> wordList set (disj word) vec))
I don't think the function does what you think it does, because it doesn't always preserve the order of elements in the vector.
If I were you, I'd work my way through some of the community tutorials on this page. There are several good books referred to there too. Once you get to grips with the idioms of the language, you'll find the sort of thing you are trying to do here much clearer and easier.

clojure - (Another one) StackOverflow with loop/recur

I know this is a recurring question (here, here, and more), and I know that the problem is related to creating lazy sequencies, but I can't see why it fails.
The problem: I had written a (not very nice) quicksort algorithm to sort strings that uses loop/recur. But applied to 10000 elements, I get a StackOverflowError:
(defn qsort [list]
(loop [[current & todo :as all] [list] sorted []]
(cond
(nil? current) sorted
(or (nil? (seq current)) (= (count current) 1)) (recur todo (concat sorted current))
:else (let [[pivot & rest] current
pred #(> (compare pivot %) 0)
lt (filter pred rest)
gte (remove pred rest)
work (list* lt [pivot] gte todo)]
(recur work sorted)))))
I used in this way:
(defn tlfnum [] (str/join (repeatedly 10 #(rand-int 10))))
(defn tlfbook [n] (repeatedly n #(tlfnum)))
(time (count (qsort (tlfbook 10000))))
And this is part of the stack trace:
[clojure.lang.LazySeq seq "LazySeq.java" 49]
[clojure.lang.RT seq "RT.java" 521]
[clojure.core$seq__4357 invokeStatic "core.clj" 137]
[clojure.core$concat$fn__4446 invoke "core.clj" 706]
[clojure.lang.LazySeq sval "LazySeq.java" 40]
[clojure.lang.LazySeq seq "LazySeq.java" 49]
[clojure.lang.RT seq "RT.java" 521]
[clojure.core$seq__4357 invokeStatic "core.clj" 137]]}
As far as I know, loop/recur performs tail call optimization, so no stack is used (is, in fact, an iterative process written using recursive syntax).
Reading other answers, and because of the stack trace, I see there's a problem with concat and adding a doall before concat solves the stack overflow problem. But... why?
Here's part of the code for the two-arity version of concat.
(defn concat [x y]
(lazy-seq
(let [s (seq x)]
,,,))
)
Notice that it uses two other functions, lazy-seq, and seq. lazy-seq is a bit like a lambda, it wraps some code without executing it yet. The code inside the lazy-seq block has to result in some kind of sequence value. When you call any sequence operation on the lazy-seq, then it will first evaluate the code ("realize" the lazy seq), and then perform the operation on the result.
(def lz (lazy-seq
(println "Realizing!")
'(1 2 3)))
(first lz)
;; prints "realizing"
;; => 1
Now try this:
(defn lazy-conj [xs x]
(lazy-seq
(println "Realizing" x)
(conj (seq xs) x)))
Notice that it's similar to concat, it calls seq on its first argument, and returns a lazy-seq
(def up-to-hundred
(reduce lazy-conj () (range 100)))
(first up-to-hundred)
;; prints "Realizing 99"
;; prints "Realizing 98"
;; prints "Realizing 97"
;; ...
;; => 99
Even though you asked for only the first element, it still ended up realizing the whole sequence. That's because realizing the outer "layer" results in calling seq on the next "layer", which realizes another lazy-seq, which again calls seq, etc. So it's a chain reaction that realizes everything, and each step consumes a stack frame.
(def up-to-ten-thousand
(reduce lazy-conj () (range 10000)))
(first up-to-ten-thousand)
;;=> java.lang.StackOverflowError
You get the same problem when stacking concat calls. That's why for instance (reduce concat ,,,) is always a smell, instead you can use (apply concat ,,,) or (into () cat ,,,).
Other lazy operators like filter and map can exhibit the exact same problem. If you really have a lot of transformation steps over a sequence consider using transducers instead.
;; without transducers: many intermediate lazy seqs and deep call stacks
(->> my-seq
(map foo)
(filter bar)
(map baz)
,,,)
;; with transducers: seq processed in a single pass
(sequence (comp
(map foo)
(filter bar)
(map baz))
my-seq)
Arne had a good answer (and, in fact, I'd never noticed cat before!). If you want a simpler solution, you can use the glue function from the Tupelo library:
Gluing Together Like Collections
The concat function can sometimes have rather surprising results:
(concat {:a 1} {:b 2} {:c 3} )
;=> ( [:a 1] [:b 2] [:c 3] )
In this example, the user probably meant to merge the 3 maps into one. Instead, the three maps were mysteriously converted into length-2 vectors, which were then nested inside another sequence.
The conj function can also surprise the user:
(conj [1 2] [3 4] )
;=> [1 2 [3 4] ]
Here the user probably wanted to get [1 2 3 4] back, but instead got a nested vector by mistake.
Instead of having to wonder if the items to be combined will be merged, nested, or converted into another data type, we provide the glue function to always combine like collections together into a result collection of the same type:
; Glue together like collections:
(is (= (glue [ 1 2] '(3 4) [ 5 6] ) [ 1 2 3 4 5 6 ] )) ; all sequential (vectors & lists)
(is (= (glue {:a 1} {:b 2} {:c 3} ) {:a 1 :c 3 :b 2} )) ; all maps
(is (= (glue #{1 2} #{3 4} #{6 5} ) #{ 1 2 6 5 3 4 } )) ; all sets
(is (= (glue "I" " like " \a " nap!" ) "I like a nap!" )) ; all text (strings & chars)
; If you want to convert to a sorted set or map, just put an empty one first:
(is (= (glue (sorted-map) {:a 1} {:b 2} {:c 3}) {:a 1 :b 2 :c 3} ))
(is (= (glue (sorted-set) #{1 2} #{3 4} #{6 5}) #{ 1 2 3 4 5 6 } ))
An Exception will be thrown if the collections to be 'glued' are not all of the same type. The allowable input types are:
all sequential: any mix of lists & vectors (vector result)
all maps (sorted or not)
all sets (sorted or not)
all text: any mix of strings & characters (string result)
I put glue into your code instead of concat and still got a StackOverflowError. So, I also replaced the lazy filter and remove with eager versions keep-if and drop-if to get this result:
(defn qsort [list]
(loop [[current & todo :as all] [list] sorted []]
(cond
(nil? current) sorted
(or (nil? (seq current)) (= (count current) 1))
(recur todo (glue sorted current))
:else (let [[pivot & rest] current
pred #(> (compare pivot %) 0)
lt (keep-if pred rest)
gte (drop-if pred rest)
work (list* lt [pivot] gte todo)]
(recur work sorted)))))
(defn tlfnum [] (str/join (repeatedly 10 #(rand-int 10))))
(defn tlfbook [n] (repeatedly n #(tlfnum)))
(def result
(time (count (qsort (tlfbook 10000)))))
-------------------------------------
Clojure 1.8.0 Java 1.8.0_111
-------------------------------------
"Elapsed time: 1377.321118 msecs"
result => 10000

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.

In Clojure, is it possible to combine memoization and tail call optimization?

In clojure, I would like to write a tail-recursive function that memoizes its intermediate results for subsequent calls.
[EDIT: this question has been rewritten using gcd as an example instead of factorial.]
The memoized gcd (greatest common divisor) could be implemented like this:
(def gcd (memoize (fn [a b]
(if (zero? b)
a
(recur b (mod a b))))
In this implementation, intermediate results are not memoized for subsequent calls. For example, in order to calculate gcd(9,6), gcd(6,3) is called as an intermediate result. However, gcd(6,3) is not stored in the cache of the memoized function because the recursion point of recur is the anonymous function that is not memoized.
Therefore, if after having called gcd(9,6), we call gcd(6,3) we won't benefit from the memoization.
The only solution I can think about will be to use mundane recursion (explicitely call gcd instead of recur) but then we will not benefit from Tail Call Optimization.
Bottom Line
Is there a way to achieve both:
Tail call optimization
Memoization of intermediate results for subsequent calls
Remarks
This question is similar to Combine memoization and tail-recursion. But all the answers there are related to F#. Here, I am looking for an answer in clojure.
This question has been left as an exercise for the reader by The Joy of Clojure (chap 12.4). You can consult the relevant page of the book at http://bit.ly/HkQrio.
in your case it's hard to show memoize do anything with factorial because the intermediate calls are unique, so I'll rewrite a somewhat contrived example assuming the point is to explore ways to avoid blowing the stack:
(defn stack-popper [n i]
(if (< i n) (* i (stack-popper n (inc i))) 1))
which can then get something out of a memoize:
(def stack-popper
(memoize (fn [n i] (if (< i n) (* i (stack-popper n (inc i))) 1))))
the general approaches to not blowing the stack are:
use tail calls
(def stack-popper
(memoize (fn [n acc] (if (> n 1) (recur (dec n) (* acc (dec n))) acc))))
use trampolines
(def stack-popper
(memoize (fn [n acc]
(if (> n 1) #(stack-popper (dec n) (* acc (dec n))) acc))))
(trampoline (stack-popper 4 1))
use a lazy sequence
(reduce * (range 1 4))
None of these work all the time, though I have yet to hit a case where none of them work. I almost always go for the lazy ones first because I find them to be most clojure like, then I head for tail calling with recur or tramplines
(defmacro memofn
[name args & body]
`(let [cache# (atom {})]
(fn ~name [& args#]
(let [update-cache!# (fn update-cache!# [state# args#]
(if-not (contains? state# args#)
(assoc state# args#
(delay
(let [~args args#]
~#body)))
state#))]
(let [state# (swap! cache# update-cache!# args#)]
(-> state# (get args#) deref))))))
This will allow a recursive definition of a memoized function, which also caches intermediate results. Usage:
(def fib (memofn fib [n]
(case n
1 1
0 1
(+ (fib (dec n)) (fib (- n 2))))))
(def gcd
(let [cache (atom {})]
(fn [a b]
#(or (#cache [a b])
(let [p (promise)]
(deliver p
(loop [a a b b]
(if-let [p2 (#cache [a b])]
#p2
(do
(swap! cache assoc [a b] p)
(if (zero? b)
a
(recur b (mod a b))))))))))))
There is some concurrency issues (double evaluation, the same problem as with memoize, but worse because of the promises) which may be fixed using #kotarak's advice.
Turning the above code into a macro is left as an exercise to the reader. (Fogus's note was imo tongue-in-cheek.)
Turning this into a macro is really a simple exercise in macrology, please remark that the body (the 3 last lines) remain unchanged.
Using Clojure's recur you can write factorial using an accumulator that has no stack growth, and just memoize it:
(defn fact
([n]
(fact n 1))
([n acc]
(if (= 1 n)
acc
(recur (dec n)
(* n acc)))))
This is factorial function implemented with anonymous recursion with tail call and memoization of intermediate results. The memoization is integrated with the function and a reference to shared buffer (implemented using Atom reference type) is passed by a lexical closure.
Since the factorial function operates on natural numbers and the arguments for succesive results are incremental, Vector seems more tailored data structure to store buffered results.
Instead of passing the result of a previous computation as an argument (accumulator) we're getting it from the buffer.
(def ! ; global variable referring to a function
(let [m (atom [1 1 2 6 24])] ; buffer of results
(fn [n] ; factorial function definition
(let [m-count (count #m)] ; number of results in a buffer
(if (< n m-count) ; do we have buffered result for n?
(nth #m n) ; · yes: return it
(loop [cur m-count] ; · no: compute it recursively
(let [r (*' (nth #m (dec cur)) cur)] ; new result
(swap! m assoc cur r) ; store the result
(if (= n cur) ; termination condition:
r ; · base case
(recur (inc cur)))))))))) ; · recursive case
(time (do (! 8000) nil)) ; => "Elapsed time: 154.280516 msecs"
(time (do (! 8001) nil)) ; => "Elapsed time: 0.100222 msecs"
(time (do (! 7999) nil)) ; => "Elapsed time: 0.090444 msecs"
(time (do (! 7999) nil)) ; => "Elapsed time: 0.055873 msecs"

How to return the output of a recursive function in Clojure

I'm new to functional languages and clojure, so please bear with me...
I'm trying to construct a list of functions, with either random parameters or constants. The function that constructs the list of functions is already working, though it doesn't return the function itself. I verified this using println.
(edit: Okay, it isn't working correctly yet after all)
(edit: Now it's working, but it cannot be "eval"-ed. it seems I need to recur at least two times, to ensure there are at least two children nodes. Is this possible?)
Here is the snippet:
(def operations (list #(- %1 %2) #(+ %1 %2) #(* %1 %2) #(/ %1 %2)))
(def parameters (list \u \v \w \x \y \z))
(def parameterlistcount 6)
(def paramcount 2)
(def opcount 4)
(defn generate-function
([] (generate-function 2 4 0.5 0.6 () parameters))
([pc maxdepth fp pp function-list params]
(if (and (pos? maxdepth) (< (rand) fp))
(let [function-list
(conj function-list
(nth operations
(rand-int (count operations))))]
(recur pc (dec maxdepth) fp pp function-list params))
(if (and (< (rand) pp) (pos? pc))
(let [ params (pop parameters)
function-list
(conj function-list
(nth params
(rand-int (count params))))]
(if (contains? (set operations) (last function-list) )
(recur (dec pc) maxdepth fp pp function-list params)
nil))
(let [function-list
(conj function-list
(rand-int 100))]
(if (or (pos? maxdepth) (pos? pc))
(if (contains? (set operations) (last function-list) )
(recur pc maxdepth fp pp function-list params)
nil)
function-list))))))
Any help will be appreciated, thanks!
Here's my shot at rewriting your function (see comments below):
(defn generate-function
([] (generate-function 2 4 0.5 0.6 ()))
([pc maxdepth fp pp function-list]
(if (and (pos? maxdepth) (< (rand) fp))
(let [function-list
(conj function-list
{:op
(nth operations
(rand-int (count operations)))})]
(recur pc (dec maxdepth) fp pp function-list))
(if (and (< (rand) pp) (pos? pc))
(let [function-list
(conj function-list
{:param
(nth parameters
(rand-int (count parameters)))})]
(recur (dec pc) maxdepth fp pp function-list))
(let [function-list
(conj function-list
{:const
(rand-int 100)})]
(if (or (pos? maxdepth) (pos? pc))
(recur pc maxdepth fp pp function-list)
function-list))))))
And some examples of use from my REPL...
user> (generate-function)
({:const 63} {:op #<user$fn__4557 user$fn__4557#6cbb2d>} {:const 77} {:param \w} {:op #<user$fn__4559 user$fn__4559#8e68bd>} {:const 3} {:param \v} {:const 1} {:const 8} {:op #<user$fn__4559 user$fn__4559#8e68bd>} {:op #<user$fn__4555 user$fn__4555#6f0962>})
user> (generate-function)
({:const 27} {:param \y} {:param \v} {:op #<user$fn__4561 user$fn__4561#10463c3>} {:op #<user$fn__4561 user$fn__4561#10463c3>} {:op #<user$fn__4561 user$fn__4561#10463c3>} {:op #<user$fn__4561 user$fn__4561#10463c3>} {:const 61})
A couple of things to keep in mind, in pretty random order:
I used recur in the above to avoid consuming stack in the recursive self-calls. However, you have this dotimes statement which makes me wonder if you might be interested in constructing a bunch of function-lists in parallel with one generate-function call. If so, tail-recursion with recur might not be an option with simplistic code like this, so you could either settle for the regular self-calls (but do consider the possibility of hitting the recursion limit; if you're positive that you'll only generate smallish functions and this won't be a problem, go ahead with the self-calls) or investigate continuation-passing style and rewrite your function in that style.
The (do (dec pc) ...) thing in your code does nothing to the value of pc in the next recursive call, or indeed to its current value. Local variables (or locals, as they are most often called in the community) in Clojure are immutable; this includes function parameters. If you want to pass along a decremented pc to some function, you'll have to do just that, like you did with maxdepth in an earlier branch of your code.
I renamed your function to generate-function, because camel case in function names is quite unusual in Clojure land. Also, I renamed the parameter which you called function to function-list (so maybe I should have used a name like generate-function-list for the function... hm), because that's what it is for now.
Note that there's no point to keeping a separate opcount Var around; Clojure's persistent lists (as created by the list function) carry their count around, so (count some-list) is a constant-time operation (and very fast). Also, it would be idiomatic to use vectors for operations and parameters (and you can switch to vectors without changing anything in the rest of the code!). E.g. [\u \v \w \x \y \z].
In Clojure 1.2, you'll be able to use (rand-nth coll) for (nth coll (rand-int (count coll))).
If you want to generate actual Clojure functions from trees of items representing ops, params and constants, you'll want to use eval. That's discouraged in most scenarios, but not for evolutionary programming and similar stuff where it's the only way to go.
Personally, I'd use a different format of the op/param/constant maps: something like {:category foo, :content bar} where foo is :op, :param or :const and bar is something appropriate in connection to any given foo.
In general it is a better idea in Clojure to use (recur ...) for your recursive functions. From the docs: "Note that recur is the only non-stack-consuming looping construct in Clojure." link
One other thing to note is that you might want to call the randomizer outside the recursive function, so you can define the stop-condition inside the function.
So like this:
(let [n (rand-int 10)]
(println "Let's define f with n =" n)
(defn f [x]
(if (> x n)
"result"
(do (println x)
(recur (inc x))))))
It prints:
Let's define f with n = 4
user> (f 0)
0
1
2
3
4
"result"
where 4 is of course a random number between 0 (inclusive) and 10 (exclusive).
So okay, I discovered I was going about this the wrong way.
A recursive definition of a tree is non other than defining vertices, and trying to tie everything with it. So, I came up with this, in less than 15 minutes. >_<
(defn generate-branch
"Generate branches for tree"
([] (generate-branch 0.6 () (list \x \y \z)))
([pp branch params]
(loop [branch
(conj branch (nth operations (rand-int (count operations))))]
(if (= (count branch) 3)
branch
(if (and (< (rand) pp))
(recur (conj branch (nth params (rand-int (count params)))))
(recur (conj branch (rand-int 100))))))))
(defn build-vertex
"Generates a vertex from branches"
[]
(let [vertex (list (nth operations (rand-int (count operations))))]
(conj vertex (take 5 (repeatedly generate-branch)))))
THANKS EVERYONE!

Resources