What's wrong with this factorial function in clojure - clojure

I have this function:
(defn ! [x]
(let [n x product 1]
(if (zero? n)
product
(recur (- n 1) (* product n)))))
and I got error: java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2 (NO_SOURCE_FILE:33)
but this factorial from other SO question work fine. Why?
(defn fact [x]
(loop [n x f 1]
(if (= n 1)
f
(recur (dec n) (* f n)))))

You can't recur on let.
When you recur here, you are actually recurring on the function definition which has one argument hence java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2 (NO_SOURCE_FILE:33).
On the second example (s)he's using loop which you should use when you want to recur on some other arguments, other than the functions.

in your example recur loops to ! which is expecting 1 param but gets 2,
in the second example recur loops to loop which is expecting 2 params and gets 2 params

Related

Why can't this recur function be defined?

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)))))

clojure function name as argument

I need to make loop method, which takes as argument some method name and how many times it will be looped.
Problem is that, i can't use any mutations (def,let and etc) as well as standart clojure functions, except if, inc, dec, println, +, -, = and etc.
Only with SEQ and Recursion !!!
My example:
;; F = some function name, for example, inc, dec, println and etc.
(defn my-loop [f n]
(if (= n 0)
f
(my-loop f (dec n))))
;; Returns 2, instead of 3, because on next iteration argument F = nil :(
(my-loop (inc 1) 2)
Obviously, when recursion is called, argument F is NIL, so how i can return same argument when recursion was called (without hardcode).
(letfn [(my-loop [f n result]
(if (< n 1) result
(recur f (dec n) (f result))))]
(my-loop inc 2 1))
Thanks for help, my solution is:
(defn my-loop [f n result]
(if (< n 1)
result
(my-loop f (dec n) (f result))))
(my-loop inc 2 1)

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.

Correct use of `recur` in Clojure?

I'm trying to solve the Count a Sequence problem on 4Clojure, but I can't work out what's wrong with my use of recur:
fn [s] (
fn [t n] (
if (empty t)
n
(recur (rest t) (+ n 1))
) s 0
)
It gives the following exception:
java.lang.UnsupportedOperationException: Can only recur from tail position, compiling:(NO_SOURCE_PATH:0)
But to me it seems that the call to recur is in a tail position for the inner function. What am I missing?
Two problems:
Your parentheses are misplaced.
You are using empty where you want empty?.
Parentheses
The fn special form for defining a function takes the shape
(fn name? [params* ] exprs*) with the parentheses around it.
Another level of parentheses applies the function ((fn [n] (* n n))
3) => 9.
Using defn instead of fn for the moment, we get
(defn l [s]
((fn [t n] (if (empty? t) n (recur (rest t) (+ n 1))))
s 0))
Then, for example,
(l ())
; 0
and
(l [1 2 3])
; 3
#Thumbnail is right -- your code will work just fine if you fix the placement of your parentheses (most importantly, you need to add a ( before (fn [t n] ... and a corresponding ) after s 0, in order to actually return the result of calling that function (the one that takes t and n as arguments) on the values s and 0. Otherwise, you are returning the function itself.), and change empty to empty?.
If you wanted to simplify things a bit, you might consider using a loop/recur structure instead, like this:
(fn [s]
(loop [t s, n 0]
(if (empty? t)
n
(recur (rest t) (+ n 1)))))

why this code is wrong ? How does 'recur' work?

I don't know why the code below is wrong:
(defn factorial [n]
(loop [n n
acc 1]
(if (zero? n)
acc
(recur (* acc n)(dec n)))))
(= 1 (factorial 1))
How does recur work?
The arguments to the recur are the wrong way round.
n should become (dec n)
acc should become (* acc n)
So it should be
(recur (dec n) (* acc n))
We can recast the given algorithm to see what's going on inside it.
If we represent the pair of arguments as a vector, the function that generates the next pair is
(fn [[n acc]] [(* acc n) (dec n)])
We can generate the endless sequence of possible pairs for a given noby applying iterate to the function above, starting with [no 1].
(fn [no]
(iterate (fn [[n acc]] [(* acc n) (dec n)]) [no 1]))
Applying this to 1 generates
([1 1] [1 0] [0 0] [0 -1] ...)
We stop at element 2, the first with an initial 0, returning the other 0.
If we put the arguments the right way round, we can get the proper factorial thus:
(defn factorial [no]
((comp second first)
(drop-while
(comp not zero? first)
(iterate (fn [[n acc]] [(dec n) (* acc n)]) [no 1]))))
This returns the second element of the first pair in the sequence with a zero first (Duh!).
Hopelessly overcomplicated for normal use, but does it work?
=> (map factorial (range 6))
(1 1 2 6 24 120)
Yes.