idiomatic way of counting loop iteration

461 views
Skip to first unread message

Joeyjoejoe

unread,
Sep 9, 2016, 8:02:14 AM9/9/16
to Clojure
Hi,

I'm just stating to learn clojure, i made a first read of "clojure programming" to get the big picture, and i'm starting to play with the repl, trying to solve some katas. A lot of theses katas involves returning the count of loop iterations. Most of the time, i end up with this kind of functions:

(defn my-function [a b & [n]]
 
(if cond
   
(my-function new-a new-b (inc (or n 0))
   
(or n defaut-value)
 
)
)

What are the pros/cons of doing this? Are there any idiomatic ways of doing this.

Thank you

Stuart Sierra

unread,
Sep 9, 2016, 8:28:46 AM9/9/16
to Clojure
loop/recur is more typical for this kind of counting loop, as it avoids the risk of a stack-overflow when the number of iterations is high.

Also, I recommend against the [a b & [n]] argument pattern here:

–S

Jason Felice

unread,
Sep 9, 2016, 9:00:31 AM9/9/16
to clo...@googlegroups.com
Generally speaking, `loop`, `recur`, and writing recursive functions are not idiomatic in Clojure.  Using things like `iterate`, `map`, and `filter` are considered clearer.

If `n` is used just to count iterations, then `iterate` would be useful.  e.g.
(first (drop n (iterate (fn [[a b]] ... [new-a new-b]))))

If `n` is used in the computation to create new-a and new-b, then `reduce`  and `range` would be useful.

(reduce (fn [[a b] n]
                ...
                [new-a new-b])
             [a b]
             (range n))

It might be possible to use `map-indexed` with `repeat`, also.

-Jason


--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+unsubscribe@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Joeyjoejoe

unread,
Sep 9, 2016, 11:36:13 AM9/9/16
to Clojure
Thanks, i like the "unambiguous intent" argument from your post, and indeed i met the stack-overflow issue. 

Joeyjoejoe

unread,
Sep 9, 2016, 11:53:50 AM9/9/16
to Clojure
Thanks for helping me!

In your first example:
(first (drop n (iterate (fn [[a b]] ... [new-a new-b]))))
Given that iterate will return a sequence whose length is the number of iteration i'm looking for, the "(first (drop n" part will return one element of this sequence (depending on n value), and not the number of iteration. Am i right?

Maybe i could do this, to get the number of iteration:

Thank you again
(count (iterate (fn [[a b]] ... [new-a new-b]))))

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.

Gary Johnson

unread,
Sep 12, 2016, 5:10:04 PM9/12/16
to Clojure
Almost right. The iterate function is an infinite sequence generator, so (count (iterate f x)) will never return.

If you want the iteration to terminate when cond is false (as in your original example), you're looking for this:

(count (take-while cond (iterate (fn [[a b]] ... [new-a new-b]) [init-a init-b])))

Happy hacking!

Timothy Baldridge

unread,
Sep 12, 2016, 5:18:04 PM9/12/16
to clo...@googlegroups.com
Also consider map-indexed if you just need to count how many things go through a lazy seq. It works like map, but takes a (fn [idx itm] ...) where idx is the index of the item in the overall seq. 

--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
“One of the main causes of the fall of the Roman Empire was that–lacking zero–they had no way to indicate successful termination of their C programs.”
(Robert Firth)
Reply all
Reply to author
Forward
0 new messages