Clojure, implement range, why this solution doesn't work - clojure

I want to implement range function of clojure, why following code won't work ?
(fn [low high]
(loop[low low
ret []]
(if(= low high)
(list ret)
(recur (inc low) (concat ret [low])))))

I've given two correct implementations below. Your problem is you were wrapping your accumulator, which was already a list, in another sequence when you called (list ret).
(defn my-range [low high]
(loop [low low
ret []]
(if (= low high)
(seq ret)
(recur (inc low) (conj ret low)))))
(defn my-range2 [low high]
(take-while
(partial > high)
(iterate inc low)))
Edit: range doesn't include the upper limit parameter in its returned seq, changed partial in my-range2 from >= to >.

There are several problems with your code.
As the previous answers point out
(list ret) is wrong. Replace it with (seq ret). Note: To return exactly (), not nil for an empty sequence, use (if (seq ret) (seq ret) ()). Nil-punning probably makes this needless.
concat is over the top. Use conj instead.
Also,
Guard against runaway: (my-range 10 0) loops forever. Replace = with >=.
Making these changes,
(defn my-range [low high]
(loop [low low, ret []]
(if (>= low high)
(if (seq ret) (seq ret) ())
(recur (inc low) (conj ret low)))))
The remaining problem is that this is not lazy: it develops the whole vector before returning. For example,
(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))
... seems to take forever, though you only want five elements. A simple lazy version is
(defn my-range [low high]
(lazy-seq
(if (>= low high) () (cons low (my-range (inc low) high)))))
Then
(take 5 (my-range 42 (java.lang.Integer/MAX_VALUE)))
;(42 43 44 45 46)
... is immediate.
RedDeckWins's my-range2 does just as well, and is neater.
EDIT: range returns a list, not a vector, changed return statement to (if (seq ret) (seq ret) ()) in first implementation of my-range.

Your code is fine, except for (list ret) part.
list function creates new list with given elements (in your example, with single ret element). If you want to convert your sequential, you should use seq function instead.
I would also recommend you not to use concat function here, because its lazy and may cause a StackOwerflowError producing long sequences.
The rest of your code is fine.
For working example see RedDeckWins's answer.

Related

Getting Execution error (StackOverflowError) when evaluating a function on larger range of values

I'm learning Clojure and solving exercises from SICP book in the process. I get this error when evaluating (search-for-primes 1001 10000) but when called on smaller values (search-for-primes 101 1000) it works fine.
This seems to be a memory issue but I'm unable to zero in on the cause of it. Would love your help. Thank you. Below is the code.
(defn square [x]
(* x x))
(defn divides? [a b]
(= (rem b a) 0))
(defn find-divisor [n test-divisor]
(cond
(> (square test-divisor) n) n
(divides? test-divisor n) test-divisor
:else (find-divisor n (+ test-divisor 1))))
(defn smallest-divisor [n]
(find-divisor n 2))
;;return true if prime
(defn prime?
[n]
(= n (smallest-divisor n)))
;;return the first of the three consecutive prime numbers
(defn search-for-primes [low high]
(if (< low high)
(cond
(and (prime? low) (prime? (+ low 2)) (prime? (+ low 4))) low
:else (search-for-primes (+ low 2) high))))
You don't show the actual error you're getting, but I'll guess that it has something to do with the stack overflowing.
Unlike Scheme, Clojure does not support tail call elimination, so you probably need to look at loop/recur, see https://clojuredocs.org/clojure.core/loop for example.

Debugging a slow performing function in Clojure

