views:

95

answers:

2

Hi, I am stuck in a Clojure loop and need help to get out.

I first want to define a vector

(def lawl [1 2 3 4 5])

I do

(get lawl 0)

And get "1" in return. Now, I want a loop that get each number in the vector, so I do:

(loop [i 0]
   (if (< i (count lawl)) 
     (get lawl i) 
       (recur (inc i))))

In my mind this is supposed to set the value of i to nil, then if i is lower then the count of the lawl vector, it should get each lawl value and then increase the i variable with 1 and try again, getting the next value in the vector.

However, this does not work and I have spent some time trying to get it working and are totally stuck, would appreciate some help. I have also tried changing "if" to "when" with the same result, it doesn't provide any data the REPL just enters a new line and blink.

EDIT: Fixed the recur.

+2  A: 

(recur (inc)) should be (recur (inc i))

Even so this code will just return 1 in the end, if you want a listing of the number you might add a print expression :-) Btw index based loops are not needed at all in scenarios such as this.

(loop [list [1 2 3 4 5] ]
         (if (empty? list)
             (println "done")
             (do
              (println (first list))
              (recur (rest list)))))
Bozhidar Batsov
The problem is that I have an external vector which I need each value to be "pushed" to a function. The example I used above is just a way of showing how I try to get each value in the "lawl" vector to be pushed to the "get" function. I have a function that generates a HTML output, and I have a function that reads a file and sends it to the HTML function for generation. I have created a function that puts each file in a given directory in a vector, so I am trying to make a loop that push each file into the function.
bleakgadfly
Lets say I have vector "dirs" which containts ["/home/bozhidar/file1" "/home/bozhidar/file"] I want a loop that sends each of those files to a function. What a for-loop would do in C or Python.
bleakgadfly
You have to ask yourself what does sending a file to your function mean to you. If you have a function which takes a filename and *returns* some HTML, you'll want to do `(map produce-html the-files)` (where `the-files` may be any seqable, in particular a vector). If you have a function which takes a filename and *causes a side effect involving the HTML*, you'll want to do something like `(doseq [f the-files] (print-html f))`.
Michał Marczyk
I totally support Michal.
Bozhidar Batsov
+3  A: 

You need to consider what is "to get each lawl value" supposed to mean. Your get call does indeed "get" the appropriate value, but since you never do anything with it, it is simply discarded; Bozhidar's suggestion to add a println is a good one and will allow you to see that the loop does indeed access all the elements of lawl (just replace (get ...) with (println (get ...)), after fixing the (inc) => (inc i) thing Bozhidar mentioned also).

That said, if you simply want to do something with each number in turn, loop / recur is not a good way to go about it at all. Here are some others:

;;; do some side-effecty thing to each number in turn:
(dotimes [i (count lawl)]
  (println (str i ": " (lawl i)))) ; you don't really need the get either

;; doseq is more general than dotimes, but doesn't give you equally immediate
;; acess to the index
(doseq [n lawl]
  (println n))

;;; transform the lawl vector somehow and return the result:
; produce a seq of the elements of lawl transformed by some function
(map inc lawl)
; or if you want the result to be a vector too...
(vec (map inc lawl))
; produce a seq of the even members of lawl multiplied by 3
(for [n lawl
      :when (even? n)]
  (* n 3))

This is just the beginning. For a good tour around Clojure's standard library, see the Clojure -- Functional Programming for the JVM article by Mark Volkmann.

Michał Marczyk
If you replace `inc` with, say, `produce-html` in the `map` examples, you'll likely get the best fit for your use case.
Michał Marczyk
Wow, doseq was all I needed!
bleakgadfly