0
    n = (count somevector)        
   (foo [w] ( for [i (range n) 
                   j (range w)
                   :let [n (* i j)] 
                   :while ( < i j)
                  ] 
              (println n)))

When i run it.

=> (foo 10) ClassCastException clojure.lang.LazySeq cannot be cast to clojure.lang.IFn HelloWorld.core/foo

What I am really looking to do is have a couple of nested for loops and have some ifs and else inside it do some checking.

Edit ::

As it turns out the following also causes error

(defn foo [arg]
 (      
      for [ i (range (count vector)) ]
      (
        for [j arg ]
        [i j]
        ) 

     ) ) 

IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom

Edit::

the following works

(defn foo [arg]
  (def w arg) 
(for [ i (range (count vector)) ]
      (
        for [j (range v)  ]
        [i j]
        )
  )   )

Now can someone help me understand why would it not work in the first place ?

3 Answers 3

7

if you use :while, for-loop will return null, because first value is false, :when is better.

user=> (for [i (range 3) j (range 5)] [i j])
([0 0] [0 1] [0 2] [0 3] [0 4] [1 0] [1 1] [1 2] [1 3] [1 4] [2 0] [2 1] [2 2] [2 3] [2 4])
user=> (for [i (range 3) j (range 5) :while (< i j)] [i j])
()
user=> (for [i (range 3) j (range 5) :when (< i j)] [i j])
([0 1] [0 2] [0 3] [0 4] [1 2] [1 3] [1 4] [2 3] [2 4])
Sign up to request clarification or add additional context in comments.

1 Comment

what is the difference between :while and :when in clojure: stackoverflow.com/questions/10966142/…
3

Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom

This error message states the cause of exception accurately. I guess you passed a long value where a seq is expected. I could reproduce it:

user> (def v [1 2 3])
#'user/v
user> (defn foo [arg]
        (for [ i (range (count v)) ]
             (for [j arg ]
                  [i j]))) 
#'user/foo
user> (foo (range 3))
(([0 0] [0 1] [0 2]) ([1 0] [1 1] [1 2]) ([2 0] [2 1] [2 2]))
user> (foo 3)
; Evaluation aborted.
; Don't know how to create ISeq from: java.lang.Long
;  [Thrown class java.lang.IllegalArgumentException]

Your foo function works. However, the arg argument must be a seq, because arg is binded in the nested for to j

1 Comment

for [ j (range arg)] should fix this .
3

The first thing you should know is, that clojure's for is not a for loop, it's a list comprehension.

This means, that it is used to build lists (lazy sequence, actually) with the specified properties.

Your original for looks like this:

(for [i (range n) 
      j (range w)
      :let [n (* i j)] 
      :while ( < i j)] 
  (println n))

(I don't get a class cast exception with your original example).

What it says is: take pairs of i and j while i < j do something. The first pair of i and j is i = 0 and j = 0. Is 0 < 0? No. Stop. That is, you're constructing an empty sequence.

Now, if we change the :while with :when, it'll change the meaning to: for each pair of i and j, for which i < j, and do something with them. That is, you won't stop constructing the sequence when you encounter an i >= j, you'll just skip this pair.

The next thing to note is the println. This function prints its arguments, but always returns nil. This return value is what you'll get in the result sequence and the printing is called a side effect. Generally, you don't want side effect with lazy sequences, because they (the side effects) will happen when needed. That is, if you assign the returned sequence to some variable, none of the printlns will be called. They'll start popping up, when the sequence gets realized.

The bottom line is, don't think of for as a loop, think of it as a sequence constructor.

3 Comments

This was interesting ... so how do we realise a sequence in functional sense ? so, if I return instead of printing does that mean it will realised ?
You "realize" a sequence by requesting its elements. It'll be realized to the point it's needed. For example (take 10 (range)) will return only the first 10 integers of the infinite sequence generated by range. (Actually take is also lazy, but the REPL isn't, so it forces the realization.) You can also force realization explicitly with doall or dorun (they differ in what they return). Also related is doseq.
Also, "traditional" looping is done with loop and recur, but these are often considered low-level building blocks for creating higher level abstractions, like map, filter, for, etc.

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.