To "nest" or iterate a function over a value, Clojure has the iterate
function. For example, (iterate inc 2)
can be thought of as an infinite lazy list [2, (inc 2), (inc (inc 2)), (inc (inc (inc 2))) ...]
(I use the []
brackets not to denote a "list"--in fact, they represent a "vector" in Clojure terms--but to avoid confusion with ()
which can denote a data list or an s-expression that is supposed to be a function call--iterate
does not return a vector). Of course, you probably don't want an infinite list, which is where the lazy part comes in. A lazy list will only give you what you ask it for. So if you ask for the first ten elements, that's what you get:
user> (take 10 (iterate inc 2))
> (2 3 4 5 6 7 8 9 10 11)
Of course, you could try to ask for the whole list, but be prepared to either restart your REPL, or dispatch in a separate thread, because this call will never end:
user> (iterate inc 2)
> (2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
=== Shutting down REPL ===
=== Starting new REPL at C:\Users\Omnomnomri\Clojure\user ===
Clojure 1.5.0
user>
Here, I'm using clooj, and this is what it looks like when I restart my REPL. Anyways, that's all just a tangent. The point is that iterate
answers the core of your question. The other part, stopping upon some test condition, involves take-while
. As you might imagine, take-while
is a lot like take
, only instead of stopping after some number of elements, it stops upon some test condition (or in Clojure parlance, a predicate):
user> (take-while #(< % 10) (iterate inc 2))
> (2 3 4 5 6 7 8 9)
Note that take-while
is exclusive with its predicate test, so that here once the value fails the test (of being less than 10), it excludes that value, and only includes the previous values in the return result. At this point, solving your example is pretty straightfoward:
user> (take-while #(< % 7) (iterate inc 2))
> (2 3 4 5 6)
And if you need it to be a vector, wrap the whole thing in a call to vec
:
user> (vec (take-while #(< % 7) (iterate inc 2)))
> [2 3 4 5 6]