(And for context, here is Christophe's 'while-let' from 2009): (defmacro while-let
"Makes it easy to continue processing an expression as long as it is true" [binding & forms] `(loop [] (when-let ~binding ~@forms (recur)))) On Wed, Mar 5, 2014 at 5:09 AM, Dan Cross <cro...@gmail.com> wrote: > 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.