I am trying to implement a solution for minimum-swaps required to sort an array in clojure.
The code works, but takes about a second to solve for the 7 element vector, which is very poor compared to a similar solution in Java. (edited)
I already tried providing the explicit types, but doesnt seem to make a difference
I tried using transients, but has an open bug for subvec, that I am using in my solution- https://dev.clojure.org/jira/browse/CLJ-787
Any pointers on how I can optimize the solution?
;; Find minimumSwaps required to sort the array. The algorithm, starts by iterating from 0 to n-1. In each iteration, it places the least element in the ith position.
(defn minimumSwaps [input]
(loop [mv input, i (long 0), swap-count (long 0)]
(if (< i (count input))
(let [min-elem (apply min (drop i mv))]
(if (not= min-elem (mv i))
(recur (swap-arr mv i min-elem),
(unchecked-inc i),
(unchecked-inc swap-count))
(recur mv,
(unchecked-inc i),
swap-count)))
swap-count)))
(defn swap-arr [vec x min-elem]
(let [y (long (.indexOf vec min-elem))]
(assoc vec x (vec y) y (vec x))))
(time (println (minimumSwaps [7 6 5 4 3 2 1])))
There are a few things that can be improved in your solution, both algorithmically and efficiency-wise. The main improvement is to remember both the minimal element in the vector and its position when you search for it. This allows you to not search for the minimal element again with .indexOf.
Here's my revised solution that is ~4 times faster:
(defn swap-arr [v x y]
(assoc v x (v y) y (v x)))
(defn find-min-and-position-in-vector [v, ^long start-from]
(let [size (count v)]
(loop [i start-from, min-so-far (long (nth v start-from)), min-pos start-from]
(if (< i size)
(let [x (long (nth v i))]
(if (< x min-so-far)
(recur (inc i) x i)
(recur (inc i) min-so-far min-pos)))
[min-so-far min-pos]))))
(defn minimumSwaps [input]
(loop [mv input, i (long 0), swap-count (long 0)]
(if (< i (count input))
(let [[min-elem min-pos] (find-min-and-position-in-vector mv i)]
(if (not= min-elem (mv i))
(recur (swap-arr mv i min-pos),
(inc i),
(inc swap-count))
(recur mv,
(inc i),
swap-count)))
swap-count)))
To understand where are the performance bottlenecks in your program, it is better to use https://github.com/clojure-goes-fast/clj-async-profiler rather than to guess.
Notice how I dropped unchecked-* stuff from your code. It is not as important here, and it is easy to get it wrong. If you want to use them for performance, make sure to check the resulting bytecode with a decompiler: https://github.com/clojure-goes-fast/clj-java-decompiler
A similar implementation in java, runs almost in half the time.
That's actually fairly good for Clojure, given that you use immutable vectors where in Java you probably use arrays. After rewriting the Clojure solution to arrays, the performance would be almost the same.

Clojure : function returns nil rather an evaluated expression

I have written a function that sums the members of a list. Pretty straightforward, newbie stuff, but for some reason it returns nil, and I am at a loss as to why: this should be a no-brainer. The implementation and function call follow.
The implementation:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
The call to the function:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
Meanwhile, I have a debugging version with print statements added, and I have been able to verify that the implementation works as it should.
Debugging version:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
Call to debugging version:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
The development tools I am using are Vim plugged into the Leiningen REPL. Any hints about what I'm doing wrong here would be most appreciated.
You used if in a wrong way. Consider the following code: I intentionally simplified the code to make it clear what happens.
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
What happens if you run (xxx [1])? Perhaps you expect the code will return "one", however, it returns nil. Why?
Function returns value of its last expression, in this case, the last line (if (> (count v) 2) "more"). If you pass [1], the first if expression returns "one", which is ignored. The second if will return nil, which is also ignored. The third and the last will return nil, which is the return value of the function.
Perhaps the simplest way to compute sum of elements is:
(defn add-elements [xs] (apply + xs))
or
(defn add-elements [xs] (reduce + xs))
Your code can be reimplemented in much simpler way:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))
The parentheses are wrong, or at least suboptimal, and you have no base case that returns total. (About the parentheses: Your indentation, which is correct given the parentheses, shows this: Each if is on the same level; none of them are in the "else" position.) Here's one correct version:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
You get nil as the return value because when the last if test fails, it goes to the else clause, which in this case is an empty end of a list, i.e. nil.
However, the multiple ifs can be replaced with one cond. You can also use ffirst for (first (first, fnext instead of (first (rest, and nnext instead of (rest (rest. It would also be more idiomatic to use a predicate such as empty? instead of checking for count equal to 0; I used count for the base case simply to maintain the parallel with your existing code. The simplest version might be:
(defn add-list-members [x] (apply + x))
You could also use reduce for a very simple version. You may just have wanted to experiment with recur, though.
(Well, you could do it without using the embedded else clauses, as in your original, but I wouldn't recomment it, and you still need the empty sequence base case. When you put multiple separate expressions in an function definition, each one of them always gets executed. This is inefficient and, I feel, error prone. Using multiple, separate expressions in a function definition makes sense when you're creating side effects--e.g. adding print statements for debugging.)

Stackoverflow when calling sol-count on 10 (N-queens program)

So this is my first time programming in clojure and I am running into some issues with stackoverflow with my program. This program basically tries to find all the possible solutions to the N-queens problem
http://en.wikipedia.org/wiki/Eight_queens_puzzle
When I call sol-count (finds number of solutions for a given N) on 10 or higher I get a stack overflow
(defn qextends?
"Returns true if a queen at rank extends partial-sol."
[partial-sol rank]
(if (>= (count partial-sol) 1)
(and
(not= (first partial-sol) (- rank (count partial-sol)))
(not= (first partial-sol) (+ rank (count partial-sol)))
(not= (first partial-sol) rank)
(qextends? (rest partial-sol) rank))
true)
)
(defn qextend-helper [n x partial-sol partial-sol-list]
(if (<= x n)
(if (qextends? partial-sol x)
(qextend-helper n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
(qextend-helper n (inc x) partial-sol partial-sol-list)
)
partial-sol-list)
)
(defn qextend
"Given a vector *partial-sol-list* of all partial solutions of length k,
returns a vector of all partial solutions of length k + 1.
"
[n partial-sol-list]
(if (>= (count partial-sol-list) 1)
(vec (concat (qextend-helper n 1 (first partial-sol-list) [])
(qextend n (rest partial-sol-list))))
nil))
(defn sol-count-helper
[n x partial-sol-list]
(if (<= x (- n 1))
(sol-count-helper n (+ 1 x) (qextend n partial-sol-list))
(qextend n partial-sol-list))
)
(defn sol-count
"Returns the total number of n-queens solutions on an n x n board."
[n]
(count (sol-count-helper n 1 [[]]))
)
Completing dizzystar's answer:
Most of your recursions can be recurred: You can put recur inside if, and hence under and and or, macros which expand to if forms. For example ...
(defn qextend-helper [n x partial-sol partial-sol-list]
(if (<= x n)
(if (qextends? partial-sol x)
(recur n (inc x) partial-sol (conj partial-sol-list (conj partial-sol x)))
(recur n (inc x) partial-sol partial-sol-list))
partial-sol-list)
)
But the recursive call in qextend:
(vec (concat ( ...)
(qextend n (rest partial-sol-list))))
... can't be dealt with by recur, since it is buried in function calls, to concat and vec.
You can solve this problem by returning a lazy sequence, so making the partial-sol-list argument lazy:
get rid of vec - return the sequence - and
replace concat with lazy-cat.
The resulting function is
(defn qextend [n partial-sol-list]
(if (seq partial-sol-list)
(lazy-cat (qextend-helper n 1 (first partial-sol-list) [])
(qextend n (rest partial-sol-list)))
nil))
You also have to avoid counting (and hence realizing) the lazy sequence: so useseq instead to test whether there is anything in partial-sol-list.
It works!
=> (sol-count 11)
2680
For starters, Clojure does not have TCO like other lisps. To mitigate this, Clojure offers loop and recur. In Clojure and other lisps, you generally do not have explicit returns, instead, the focus is on returning values.
I fixed up the qextend-helper to give you a start. I tested a few of your answers against the snippet that I replaced here, and they all resolve to the same solution. You still can't go past 10 even with this snippet inside of it, but if you continue to remove all the tail call recursions, you should be able to get past the stackoverflow errors:
(defn qextend-helper [n x partial-sol partial-sol-list]
(loop [n n
x x
partail-sol partial-sol
partial-sol-list partial-sol-list]
(when (and (<= x n)
(qextends? partail-sol x))
(recur n (inc x) partail-sol (conj partial-sol-list (conj partial-sol x))))))
I should point out also that the above isn't great Clojure either. There are many other solutions online that are less LOC and more Clojure-y, but since you are starting down this route, I am simply attempting to encourage you to remove the errors that you are running into. In this case, removing the tail-calls is a good place to start. With that said, there is nothing that would stop you from using for or other constructs and I encourage you to look into other options after you solved this.
When using recur, resist the temptation to put recur at the end of a function to simulate TCO:
(defn my-funct [x]
.....
(recur x))
Finally, this indention style and putting parens on their own lines does not improve readability.:
(qextend-helper n (inc x) partial-sol partial-sol-list)
)
partial-sol-list)
)

Binary search in clojure (implementation / performance)

I wrote a binary search function as part of a larger program, but it seems to be slower than it should be and profiling shows a lot of calls to methods in clojure.lang.Numbers.
My understanding is that Clojure can use primitives when it can determine that it can do so. The calls to the methods in clojure.lang.Numbers seems to indicate that it's not using primitives here.
If I coerce the loop variables to ints, it properly complains that the recur arguments are not primitive. If i coerce those too, the code works again but again it's slow. My only guess is that (quot (+ low-idx high-idx) 2) is not producing a primitive but I'm not sure where to go from here.
This is my first program in Clojure so feel free to let me know if there are more cleaner/functional/Clojure ways to do something.
(defn binary-search
[coll coll-size target]
(let [cnt (dec coll-size)]
(loop [low-idx 0 high-idx cnt]
(if (> low-idx high-idx)
nil
(let [mid-idx (quot (+ low-idx high-idx) 2) mid-val (coll mid-idx)]
(cond
(= mid-val target) mid-idx
(< mid-val target) (recur (inc mid-idx) high-idx)
(> mid-val target) (recur low-idx (dec mid-idx))
))))))
(defn binary-search-perf-test
[test-size]
(do
(let [test-set (vec (range 1 (inc test-size))) test-set-size (count test-set)]
(time (count (map #(binary-search2 test-set test-set-size %) test-set)))
)))
First of all, you can use the binary search implementation provided by java.util.Collections:
(java.util.Collections/binarySearch [0 1 2 3] 2 compare)
; => 2
If you skip the compare, the search will be faster still, unless the collection includes bigints, in which case it'll break.
As for your pure Clojure implementation, you can hint coll-size with ^long in the parameter vector -- or maybe just ask for the vector's size at the beginning of the function's body (that's a very fast, constant time operation), replace the (quot ... 2) call with (bit-shift-right ... 1) and use unchecked math for the index calculations. With some additional tweaks a binary search could be written as follows:
(defn binary-search
"Finds earliest occurrence of x in xs (a vector) using binary search."
([xs x]
(loop [l 0 h (unchecked-dec (count xs))]
(if (<= h (inc l))
(cond
(== x (xs l)) l
(== x (xs h)) h
:else nil)
(let [m (unchecked-add l (bit-shift-right (unchecked-subtract h l) 1))]
(if (< (xs m) x)
(recur (unchecked-inc m) h)
(recur l m)))))))
This is still noticeably slower than the Java variant:
(defn java-binsearch [xs x]
(java.util.Collections/binarySearch xs x compare))
binary-search as defined above seems to take about 25% more time than this java-binsearch.
in Clojure 1.2.x you can only coerce local variables and they can't cross functions calls.
starting in Clojure 1.3.0 Clojure can use primative numbers across function calls but not through Higher Order Functions such as map.
if you are using clojure 1.3.0+ then you should be able to accomplish this using type hints
as with any clojure optimization problem the first step is to turn on (set! *warn-on-reflection* true) then add type hints until it no longer complains.
user=> (set! *warn-on-reflection* true)
true
user=> (defn binary-search
[coll coll-size target]
(let [cnt (dec coll-size)]
(loop [low-idx 0 high-idx cnt]
(if (> low-idx high-idx)
nil
(let [mid-idx (quot (+ low-idx high-idx) 2) mid-val (coll mid-idx)]
(cond
(= mid-val target) mid-idx
(< mid-val target) (recur (inc mid-idx) high-idx)
(> mid-val target) (recur low-idx (dec mid-idx))
))))))
NO_SOURCE_FILE:23 recur arg for primitive local: low_idx is not matching primitive,
had: Object, needed: long
Auto-boxing loop arg: low-idx
#'user/binary-search
user=>
to remove this you can type hint the coll-size argument
(defn binary-search
[coll ^long coll-size target]
(let [cnt (dec coll-size)]
(loop [low-idx 0 high-idx cnt]
(if (> low-idx high-idx)
nil
(let [mid-idx (quot (+ low-idx high-idx) 2) mid-val (coll mid-idx)]
(cond
(= mid-val target) mid-idx
(< mid-val target) (recur (inc mid-idx) high-idx)
(> mid-val target) (recur low-idx (dec mid-idx))
))))))
it is understandably difficult to connect the auto-boxing on line 10 to the coll-size parameter because it goes through cnt then high-idx then mid-ixd and so on, so I generally approach these problems by type-hinting everything until I find the one that makes the warnings go away, then remove hints so long as they stay gone