Nested recur statements - clojure

Why doesn't the following snippet of code print "1" to the console?
(loop
[i 0]
(println (if (= i 0) (recur 1) i)))
Instead, it throws clojure.lang.ExceptionInfo: Can't recur here at line 3 in the REPL. Are nested (recur..) statements like this not allowed in Clojure(Script)?

Correct, "nested recur statements" are not allowed in any Clojure dialect. The alternate behavior described in a comment (recur "halts and dismisses the execution of its parent statements") would work as an alternate language design choice, but would probably be a lot more confusing to read.

In your code you try to print the result of (recur 1), which doesn't make sense. I think you probably meant to do (recur 1) if i==0, and print i otherwise, as follows:
(loop [i 0]
(if (= i 0) (recur 1) (println i)))

See Clojure: What exactly is tail position for recur? - you can only use recur from a "tail position" in Clojure. In this case, recur is not in a tail position because it is not the last thing to be evaluated in this function - the println would be evaluated after the call to recur.

Related

Making Clojure let statement more functional

In my first Clojure project everything turned out nicely except this part at the end:
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (-> (filter (complement fixable?) broken-signs)
(count))]
(println
(if (> unfixable-count 0)
-1
(- broken-count unfixable-count))))
The indentation looks off and it does not feel functional, since I am reusing state in the let block. I basically count the number of broken signs and then the number of fixable signs. If any sign is unfixable, I print -1, otherwise I print the number of signs to be fixed.
If I mapped/filtered twice, I'd have duplicate code, but most of all it'd run slower. Is there a way of improving this code nevertheless?
EDIT: This is what I settled on
(defn count-broken-yet-fixable []
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (empty? unfixable)
(count broken))))
(defn solve-task []
(if-let [result (count-broken-yet-fixable)]
result
-1))
(println (solve-task))
The subtraction was indeed not necessary and the count did not have to happen in the let block. Outputting the -1 on bad input also isn't the job of the function and is only part of the task.
I don't think there's anything "non-functional" or wrong with your approach. The indentation looks fine.
(let [broken (->> (:symbols field)
(map make-sign)
(filter broken?))
unfixable (remove fixable? broken)]
(when (seq unfixable)
(- (count broken) (count unfixable))))
You could replace filter (complement with remove
Could use pos? instead of (> n 0)
I might put two printlns inside the if, but really it's better to return a value
You could inline the broken-count binding, since it's only used in one place
I personally think this is easier to read with less threading macros
Since the need to count unfixables is conditional, you could test for values with seq first
If you return -1 as a sentinel value, I'd use nil instead; this happens naturally when the when condition isn't met
The conditional logic seems backwards: you return -1 when unfixable-count is positive, and only use its value when it's not positive (which means it's zero b/c count can't be negative), e.g. it could be rewritten as (- broken-count 0) and then just broken-count
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))]
(if-let [unfixable-signs (seq (remove fixable? broken-signs))]
-1
(- (count broken-signs) (count unfixable-signs)))
Your code is already pretty neat and well laid out. The only change I would want to do, is stay in the domain as long as possible - in this case the signs objects. And use the counts only much later.
The return value can then use print to do the actual actions.
Your code doesn't have side-effects (except for printing, which we'll fix), so I wouldn't say it's not functional. let is designed for building up intermediate values. In comments are some potential improvements.
; align here (controversial)
(let [broken-signs (->> (:symbols field)
(map make-sign)
(filter broken?))
broken-count (count broken-signs)
unfixable-count (->> broken-signs ; maybe emphasize non-function start
(filter (complement fixable?))
count)] ; no parens needed
;; don't print; just return number
(if (< 0 unfixable-count) ; prefer less-than (Elements of Clojure book)
-1
(- broken-count unfixable-count)))
I highly recommend the Clojure Style Guide for related suggestions.

`loop` and `with-redefs` do not play well together

I have some code which I refactored only to find out something was broken with loop. After some debugging I found out loop and with-redefs do not play well together. I realize it may not make sense to use with-redefs inside a loop, but I didn't expect it to not work. I'm not sure if its intentional or not.
This is an MCVE I've created to demonstrate the "problem":
(loop [test 3]
(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
This gives me:
Mismatched argument count to recur, expected: 0 args, got: 1
Removing the with-redefs works as expected:
(loop [test 3]
(if (zero? test)
"done"
(recur (dec test))))
and returns "done".
What is the reason the first piece of code does not work? Is this intentional?
The explanation is in the macroexpansion of with-redefs:
(macroexpand-1
'(with-redefs []
(if (zero? test)
"done"
(recur (dec test)))))
returns:
(with-redefs-fn {}
(fn []
(if (zero? test)
"done"
(recur (dec test)))))
where you can see that because a new fn has been introduced, the recur is going to refer to that fn rather than the farther-away loop (which explains the arity exception).
There are a variety of other macros that are "incompatible" with loop in this way, because the recur needs to be in the tail position with respect to loop, and if the recur occurs inside a macro call, the macro may be manipulating the code such that the recur is no longer in tail position.
For with-redefs in particular (and a variety of other situations), a workaround could be:
(loop [test 3]
(let [[recur? val]
(with-redefs []
(if (zero? test)
[false "done"]
[true (dec test)]))]
(if recur?
(recur val)
val)))

Error in recur call in Clojure

I am trying to read numbers from input and printing them back in Clojure till I read the number 42. A really basic thing to make sure I know how to read input. Taken from codechef
I have written this program. Might not be good clojure.
(defn universe
[]
(let [num (line-seq (java.io.BufferedReader. *in*))]
(if (not= num 42)
(do
(println num)
(recur (universe))
)
)
)
)
My understanding is that line-seq lazily evaluates from whatever reader is given. In this case the standard input.
So I have let it be num. Then if num is not 42 I print it and then recursively call universe. But it throws exception
Mismatched argument count to recur, expected: 0 args, got: 1,
I have seen an example and recur does take an argument. Looking at the official documentation I couldn't see the syntax for this. So why am I getting this error?
recur does not take the name of the location to recur to. Instead the recur special form jumps back up to the closest function or loop expression, whichever is closer. It then passes it different arguments. This lets you go through the same block of code repeatedly as you work through the data, and there is no function call overhead.
In your case it's recurring up to the function call:
(defn universe [] ...
and trying to pass it an argument, which fails because universe, the function, does not accept any arguments. perhaps you intended to put a loop expression around the if?
user> (defn universe
[]
(let [numbers (line-seq (java.io.BufferedReader. *in*))]
(loop [numbers numbers]
(let [num (first numbers)]
(if (not= (Integer/parseInt num) 42)
(do
(println num)
(recur (rest numbers))))))))
#'user/universe
user> (universe)
3 ;; typed 3
nil ;; typed 42
or where you intending to recur back to the top of the function, in which case just call (recur) instead of (recur universe)

change values from global variable in Clojure

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 with dec).
Also (= FIND_MORE_PRIMES false) can be simply replaced by find-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:
(defn gather-primes-in-range [range-start range-end target-number prime-list]
(if (or (zero? target-number) (> range-start range-end) need-more-primes?)
prime-list
(do
(if (is-prime? range-start)
(gather-primes-in-range (inc range-start) range-end (dec target-number) (conj prime-list range-start))
(gather-primes-in-range (inc range-start) range-end target-number prime-list)))))
2) Now we should remove redundant do call 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-range calls to recur
(defn gather-primes-in-range
[range-start range-end target-number prime-list]
(if (or (zero? target-number) (> range-start range-end) need-more-primes?)
prime-list
(if (is-prime? range-start)
(recur (inc range-start) range-end (dec target-number) (conj prime-list range-start))
(recur (inc range-start) range-end target-number prime-list))))
And here comes time for answering your question. You wouldn't benefit from this approach
(def PRIMES_FOUND_SO_FAR #{})
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.
(def PRIMES_FOUND_SO_FAR (atom #{}))
Adding new prime number to atom:
(swap! PRIMES_FOUND_SO_FAR conj prime-number)
Deref atom for extracting the value:
#PRIMES_FOUND_SO_FAR ;; or (deref PRIMES_FOUND_SO_FAR)
-> #{2 3 5 7 11}
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:
(defn gather-primes-in-range [start end target-number]
(take target-number (filter is-prime? (range start end))))
for those who have spent too much time searching how to modify a global (root) variable in clojure here is the solution:
(def user-remote-browser "anonymous")
you can modify it from anywhere i suppose but in the same namepace with:
(alter-var-root #'user-remote-browser (constantly name))
alter-var-root use a function to modify a variable,
constantly create a constant function returning here the string name

Clojure :: get the single element of a list and throw exception if the list has more than 1 elements

I know at a certain point in my code that a list only has one element so I obtain it with
(first alist)
But I would also like the code to break if the list has more than one elements to alert me of the erroneous condition. What's an idiomatic way to achieve that in Clojure ?
Replace first with an only (or other poetically named) function with a pre-condition where you want to make your assertion:
(defn only [x] {:pre [(nil? (next x))]} (first x))
(only [1])
=> 1
(only [1 2])
=> AssertionError Assert failed: (nil? (next x)) user/only (NO_SOURCE_FILE:1)
This will blow up on a collection with anything other than one element. Works fine on lazy seqs as well.
(defn only
"Gives the sole element of a sequence"
[coll]
(if (seq (rest coll))
(throw (RuntimeException. "should have precisely one item, but had at least 2"))
(if (seq coll)
(first coll)
(throw (RuntimeException. "should have precisely one item, but had 0")))))
I can't immediately think of a nice concise, idiomatic way to do this.
Option 1 is that there isn't one, because this is a bit of an odd situation. If you know there's supposed to be exactly one element, why is it in a list in the first place?
Option 2 is that there is one, and someone will come along and tell off for not seeing it :)
That said, in your situation I'd probably write something like:
(let [[item & rest] alist]
(if (nil? rest)
(throw (IllegalArgumentException. "Expected a single-element list"))
item))
Possibly more simply, you could also just do (count alist) and make sure it had exactly one item. The code above, though, has the nice property that it won't force evaluation beyond the head of the list, but depending on your use case that might not be a concern.
The Tupelo library has this function defined as a core sanity-check, allowing one to "unwrap" scalar values from length-1 vectors/lists and document the intended result. The definition is simplicity itself:
(defn only
"(only coll)
Ensures that a sequence is of length=1, and returns the only value present.
Throws an exception if the length of the sequence is not one.
Note that, for a length-1 sequence S, (first S), (last S) and (only S) are equivalent."
[coll]
(let [coll-seq (seq coll)
num-items (count coll-seq)]
(when-not (= 1 num-items)
(throw (IllegalArgumentException. (str "only: num-items must=1; num-items=" num-items))))
(clojure.core/first coll-seq)))
You can find a similar function in the SuchWow library and other places.