Why can't this recur function be defined? - clojure

This works fine:
(defn fact [x]
(loop [n x prod 1]
(if (= 1 n)
prod
(recur (dec n) (* prod n)))))
and this one can even be evaluated as a symbol:
(defn fact2 []
(loop [prod [1 2 3]]
(if (empty? prod)
prod
(recur (rest prod) (* prod 2)))))
What's wrong with the second one?

This is the exception thrown on evaluating the second expression:
Execution error (IllegalArgumentException) at user/fact2 (test.clj:3).
Mismatched argument count to recur, expected: 1 args, got: 2
The loop binding in fact2 has only one variable (which is called prod), however, the recur call would pass 2 values. You can not use the single variable prod to hold both the product (a number) and the list of numbers (a collection).
The correct definition would look something like this:
(defn fact2 []
(loop [n [1 2 3] prod 1]
(if (empty? n)
prod
(recur (rest n) (* prod 2)))))

Related

Clojure function to Replace Count

I need help with an assignment that uses Clojure. It is very small but the language is a bit confusing to understand. I need to create a function that behaves like count without actually using the count funtion. I know a loop can be involved with it somehow but I am at a lost because nothing I have tried even gets my code to work. I expect it to output the number of elements in list. For example:
(defn functionname []
...
...)
(println(functionname '(1 4 8)))
Output:3
Here is what I have so far:
(defn functionname [n]
(def n 0)
(def x 0)
(while (< x n)
do
()
)
)
(println(functionname '(1 4 8)))
It's not much but I think it goes something like this.
This implementation takes the first element of the list and runs a sum until it can't anymore and then returns the sum.
(defn recount [list-to-count]
(loop [xs list-to-count sum 0]
(if (first xs)
(recur (rest xs) (inc sum))
sum
)))
user=> (recount '(3 4 5 9))
4
A couple more example implementations:
(defn not-count [coll]
(reduce + (map (constantly 1) coll)))
or:
(defn not-count [coll]
(reduce (fn [a _] (inc a)) 0 coll))
or:
(defn not-count [coll]
(apply + (map (fn [_] 1) coll)))
result:
(not-count '(5 7 8 1))
=> 4
I personally like the first one with reduce and constantly.

Can't use recur in multi-arity Clojure function

This works:
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (tri* new-sum (+ n 1)))))))
but when I use recur in it, I get a CompilerException:
Mismatched argument count to recur, expected 0 args, got: 2
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (recur new-sum (+ n 1)))))))
lazy-seq is a macro which expands to code involving a zero-arg thunk that can be called later as the sequence is realized. You can see that the recur form is captured as the body of this thunk by doing
(macroexpand '(lazy-seq (recur new-sum (+ n 1))))
to get
(new clojure.lang.LazySeq (fn* [] (recur new-sum (+ n 1))))
which shows that the target of recur is the thunk, not tri*.
Another way to think about all of this is that the original call to tri* has long since completed (and returned a Cons object containing LazySeq rest object) by the time recur would be “evaluated.”
Your first version of tri* is fine in that the recursive call to tri* doesn't grow the stack, but instead simply creates a new set of Cons / LazySeq objects.

Clojure: Why surrounding an expression with extra parenthesis gives NullPointerException [duplicate]

Trying to define a factors function that will return a vector of all the factors of a number using loop/recur.
;; `prime?` borrowed from https://swizec.com/blog/comparing-clojure-and-node-js-for-speed/swizec/1593
(defn prime? [n]
(if (even? n) false
(let [root (num (int (Math/sqrt n)))]
(loop [i 3] (if (> i root) true
(if (zero? (mod n i)) false
(recur (+ i 2))))))))
(defn factors [x] (
(loop [n x i 2 acc []]
(if (prime? n) (conj acc n)
(if (zero? (mod n i)) (recur (/ n i) 2 (conj acc i))
(recur n (inc i) acc))))))
But I keep running into the following error:
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity
I must be missing something obvious here. Any suggestions are much appreciated!
Let me move the whitespace in your code so it's obvious to you what is wrong:
(defn factors [x]
((loop [n x i 2 acc []]
(if (prime? n) (conj acc n)
(if (zero? (mod n i)) (recur (/ n i) 2 (conj acc i))
(recur n (inc i) acc))))))
You see that weird (( at the start of your function? What's that all about? Remember that in Clojure, as in lisps in general, parentheses are not a grouping construct! They are a function-call mechanism, and you can't just throw extras in for fun. Here, what you wrote has the following meaning:
Run this loop that will compute a vector.
Call the resulting value as a function, passing it no arguments.

Wrong number of args (0) passed to: PersistentVector on loop/recur function

Trying to define a factors function that will return a vector of all the factors of a number using loop/recur.
;; `prime?` borrowed from https://swizec.com/blog/comparing-clojure-and-node-js-for-speed/swizec/1593
(defn prime? [n]
(if (even? n) false
(let [root (num (int (Math/sqrt n)))]
(loop [i 3] (if (> i root) true
(if (zero? (mod n i)) false
(recur (+ i 2))))))))
(defn factors [x] (
(loop [n x i 2 acc []]
(if (prime? n) (conj acc n)
(if (zero? (mod n i)) (recur (/ n i) 2 (conj acc i))
(recur n (inc i) acc))))))
But I keep running into the following error:
ArityException Wrong number of args (0) passed to: PersistentVector clojure.lang.AFn.throwArity
I must be missing something obvious here. Any suggestions are much appreciated!
Let me move the whitespace in your code so it's obvious to you what is wrong:
(defn factors [x]
((loop [n x i 2 acc []]
(if (prime? n) (conj acc n)
(if (zero? (mod n i)) (recur (/ n i) 2 (conj acc i))
(recur n (inc i) acc))))))
You see that weird (( at the start of your function? What's that all about? Remember that in Clojure, as in lisps in general, parentheses are not a grouping construct! They are a function-call mechanism, and you can't just throw extras in for fun. Here, what you wrote has the following meaning:
Run this loop that will compute a vector.
Call the resulting value as a function, passing it no arguments.

Generator pattern code can't return value

I want to create a generator to do, 1 2 3 4.
(defn getNums []
(loop [i 4
r []]
(when (<= i 0)
r ;<--- point A
(recur (dec i)
(conj r i)))))
(getNums) ;Eval to nil.
Nothing get return, why ?
Would the code in point A return result vector r ?
when, is a clojure macro defined as:
(when test & body)
So, in your first example, the body of when would be:
(do
r
(recur (dec i)
(conj r i)))
The when test itself is evaluated to false so the body of the when macro is not executed.
The return value of the function it therefore the return value of when itself is return, which is nil. Ex:
(when (< 2 1)) ; nil
By the way, there is a build in function range that does the same as your method:
(range 1 10)
And, in a more generic way, you could use the lazy function iterate:
(take 10 (iterate inc 1))
(defn getNums []
(loop [i 4
r []]
(if (<= i 0)
r
(recur (dec i)
(cons i r)))))
(getNums)