2

I am doing this Clojure program for fibonacci series.

(def fibonacci []
  (def a 0)
  (def b 0)
  (def c 1)
  (def n (atom 0))
  (while (<= @n 10)
    (do
      (def c (+ a b))
      (def a b)
      (def b c)
      (println '(a b c))
      )(swap! n inc)))
(fibonacci)

I am getting this error:

CompilerException java.lang.RuntimeException: Too many arguments to def, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:1:1) 
CompilerException java.lang.RuntimeException: Unable to resolve symbol: fibonacci in this context, compiling:(C:\Users\user\AppData\Local\Temp\form-init4960759414983563364.clj:13:1) 

I can't figure out how to reassign the variables a, b and c . And also please suggest any correction needed in the program.

2
  • 9
    A few pointers: defining a function should be done by defn, not def. Assigning local variables is done by let, not def. Atoms that are exclusively used within one function usually means your approach is imperative, not functional. I suggest starting off with a few 4clojure.com exercises, which builds up your functional thinking. Commented Oct 10, 2018 at 8:02
  • 5
    It looks like you are entering with an imperative mindset. Apart from what @NielsK suggested, perhaps you can have a look at Clojure for the Brave and True free book or Clojure from the Ground Up series. It takes some getting used to, and if you don't have colleagues or friends who are already "in" Clojure to show you the way, your best bet would be to follow any one of number of books on Clojure. The above mentioned are quite nice. Commented Oct 10, 2018 at 9:41

2 Answers 2

4

First, let's get your code working. The first def, to define a function, should be defn:

(defn fibonacci []
  (def a 0)
  (def b 0)
  (def c 1)
  (def n (atom 0))
  (while (<= @n 10)
    (do
      (def c (+ a b))
      (def a b)
      (def b c)
      (println '(a b c))
      )(swap! n inc)))

It compiles. Let's try it:

> (fibonacci)

(a b c)
(a b c)
...
(a b c)
=> nil

Not what you intended. The trouble is the quote in front of (a b c), which returns the elements of the list unevaluated. We have to take the quote off, but we don't want a to be treated as an operator. So put in list:

(defn fibonacci []
  (def a 0)
  (def b 0)
  (def c 1)
  (def n (atom 0))
  (while (<= @n 10)
    (do
      (def c (+ a b))
      (def a b)
      (def b c)
      (println (list a b c))
      )(swap! n inc)))

Let's run it:

> (fibonacci)

(0 0 0)
(0 0 0)
...
(0 0 0)
=> nil

Well, we got numbers, though not the ones we want. The problem is that the first (def c (+ a b)) wipes out the only non-zero value. We ought to start with b at 1, and just use c temporarily:

(defn fibonacci []
  (def a 0)
  (def b 1)
  (def n (atom 0))
  (while (<= @n 10)
    (do
      (def c (+ a b))
      (def a b)
      (def b c)
      (println (list a b c))
      )(swap! n inc)))

And now ...

> (fibonacci)

(1 1 1)
(1 2 2)
(2 3 3)
(3 5 5)
(5 8 8)
(8 13 13)
(13 21 21)
(21 34 34)
(34 55 55)
(55 89 89)
(89 144 144)
=> nil

Hurrah!

But we can see that b and c are the same, and just predict the next a.

There is a bigger problem. Using mutable variables is not the Clojure way. Nor is it idiomatic for a function to print what it computes: better develop the result as a sequence, which we can do what we like with.

We can define the whole Fibonacci sequence thus:

(defn fibonacci []
  (map second
       (iterate
         (fn [[a b]] [b (+ a b)])
         [0 1])))

And just develop as much as we want:

   (take 10 (fibonacci))

=> (1 1 2 3 5 8 13 21 34 55)
Sign up to request clarification or add additional context in comments.

2 Comments

@santoshsahoo Good! It's quite a jump from your code to mine: you're going to have to learn about sequences and destructuring, which keeps my computation the same shape as yours. By the way, I've made some minor corrections.
Yeah. I noticed. Thank you again
0

As already indicated in the comments, in an imperative language you typically solve such a problem by changing the values of variables. But in a functional language like Clojure the focus is on immutability, function calls, and recursion. While you could find a solution with bindings, set!, or the like, it is not the style in which you should program in Clojure (at least for this kind of problems).

So, a function for calculating the Fibonacci numbers iteratively could look like this (see also this section in SICP Distilled):

(defn fibonacci
  [n]
  (letfn [(fib-iter [a b count]
            (if (= count 0)
              b
              (fib-iter (+ a b) a (- count 1))))]
    (fib-iter 1 0 n)))

fib-iter is a local function and recursively calls itself (via tail call recursion). But as written here:

Since Clojure uses the Java calling conventions, it cannot, and does not, make the same tail call optimization guarantees. Instead, it provides the recur special operator, which does constant-space recursive looping by rebinding and jumping to the nearest enclosing loop or function frame.

Thus, you can replace fib-iter in the tail call with recur to get an iterative process or you could use the loop form which simplifies the code a bit:

(defn fibonacci
  [n]
  (loop [a 1
         b 0
         count n]
    (if (= count 0)
      b
      (recur (+ a b) a (- count 1)))))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.