On Saturday, October 17, 2009 11:42:28 PM UTC-4, mbrodersen wrote:

> It would be great to have while-let in contrib. Then I don't have to
> maintain let-while myself :-)


I'm reviving this ancient thread because of core.async.  This seems like
just the thing for the common pattern of looping over data received from a
channel until the channel is closed.

Consider the following snippet of Go code that illustrates a common idiom:

func printints(c chan int) {
        for v := range c {
                fmt.Println(v)
        }
        fmt.Println("Channel closed!")
}

(Note: often this would be called in a go routine by e.g., a closure that
adds and removes from a wait group or something similar, but I omit that
here for brevity.)

In particular, notice how the 'range' operator interacts with both the
channel and the 'for' construct to loop over the values received on the
channel until the channel is closed.  I'd like to do something similar in
Clojure, but I don't believe that we have an exact analogue; the closest
I've been able to come up with are the two:

(loop []
  (when-let [v (<! c)]
    (println v)
    (recur)))

and

(while
  (when-let [d (<! c)]
    (println d)
    d))

These work, but neither strikes me as particularly elegant (in particular,
the use of 'while' here is ugly).  Speaking of 'while, I also see this in
some places such as the

(while true (let [v (!< c)] (...)))

However, that won't exit when the channel closes.  Indeed, the loop will
just set 'v' to 'nil' forever after the channel closes (or at least as long
as 'true' is 'true').

What I really want is a loop that iterates (or recurses) while something is
true, like the 'while-let' that was discussed in this thread.  That seems
to capture the semantics of exactly what I want to do when looping over the
items placed onto a channel.  In particular:

- It captures the semantics of doing something *while* a binding is true;
exactly what we want when binding something from a  channel get operation.
- It encapsulates the side-effect in the binding form.
- It's simpler and more elegant than the alternatives.

Indeed, the 'loop' above is really the body of the 'while-let' macro that
Christophe Grand posted back in 2009.

Unfortunately, it doesn't seem to have made it into one of the core
libraries.  Did it ever make it into contrib?  I don't see it in the "Where
Did Clojure.Contrib Go" list.  The only references to it that I see are to
an apparent reimplementation:

https://www.versioneye.com/clojure/while-let:while-let/0.1.0 (which
ultimately leads to...)
https://github.com/markmandel/while-let/blob/master/src/while_let/core.clj

I don't like that nearly as much as Christophe's version, but it is worth
noting that the author specifically mentions core.async as well, thus
implying that there is wider demand for this sort of thing.  Is it worth
asking that this be added to e.g. the core library?  Or even to core.async?

Thanks,

        - Dan C.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@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+unsubscr...@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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to