I’m a total beginer in Clojure and I’ve ran into a problem that I’m not even sure if can be done in Closure.
So the issue is the following. I’ve implemented a function that computes the prime numbers from an interval (up to a limit).
(defn gather_primes_in_range [range_start range_end target_number prime_list]
(if (or (= 0 target_number) (> range_start range_end) (= FIND_MORE_PRIMES false))
prime_list
(do
(if (is_prime? range_start)
(gather_primes_in_range (+ range_start 1) range_end (- target_number 1) (conj, prime_list, range_start))
(gather_primes_in_range (+ range_start 1) range_end target_number prime_list)
)
)
)
)
(defn find_nr_of_primes_in_range [range_start range_end target_number]
(if (< range_start 2)
(gather_primes_in_range 2 range_end target_number [])
(gather_primes_in_range range_start range_end target_number [])
)
)
This works just fine. But what I want now is to have a global variable that should store on each method call the primes that are found in a variable to lookup later. In other languages like Python, Ruby or Scala I would just do this by having a Set to which I add entries before returing from the function. But in Clojure I have no ideea how to go around this.
Basically what I tried is, have somewhere global declared:
(def PRIMES_FOUND_SO_FAR #{})
And then somehow on return add the entries to this variable. Is this possible at all in Clojure and if so how? I’ve tried on other variables to change their values using either swap! and atom, or set! but could not make it to work here in any situation.
Firstly, I strongly advice you to read about clojure code conventions What are Clojure's Naming Conventions?
Let me show you some improvements of your code.
1) Applying clojure naming conventions.
Then switch from
(+ variable 1)to(inc variable)(the same optimizations withdec).Also
(= FIND_MORE_PRIMES false)can be simply replaced byfind-more-primes?And finally the condition
(= 0 smthng)could be written in more idiomatic style(zero? smthng)Now your code looks a bit more readable:
2) Now we should remove redundant
docall cause it wraps the only one function call.And the last trick is to apply tail recursion (http://clojure.org/special_forms#Special%20Forms–(recur%20exprs*)) via swapping entire
gather-primes-in-rangecalls torecurAnd here comes time for answering your question. You wouldn’t benefit from this approach
because you haven’t opportunity to change this set. The only thing that you can deal with it is to create some new immutable data structure from that one.
As @georgek mention you could simply use atom in this particular case.
Adding new prime number to atom:
Deref atom for extracting the value:
Anyway your code is a little bit imperative but you should always remember that clojure is functional language with immutable data structures, functions as arguments, etc. using global variables is not good idea at all. BTW thats how your function should look like in clojure style: