How to implement a For loop in Clojure

25,225

Solution 1

One way to translate an imperative for loop to Clojure is to use the for macro.

(for [i (range 10)] (inc i))

The above function will return all the numbers from 0 to 9 incremented by 1. However, it appears you simply want to iterate over a sequential collection and use each item. If that's all that you need, then you don't need to reference an index value, instead you can reference each item directly.

(for [d my-vec-of-data] (my-function d))

However, for this simple case, the map function would probably be a better choice because it is designed to invoke functions with arguments from collections. The following example is equivalent to the use of for above.

(map my-function my-vec-of-data)

Both map and for return a collection of values made up of the values returned by my-function. This is because Clojure's data structures are immutable, so it's necessary to have a new collection returned. If that isn't what you need or if your function has side effects, you could use doseq instead of for, which returns nil.

Solution 2

Jeremy's answer is good for how to do a for loop in idiomatic Clojure.

If you really want an imperative-style for loop in Clojure, you can create one with this macro:

(defmacro for-loop [[sym init check change :as params] & steps]
 `(loop [~sym ~init value# nil]
    (if ~check
      (let [new-value# (do ~@steps)]
        (recur ~change new-value#))
      value#)))

Usage as follows:

(for-loop [i 0 (< i 10) (inc i)] 
  (println i))

Solution 3

doseq does something similar to a for-loop USAGE:

(doseq [i (for [i (range 10)] (inc i))]
    (println "i=" i))

The binding is similar to that of for in Clojure. However, it does not return a list by evaluating an expression inside the doseq. It performs the expression for each value in the sequence and returns nil.

To loop through a seq, you can simply use:

(doseq [value list]
    (println "Your expression here" value)
Share:
25,225
nuvio
Author by

nuvio

Updated on February 08, 2021

Comments

  • nuvio
    nuvio about 3 years

    I'd like to implement this little code in Clojure, but I am struggling:

    struct mystruct {
       int id;
       int price;
    };
    
    mystruct mydata[10];
    
    for (int i=0; i<10; i++) {
      myfunction(mydata[i].id, mydata[i].price);
      //other things...
    }
    

    I am a beginner with Clojure and it's really complicated for me to do something simple like this, but I am really trying to learn as much as possible as I know that there are great advantages with Clojure such as using refs...

    I would really appreciate it if somebody could help me. Thanks!!

  • nuvio
    nuvio about 12 years
    does 'i' increment automatically?
  • Chuck
    Chuck about 12 years
    @nuvio: i will be the actual item in the sequence, not the index. And yes, the for macro will handle iterating the sequence for you.
  • Dale
    Dale about 12 years
    I love how in Clojure if your missing a language feature, instead of waiting for it to be added to a future version, you can just write your own.
  • jm0
    jm0 about 8 years
    "doseq" is great for functions where you don't need a return val because it returns a single nil instead of 1-per-element
  • Ike Mawira
    Ike Mawira over 4 years
    @Chuck how can you get the actual count, since i is the actual item?