Re: [ANN] com.walmartlabs/cond-let 1.0.0
I'm glad my little library has gotten some attention on better-cond, which even I'm switching over to. On Thu, Oct 4, 2018 at 10:39 PM Mark Engelberg wrote: > Documentation for latest features in the 2.0.1 branch: > https://github.com/Engelberg/better-cond/tree/v2.0.1 > > An example: > > (cond > (odd? a) 1 >:let [a (quot a 2)] >:when-let [x (fn-which-may-return-nil a), > y (fn-which-may-return-nil (* 2 a))] >:when (seq x) >:do (println x) >(odd? (+ x y)) 2 >:else 3) > > The :do performs a side-effecting statement if it gets that far in the > cond. :do is my favorite bonus addition for cond beyond :let. I find I > use it a lot to quickly insert some debugging print commands without > needing to change the shape of my code, so it can be trivially removed > later. > > When :do did not exist, but :let did exist in my cond macro, I found > myself frequently writing things like: > :let [_ (println x)] > in order to insert a side-effecting statement into the cond sequence. > :do is a cleaner solution. > > :when only continues with the cond if the value is truthy, otherwise it > bails out of the cond with nil. > :when-some (not yet merged in) will do much the same thing, but continuing > if non-nil, rather than truthy. > > :when, :when-some, and :when-let don't add a whole lot of richness. For > example, that :when line in the example could just have easily been written > as: > (not (seq x)) nil > > But using these can potentially add clarity of intention, so even though I > could make do without them, I go ahead and use them when relevant. > > In better-cond's cond macro, that final :else is optional. You may prefer > the new cond-let library if you want to continue enforcing the use of :else > on the last clause. > > To reiterate, :let is by far the most valuable addition, and I find :do to > be the second-most valuable addition. Other additions are fairly minor > syntactic sugar. > > On Thu, Oct 4, 2018 at 1:36 PM Alan Thompson wrote: > >> How would the :when and :do forms work? >> Alan >> >> On Wed, Oct 3, 2018 at 7:22 PM Mark Engelberg >> wrote: >> >>> This looks like a case of "convergent evolution". >>> >>> Having the ability to do a :let in the middle of a cond feels like one >>> of those things that *should* be in the core language, so if it's not >>> in there, a bunch of people are naturally going to arrive at the same >>> solution and make it happen in their own utility libraries. A bunch of us >>> Clojure programmers from the early 1.0 days had been privately passing >>> around and using a "cond that supports :let bindings" macro for years. The >>> first time I saw the macro was in a blog post by Christophe Grand. I really >>> hoped it would make it into Clojure proper -- other functional languages >>> like Racket and F# support ways to bind local variables with "clearer, more >>> linear code, that doesn't make a march for the right margin", as Howard >>> Lewis Ship put it. But after several years had passed without any >>> indication that CLJ-200 was ever going to be addressed, I eventually made >>> the improved cond macro into a clojars library. >>> >>> walmartlabs' cond-let addresses the most important thing (let), which is >>> the critical piece of functionality that feels like the most natural, >>> needed addition to the language. better-cond's :let syntax is identical. >>> But as us old-school Clojurians passed around the "better cond" macro over >>> the years, it grew in functionality. So in better-cond, I included the >>> other little improvements that had accumulated over time, which I had found >>> useful. So better-cond also supports :when, :when-let, and :do (and will >>> soon have :when-some). :let is the only piece that I felt really belonged >>> in the core language's cond, and if CLJ-200 had made it into the core >>> language, I would have been content to just use Clojure's own cond. But >>> once I realized I was going to need a library to achieve the much-needed >>> :let inside of cond, I figured I might as well use that library to include >>> the other convenient cond additions as well. So better-cond is a superset >>> of cond-let's functionality, with support for :let plus a few bonuses. >>> >>> Use whichever one strikes your fancy. cond-let is perfect if all you >>> care about is adding :let to your cond. If you want to experiment with >>> some of the other features beyond :let, you could u
Re: [ANN] com.walmartlabs/cond-let 1.0.0
Documentation for latest features in the 2.0.1 branch: https://github.com/Engelberg/better-cond/tree/v2.0.1 An example: (cond (odd? a) 1 :let [a (quot a 2)] :when-let [x (fn-which-may-return-nil a), y (fn-which-may-return-nil (* 2 a))] :when (seq x) :do (println x) (odd? (+ x y)) 2 :else 3) The :do performs a side-effecting statement if it gets that far in the cond. :do is my favorite bonus addition for cond beyond :let. I find I use it a lot to quickly insert some debugging print commands without needing to change the shape of my code, so it can be trivially removed later. When :do did not exist, but :let did exist in my cond macro, I found myself frequently writing things like: :let [_ (println x)] in order to insert a side-effecting statement into the cond sequence. :do is a cleaner solution. :when only continues with the cond if the value is truthy, otherwise it bails out of the cond with nil. :when-some (not yet merged in) will do much the same thing, but continuing if non-nil, rather than truthy. :when, :when-some, and :when-let don't add a whole lot of richness. For example, that :when line in the example could just have easily been written as: (not (seq x)) nil But using these can potentially add clarity of intention, so even though I could make do without them, I go ahead and use them when relevant. In better-cond's cond macro, that final :else is optional. You may prefer the new cond-let library if you want to continue enforcing the use of :else on the last clause. To reiterate, :let is by far the most valuable addition, and I find :do to be the second-most valuable addition. Other additions are fairly minor syntactic sugar. On Thu, Oct 4, 2018 at 1:36 PM Alan Thompson wrote: > How would the :when and :do forms work? > Alan > > On Wed, Oct 3, 2018 at 7:22 PM Mark Engelberg > wrote: > >> This looks like a case of "convergent evolution". >> >> Having the ability to do a :let in the middle of a cond feels like one of >> those things that *should* be in the core language, so if it's not in >> there, a bunch of people are naturally going to arrive at the same solution >> and make it happen in their own utility libraries. A bunch of us Clojure >> programmers from the early 1.0 days had been privately passing around and >> using a "cond that supports :let bindings" macro for years. The first time >> I saw the macro was in a blog post by Christophe Grand. I really hoped it >> would make it into Clojure proper -- other functional languages like Racket >> and F# support ways to bind local variables with "clearer, more linear >> code, that doesn't make a march for the right margin", as Howard Lewis Ship >> put it. But after several years had passed without any indication that >> CLJ-200 was ever going to be addressed, I eventually made the improved cond >> macro into a clojars library. >> >> walmartlabs' cond-let addresses the most important thing (let), which is >> the critical piece of functionality that feels like the most natural, >> needed addition to the language. better-cond's :let syntax is identical. >> But as us old-school Clojurians passed around the "better cond" macro over >> the years, it grew in functionality. So in better-cond, I included the >> other little improvements that had accumulated over time, which I had found >> useful. So better-cond also supports :when, :when-let, and :do (and will >> soon have :when-some). :let is the only piece that I felt really belonged >> in the core language's cond, and if CLJ-200 had made it into the core >> language, I would have been content to just use Clojure's own cond. But >> once I realized I was going to need a library to achieve the much-needed >> :let inside of cond, I figured I might as well use that library to include >> the other convenient cond additions as well. So better-cond is a superset >> of cond-let's functionality, with support for :let plus a few bonuses. >> >> Use whichever one strikes your fancy. cond-let is perfect if all you >> care about is adding :let to your cond. If you want to experiment with >> some of the other features beyond :let, you could use better-cond and see >> what you think. >> >> Either way, I strongly encourage you to use one of these two libraries so >> you can start using :let inside your cond. I agree fully with Howard Lewis >> Ship that it results in clearer code. Try either library which supports >> this -- it will change your life! >> >> >> On Wed, Oct 3, 2018 at 5:05 PM Matching Socks >> wrote: >> >>> Is this a refinement of Mark Engelberg's "better-cond", or an >>> alternative ap
Re: [ANN] com.walmartlabs/cond-let 1.0.0
How would the :when and :do forms work? Alan On Wed, Oct 3, 2018 at 7:22 PM Mark Engelberg wrote: > This looks like a case of "convergent evolution". > > Having the ability to do a :let in the middle of a cond feels like one of > those things that *should* be in the core language, so if it's not in > there, a bunch of people are naturally going to arrive at the same solution > and make it happen in their own utility libraries. A bunch of us Clojure > programmers from the early 1.0 days had been privately passing around and > using a "cond that supports :let bindings" macro for years. The first time > I saw the macro was in a blog post by Christophe Grand. I really hoped it > would make it into Clojure proper -- other functional languages like Racket > and F# support ways to bind local variables with "clearer, more linear > code, that doesn't make a march for the right margin", as Howard Lewis Ship > put it. But after several years had passed without any indication that > CLJ-200 was ever going to be addressed, I eventually made the improved cond > macro into a clojars library. > > walmartlabs' cond-let addresses the most important thing (let), which is > the critical piece of functionality that feels like the most natural, > needed addition to the language. better-cond's :let syntax is identical. > But as us old-school Clojurians passed around the "better cond" macro over > the years, it grew in functionality. So in better-cond, I included the > other little improvements that had accumulated over time, which I had found > useful. So better-cond also supports :when, :when-let, and :do (and will > soon have :when-some). :let is the only piece that I felt really belonged > in the core language's cond, and if CLJ-200 had made it into the core > language, I would have been content to just use Clojure's own cond. But > once I realized I was going to need a library to achieve the much-needed > :let inside of cond, I figured I might as well use that library to include > the other convenient cond additions as well. So better-cond is a superset > of cond-let's functionality, with support for :let plus a few bonuses. > > Use whichever one strikes your fancy. cond-let is perfect if all you care > about is adding :let to your cond. If you want to experiment with some of > the other features beyond :let, you could use better-cond and see what you > think. > > Either way, I strongly encourage you to use one of these two libraries so > you can start using :let inside your cond. I agree fully with Howard Lewis > Ship that it results in clearer code. Try either library which supports > this -- it will change your life! > > > On Wed, Oct 3, 2018 at 5:05 PM Matching Socks > wrote: > >> Is this a refinement of Mark Engelberg's "better-cond", or an alternative >> approach? >> >> I have not used better-cond myself, but it starts here: >> https://dev.clojure.org/jira/browse/CLJ-200. >> >> -- >> 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/d/optout. >> > -- > 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/d/optout. > -- 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
Re: [ANN] com.walmartlabs/cond-let 1.0.0
Yes, I wouldn't have bothered if I had known about better-cond, so there you go. I think I first wrote this code at Aviso at least five years ago. On Wed, Oct 3, 2018 at 7:22 PM Mark Engelberg wrote: > This looks like a case of "convergent evolution". > > Having the ability to do a :let in the middle of a cond feels like one of > those things that *should* be in the core language, so if it's not in > there, a bunch of people are naturally going to arrive at the same solution > and make it happen in their own utility libraries. A bunch of us Clojure > programmers from the early 1.0 days had been privately passing around and > using a "cond that supports :let bindings" macro for years. The first time > I saw the macro was in a blog post by Christophe Grand. I really hoped it > would make it into Clojure proper -- other functional languages like Racket > and F# support ways to bind local variables with "clearer, more linear > code, that doesn't make a march for the right margin", as Howard Lewis Ship > put it. But after several years had passed without any indication that > CLJ-200 was ever going to be addressed, I eventually made the improved cond > macro into a clojars library. > > walmartlabs' cond-let addresses the most important thing (let), which is > the critical piece of functionality that feels like the most natural, > needed addition to the language. better-cond's :let syntax is identical. > But as us old-school Clojurians passed around the "better cond" macro over > the years, it grew in functionality. So in better-cond, I included the > other little improvements that had accumulated over time, which I had found > useful. So better-cond also supports :when, :when-let, and :do (and will > soon have :when-some). :let is the only piece that I felt really belonged > in the core language's cond, and if CLJ-200 had made it into the core > language, I would have been content to just use Clojure's own cond. But > once I realized I was going to need a library to achieve the much-needed > :let inside of cond, I figured I might as well use that library to include > the other convenient cond additions as well. So better-cond is a superset > of cond-let's functionality, with support for :let plus a few bonuses. > > Use whichever one strikes your fancy. cond-let is perfect if all you care > about is adding :let to your cond. If you want to experiment with some of > the other features beyond :let, you could use better-cond and see what you > think. > > Either way, I strongly encourage you to use one of these two libraries so > you can start using :let inside your cond. I agree fully with Howard Lewis > Ship that it results in clearer code. Try either library which supports > this -- it will change your life! > > > On Wed, Oct 3, 2018 at 5:05 PM Matching Socks > wrote: > >> Is this a refinement of Mark Engelberg's "better-cond", or an alternative >> approach? >> >> I have not used better-cond myself, but it starts here: >> https://dev.clojure.org/jira/browse/CLJ-200. >> >> -- >> 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/d/optout. >> > -- > 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/d/optout. > -- Howard M. Lewis Ship Senior Mobile Developer at Walmart Labs (971) 678
Re: [ANN] com.walmartlabs/cond-let 1.0.0
The short-circuiting is a 'feature' of letting the type control the sequencing of operations. In practice you mix multiple interacting monads depending on what your requirements are, for example I regularly work with Deferred Options and Deferred Results. In clojure, you could try to add a 'if-let' style nil-punning thing to a cond-let implementation but at that point I imagine it more appropriate to take a step back instead :-). I'm not convinced yet that it's worth thinking about it like this in a dynamically typed language, but brought it up because there's a named concept that addresses the need people feel to extend cond/lets. On Thu, Oct 4, 2018 at 12:57 PM lei Shulang wrote: > But a Maybe/Nothing will short-circuit the whole flow where cond-let > won't? > > > On Thursday, 4 October 2018 08:38:05 UTC-7, Moe Aboulkheir wrote: > >> See https://funcool.github.io/cats/latest/#mlet for something closer to >> home, in the monadic vein. >> >> >> On Thu, Oct 4, 2018 at 4:10 PM Gary Trakhman wrote: >> > These are all just sugar over monadic bind, right? >>> >>> Here's one way to do it in the ocaml alternate universe: >>> >>> https://github.com/janestreet/ppx_let#syntactic-forms-and-actual-rewriting >>> >>> But it can be made to work for async or options or whatever, too. >>> >>> We can put the async helpers in the same bucket: >>> https://github.com/ztellman/manifold/blob/master/docs/deferred.md#let-flow >>> >>> The general idea is turning function application into something that >>> looks less nested. >>> >>> On Wed, Oct 3, 2018 at 10:22 PM Mark Engelberg >>> wrote: >>> >> This looks like a case of "convergent evolution". >>>> >>>> Having the ability to do a :let in the middle of a cond feels like one >>>> of those things that *should* be in the core language, so if it's not >>>> in there, a bunch of people are naturally going to arrive at the same >>>> solution and make it happen in their own utility libraries. A bunch of us >>>> Clojure programmers from the early 1.0 days had been privately passing >>>> around and using a "cond that supports :let bindings" macro for years. The >>>> first time I saw the macro was in a blog post by Christophe Grand. I really >>>> hoped it would make it into Clojure proper -- other functional languages >>>> like Racket and F# support ways to bind local variables with "clearer, more >>>> linear code, that doesn't make a march for the right margin", as Howard >>>> Lewis Ship put it. But after several years had passed without any >>>> indication that CLJ-200 was ever going to be addressed, I eventually made >>>> the improved cond macro into a clojars library. >>>> >>>> walmartlabs' cond-let addresses the most important thing (let), which >>>> is the critical piece of functionality that feels like the most natural, >>>> needed addition to the language. better-cond's :let syntax is identical. >>>> But as us old-school Clojurians passed around the "better cond" macro over >>>> the years, it grew in functionality. So in better-cond, I included the >>>> other little improvements that had accumulated over time, which I had found >>>> useful. So better-cond also supports :when, :when-let, and :do (and will >>>> soon have :when-some). :let is the only piece that I felt really belonged >>>> in the core language's cond, and if CLJ-200 had made it into the core >>>> language, I would have been content to just use Clojure's own cond. But >>>> once I realized I was going to need a library to achieve the much-needed >>>> :let inside of cond, I figured I might as well use that library to include >>>> the other convenient cond additions as well. So better-cond is a superset >>>> of cond-let's functionality, with support for :let plus a few bonuses. >>>> >>>> Use whichever one strikes your fancy. cond-let is perfect if all you >>>> care about is adding :let to your cond. If you want to experiment with >>>> some of the other features beyond :let, you could use better-cond and see >>>> what you think. >>>> >>>> Either way, I strongly encourage you to use one of these two libraries >>>> so you can start using :let inside your cond. I agree fully with Howard >>>> Lewis Ship that it results in clearer code. Try either library which >>>> supports this -- it will change your l
Re: [ANN] com.walmartlabs/cond-let 1.0.0
But a Maybe/Nothing will short-circuit the whole flow where cond-let won't? On Thursday, 4 October 2018 08:38:05 UTC-7, Moe Aboulkheir wrote: > > See https://funcool.github.io/cats/latest/#mlet for something closer to > home, in the monadic vein. > > > On Thu, Oct 4, 2018 at 4:10 PM Gary Trakhman > wrote: > >> These are all just sugar over monadic bind, right? >> >> Here's one way to do it in the ocaml alternate universe: >> https://github.com/janestreet/ppx_let#syntactic-forms-and-actual-rewriting >> >> But it can be made to work for async or options or whatever, too. >> >> We can put the async helpers in the same bucket: >> https://github.com/ztellman/manifold/blob/master/docs/deferred.md#let-flow >> >> The general idea is turning function application into something that >> looks less nested. >> >> On Wed, Oct 3, 2018 at 10:22 PM Mark Engelberg > > wrote: >> >>> This looks like a case of "convergent evolution". >>> >>> Having the ability to do a :let in the middle of a cond feels like one >>> of those things that *should* be in the core language, so if it's not >>> in there, a bunch of people are naturally going to arrive at the same >>> solution and make it happen in their own utility libraries. A bunch of us >>> Clojure programmers from the early 1.0 days had been privately passing >>> around and using a "cond that supports :let bindings" macro for years. The >>> first time I saw the macro was in a blog post by Christophe Grand. I really >>> hoped it would make it into Clojure proper -- other functional languages >>> like Racket and F# support ways to bind local variables with "clearer, more >>> linear code, that doesn't make a march for the right margin", as Howard >>> Lewis Ship put it. But after several years had passed without any >>> indication that CLJ-200 was ever going to be addressed, I eventually made >>> the improved cond macro into a clojars library. >>> >>> walmartlabs' cond-let addresses the most important thing (let), which is >>> the critical piece of functionality that feels like the most natural, >>> needed addition to the language. better-cond's :let syntax is identical. >>> But as us old-school Clojurians passed around the "better cond" macro over >>> the years, it grew in functionality. So in better-cond, I included the >>> other little improvements that had accumulated over time, which I had found >>> useful. So better-cond also supports :when, :when-let, and :do (and will >>> soon have :when-some). :let is the only piece that I felt really belonged >>> in the core language's cond, and if CLJ-200 had made it into the core >>> language, I would have been content to just use Clojure's own cond. But >>> once I realized I was going to need a library to achieve the much-needed >>> :let inside of cond, I figured I might as well use that library to include >>> the other convenient cond additions as well. So better-cond is a superset >>> of cond-let's functionality, with support for :let plus a few bonuses. >>> >>> Use whichever one strikes your fancy. cond-let is perfect if all you >>> care about is adding :let to your cond. If you want to experiment with >>> some of the other features beyond :let, you could use better-cond and see >>> what you think. >>> >>> Either way, I strongly encourage you to use one of these two libraries >>> so you can start using :let inside your cond. I agree fully with Howard >>> Lewis Ship that it results in clearer code. Try either library which >>> supports this -- it will change your life! >>> >>> >>> On Wed, Oct 3, 2018 at 5:05 PM Matching Socks >> > wrote: >>> >>>> Is this a refinement of Mark Engelberg's "better-cond", or an >>>> alternative approach? >>>> >>>> I have not used better-cond myself, but it starts here: >>>> https://dev.clojure.org/jira/browse/CLJ-200. >>>> >>>> -- >>>> 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+u...@googlegroups.com >>&
Re: [ANN] com.walmartlabs/cond-let 1.0.0
See https://funcool.github.io/cats/latest/#mlet for something closer to home, in the monadic vein. On Thu, Oct 4, 2018 at 4:10 PM Gary Trakhman wrote: > These are all just sugar over monadic bind, right? > > Here's one way to do it in the ocaml alternate universe: > https://github.com/janestreet/ppx_let#syntactic-forms-and-actual-rewriting > > But it can be made to work for async or options or whatever, too. > > We can put the async helpers in the same bucket: > https://github.com/ztellman/manifold/blob/master/docs/deferred.md#let-flow > > The general idea is turning function application into something that looks > less nested. > > On Wed, Oct 3, 2018 at 10:22 PM Mark Engelberg > wrote: > >> This looks like a case of "convergent evolution". >> >> Having the ability to do a :let in the middle of a cond feels like one of >> those things that *should* be in the core language, so if it's not in >> there, a bunch of people are naturally going to arrive at the same solution >> and make it happen in their own utility libraries. A bunch of us Clojure >> programmers from the early 1.0 days had been privately passing around and >> using a "cond that supports :let bindings" macro for years. The first time >> I saw the macro was in a blog post by Christophe Grand. I really hoped it >> would make it into Clojure proper -- other functional languages like Racket >> and F# support ways to bind local variables with "clearer, more linear >> code, that doesn't make a march for the right margin", as Howard Lewis Ship >> put it. But after several years had passed without any indication that >> CLJ-200 was ever going to be addressed, I eventually made the improved cond >> macro into a clojars library. >> >> walmartlabs' cond-let addresses the most important thing (let), which is >> the critical piece of functionality that feels like the most natural, >> needed addition to the language. better-cond's :let syntax is identical. >> But as us old-school Clojurians passed around the "better cond" macro over >> the years, it grew in functionality. So in better-cond, I included the >> other little improvements that had accumulated over time, which I had found >> useful. So better-cond also supports :when, :when-let, and :do (and will >> soon have :when-some). :let is the only piece that I felt really belonged >> in the core language's cond, and if CLJ-200 had made it into the core >> language, I would have been content to just use Clojure's own cond. But >> once I realized I was going to need a library to achieve the much-needed >> :let inside of cond, I figured I might as well use that library to include >> the other convenient cond additions as well. So better-cond is a superset >> of cond-let's functionality, with support for :let plus a few bonuses. >> >> Use whichever one strikes your fancy. cond-let is perfect if all you >> care about is adding :let to your cond. If you want to experiment with >> some of the other features beyond :let, you could use better-cond and see >> what you think. >> >> Either way, I strongly encourage you to use one of these two libraries so >> you can start using :let inside your cond. I agree fully with Howard Lewis >> Ship that it results in clearer code. Try either library which supports >> this -- it will change your life! >> >> >> On Wed, Oct 3, 2018 at 5:05 PM Matching Socks >> wrote: >> >>> Is this a refinement of Mark Engelberg's "better-cond", or an >>> alternative approach? >>> >>> I have not used better-cond myself, but it starts here: >>> https://dev.clojure.org/jira/browse/CLJ-200. >>> >>> -- >>> 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/d/optout. >>> >> -- >> You received this message because
Re: [ANN] com.walmartlabs/cond-let 1.0.0
These are all just sugar over monadic bind, right? Here's one way to do it in the ocaml alternate universe: https://github.com/janestreet/ppx_let#syntactic-forms-and-actual-rewriting But it can be made to work for async or options or whatever, too. We can put the async helpers in the same bucket: https://github.com/ztellman/manifold/blob/master/docs/deferred.md#let-flow The general idea is turning function application into something that looks less nested. On Wed, Oct 3, 2018 at 10:22 PM Mark Engelberg wrote: > This looks like a case of "convergent evolution". > > Having the ability to do a :let in the middle of a cond feels like one of > those things that *should* be in the core language, so if it's not in > there, a bunch of people are naturally going to arrive at the same solution > and make it happen in their own utility libraries. A bunch of us Clojure > programmers from the early 1.0 days had been privately passing around and > using a "cond that supports :let bindings" macro for years. The first time > I saw the macro was in a blog post by Christophe Grand. I really hoped it > would make it into Clojure proper -- other functional languages like Racket > and F# support ways to bind local variables with "clearer, more linear > code, that doesn't make a march for the right margin", as Howard Lewis Ship > put it. But after several years had passed without any indication that > CLJ-200 was ever going to be addressed, I eventually made the improved cond > macro into a clojars library. > > walmartlabs' cond-let addresses the most important thing (let), which is > the critical piece of functionality that feels like the most natural, > needed addition to the language. better-cond's :let syntax is identical. > But as us old-school Clojurians passed around the "better cond" macro over > the years, it grew in functionality. So in better-cond, I included the > other little improvements that had accumulated over time, which I had found > useful. So better-cond also supports :when, :when-let, and :do (and will > soon have :when-some). :let is the only piece that I felt really belonged > in the core language's cond, and if CLJ-200 had made it into the core > language, I would have been content to just use Clojure's own cond. But > once I realized I was going to need a library to achieve the much-needed > :let inside of cond, I figured I might as well use that library to include > the other convenient cond additions as well. So better-cond is a superset > of cond-let's functionality, with support for :let plus a few bonuses. > > Use whichever one strikes your fancy. cond-let is perfect if all you care > about is adding :let to your cond. If you want to experiment with some of > the other features beyond :let, you could use better-cond and see what you > think. > > Either way, I strongly encourage you to use one of these two libraries so > you can start using :let inside your cond. I agree fully with Howard Lewis > Ship that it results in clearer code. Try either library which supports > this -- it will change your life! > > > On Wed, Oct 3, 2018 at 5:05 PM Matching Socks > wrote: > >> Is this a refinement of Mark Engelberg's "better-cond", or an alternative >> approach? >> >> I have not used better-cond myself, but it starts here: >> https://dev.clojure.org/jira/browse/CLJ-200. >> >> -- >> 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/d/optout. >> > -- > 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 &
Re: [ANN] com.walmartlabs/cond-let 1.0.0
This looks like a case of "convergent evolution". Having the ability to do a :let in the middle of a cond feels like one of those things that *should* be in the core language, so if it's not in there, a bunch of people are naturally going to arrive at the same solution and make it happen in their own utility libraries. A bunch of us Clojure programmers from the early 1.0 days had been privately passing around and using a "cond that supports :let bindings" macro for years. The first time I saw the macro was in a blog post by Christophe Grand. I really hoped it would make it into Clojure proper -- other functional languages like Racket and F# support ways to bind local variables with "clearer, more linear code, that doesn't make a march for the right margin", as Howard Lewis Ship put it. But after several years had passed without any indication that CLJ-200 was ever going to be addressed, I eventually made the improved cond macro into a clojars library. walmartlabs' cond-let addresses the most important thing (let), which is the critical piece of functionality that feels like the most natural, needed addition to the language. better-cond's :let syntax is identical. But as us old-school Clojurians passed around the "better cond" macro over the years, it grew in functionality. So in better-cond, I included the other little improvements that had accumulated over time, which I had found useful. So better-cond also supports :when, :when-let, and :do (and will soon have :when-some). :let is the only piece that I felt really belonged in the core language's cond, and if CLJ-200 had made it into the core language, I would have been content to just use Clojure's own cond. But once I realized I was going to need a library to achieve the much-needed :let inside of cond, I figured I might as well use that library to include the other convenient cond additions as well. So better-cond is a superset of cond-let's functionality, with support for :let plus a few bonuses. Use whichever one strikes your fancy. cond-let is perfect if all you care about is adding :let to your cond. If you want to experiment with some of the other features beyond :let, you could use better-cond and see what you think. Either way, I strongly encourage you to use one of these two libraries so you can start using :let inside your cond. I agree fully with Howard Lewis Ship that it results in clearer code. Try either library which supports this -- it will change your life! On Wed, Oct 3, 2018 at 5:05 PM Matching Socks wrote: > Is this a refinement of Mark Engelberg's "better-cond", or an alternative > approach? > > I have not used better-cond myself, but it starts here: > https://dev.clojure.org/jira/browse/CLJ-200. > > -- > 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/d/optout. > -- 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/d/optout.
Re: [ANN] com.walmartlabs/cond-let 1.0.0
Is this a refinement of Mark Engelberg's "better-cond", or an alternative approach? I have not used better-cond myself, but it starts here: https://dev.clojure.org/jira/browse/CLJ-200. -- 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/d/optout.
[ANN] com.walmartlabs/cond-let 1.0.0
A micro library of a single macro, cond-let. cond-let acts like a cond, but adds :let terms that are followed by a binding form (like let). This allows conditional code to introduce new local symbols; the result is clearer, more linear code, that doesn't make a march for the right margin. Example: (defn ^:private has-necessary-capabilities? "Does the worker have all the capabilities that the job needs?" [state worker-id task] (cond-let :let [job-id (:job-id task)] (nil? job-id) true :let [capabilities (get-in state [:jobs job-id :clockwork/required-capabilities])] (empty? capabilities) true :let [worker-capabilities (get-in state [:workers worker-id :capabilities])] (empty? worker-capabilities) false :else ;; It's ok for the worker to have *more* capabilities than are specified. ;; For each required capability, we need an exact match. (= (select-keys worker-capabilities (keys capabilities)) capabilities))) https://github.com/walmartlabs/cond-let -- Howard M. Lewis Ship Senior Mobile Developer at Walmart Labs (971) 678-5210 http://howardlewisship.com @hlship -- 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/d/optout.
Re: ANN: Parallel let macro!
Interesting seeing the different solutions to this problem. Seems like a good place to remind people about the plumatic/plumbing Graph library: (require '[plumbing.core :refer (fnk)])(require '[plumbing.graph :as graph]) (def g { :a (fnk [] (:a (remote-req {:a 1 :x 2}))) :b (fnk [] (remote-req 1)) :c (fnk [a b] (+ a b)) :d (fnk [] (remote-req 1)) :e (fnk [] (remote-req 1)) :f (fnk [d e] (+ d e)) :ret (fnk [c f] (+ c f))}) (def g-eager (graph/compile g))(def g-par (graph/par-compile g))(time (into {} (g-eager {})));; "Elapsed time: 4005.972714 msecs"(time (into {} (g-par {})));; "Elapsed time: 1003.358028 msecs" I’d say it has an intermediate complexity between a simple macro and the libraries you mentioned. And if you wrote your own “lazy + parallel + caching” graph compiler, you could get a good fraction of the functionality of the libraries you mentioned. Muse and Urania give off a Haskell-y vibe (no surprise) and Graph feels more Clojure-y to me, but they are all interesting projects. Thanks for the post, Leif On Tuesday, November 28, 2017 at 6:58:09 AM UTC-7, Eunmin Kim wrote: Hi, folks > > This is small piece of code that is inspired by haxl, muse( > https://github.com/kachayev/muse), urania( > https://github.com/funcool/urania). Not a library. > > (defn remote-req [result] > (Thread/sleep 1000) > result) > > (defmacro plet [bindings & body] > (let [bents (partition 2 (destructure bindings)) > smap (into {} (map (fn [[b _]] > [b `(deref ~b)]) >bents)) > bindings (vec (mapcat (fn [[b v]] > [b `(future ~(postwalk-replace smap v))]) > bents))] > `(let ~bindings >~@(postwalk-replace smap body > > (time > (let [{:keys [a]} (remote-req {:a 1 :x 2}) >b (remote-req 1) >c (+ a b) >d (remote-req 1) >e (remote-req 1) >f (+ d e)] >(+ c f)));; "Elapsed time: 4007.60237 msecs" > > (time > (plet [{:keys [a]} (remote-req {:a 1 :x 2}) > b (remote-req 1) > c (+ a b) > d (remote-req 1) > e (remote-req 1) > f (+ d e)] >(+ c f)));; "Elapsed time: 1003.733416 msecs" > > > https://github.com/eunmin/plet > > Thanks! > > - Eunmin > -- 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/d/optout.
Re: ANN: Parallel let macro!
Cool! Check out code-walking libraries like riddley <https://github.com/ztellman/riddley> or tools.analyzer.jvm <https://github.com/clojure/tools.analyzer.jvm> to properly support special forms and variable shadowing. I had a quick crack myself but gave up when I remembered how hard this problem is. Thanks, Ambrose On Tuesday, November 28, 2017 at 8:58:09 AM UTC-5, Eunmin Kim wrote: > > Hi, folks > > This is small piece of code that is inspired by haxl, muse( > https://github.com/kachayev/muse), urania( > https://github.com/funcool/urania). Not a library. > > (defn remote-req [result] > (Thread/sleep 1000) > result) > > (defmacro plet [bindings & body] > (let [bents (partition 2 (destructure bindings)) > smap (into {} (map (fn [[b _]] > [b `(deref ~b)]) >bents)) > bindings (vec (mapcat (fn [[b v]] > [b `(future ~(postwalk-replace smap v))]) > bents))] > `(let ~bindings >~@(postwalk-replace smap body > > (time > (let [{:keys [a]} (remote-req {:a 1 :x 2}) >b (remote-req 1) >c (+ a b) >d (remote-req 1) >e (remote-req 1) >f (+ d e)] >(+ c f)));; "Elapsed time: 4007.60237 msecs" > > (time > (plet [{:keys [a]} (remote-req {:a 1 :x 2}) > b (remote-req 1) > c (+ a b) > d (remote-req 1) > e (remote-req 1) > f (+ d e)] >(+ c f)));; "Elapsed time: 1003.733416 msecs" > > > https://github.com/eunmin/plet > > Thanks! > > - Eunmin > -- 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/d/optout.
Re: ANN: Parallel let macro!
Very nice! Kudos. -- 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/d/optout.
ANN: Parallel let macro!
Hi, folks This is small piece of code that is inspired by haxl, muse(https://github.com/kachayev/muse), urania(https://github.com/funcool/urania). Not a library. (defn remote-req [result] (Thread/sleep 1000) result) (defmacro plet [bindings & body] (let [bents (partition 2 (destructure bindings)) smap (into {} (map (fn [[b _]] [b `(deref ~b)]) bents)) bindings (vec (mapcat (fn [[b v]] [b `(future ~(postwalk-replace smap v))]) bents))] `(let ~bindings ~@(postwalk-replace smap body (time (let [{:keys [a]} (remote-req {:a 1 :x 2}) b (remote-req 1) c (+ a b) d (remote-req 1) e (remote-req 1) f (+ d e)] (+ c f)));; "Elapsed time: 4007.60237 msecs" (time (plet [{:keys [a]} (remote-req {:a 1 :x 2}) b (remote-req 1) c (+ a b) d (remote-req 1) e (remote-req 1) f (+ d e)] (+ c f)));; "Elapsed time: 1003.733416 msecs" https://github.com/eunmin/plet Thanks! - Eunmin -- 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/d/optout.
Re: Got NullpointerException when using loop/recur/let together
Also, have another look at '(ret (- time-now start-time)) It will yield a list containing the symbol 'ret and a nested list containing the symbol '- etc etc etc. I think what you expected was a vector of two numbers. -- 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/d/optout.
Re: Got NullpointerException when using loop/recur/let together
you wrap a call to Thread/sleep in parens, in clojure this means you want to call it, Thread/sleep returns nil and calling nil gives a NullpointerException Parens are not for grouping or sequencing things in clojure, and you don't need them here - fn has an implicit do block already, in other contexts where there isn't a do block implicitly, you can use do to sequence expressions On Tue, Oct 24, 2017 at 5:26 PM yihao yang <yangyihao1...@gmail.com> wrote: > Hi, all > > I want to do sth. like query until timeout. So I write a function below. > (defn wait-ls-ready > [] > (let [pair-fn (fn [] ( > (Thread/sleep 1000) > (let [ret (try > (c/exec :ls) > 0 > (catch RuntimeException e -1) >), >time-now (quot (System/currentTimeMillis) > 1000)] >'(ret (- time-now start-time)) > ) >))] > (loop [start-time (quot (System/currentTimeMillis) 1000) >time-out 10] > (let [[ret time-delta] (pair-fn)] > (info node "Waiting gsql works...") > (if (= 0 ret) 0 > (if (> time-delta time-out) > (throw (RuntimeException. > (str "'ls' not working in " time-out "seconds."))) > (recur start-time time-out > ) > ) > ) > > But it returns a NullpointerException after 1 seconds. Could anyone help > me out? > > Thanks, > Yihao > > -- > 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/d/optout. > -- 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/d/optout.
Got NullpointerException when using loop/recur/let together
Hi, all I want to do sth. like query until timeout. So I write a function below. (defn wait-ls-ready [] (let [pair-fn (fn [] ( (Thread/sleep 1000) (let [ret (try (c/exec :ls) 0 (catch RuntimeException e -1) ), time-now (quot (System/currentTimeMillis) 1000)] '(ret (- time-now start-time)) ) ))] (loop [start-time (quot (System/currentTimeMillis) 1000) time-out 10] (let [[ret time-delta] (pair-fn)] (info node "Waiting gsql works...") (if (= 0 ret) 0 (if (> time-delta time-out) (throw (RuntimeException. (str "'ls' not working in " time-out "seconds."))) (recur start-time time-out ) ) ) But it returns a NullpointerException after 1 seconds. Could anyone help me out? Thanks, Yihao -- 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/d/optout.
Re: How to try/catch Let bindings?
As others have noted, this is pretty much what monads are made for. I've found Brian Marick's "Functional Programming for the Object-Oriented Programmer"'s chapter on monads really good at teaching how to recognize situations where monads would be a good fit. For this specific use-case, you can probably, as an intermediate solution, define a fairly simple macro that would get you almost all you want, something like: (defmacro mlet [bindings & body] (if (seq bindings) (let [[b expr & r] bindings] `(try (let [~b ~expr] (mlet ~r ~@body)) (catch Exception e# (let [~b [:mlet/error e#]] (let ~(->> r (partition 2) (mapcat (fn [[b _]] [b :mlet/unbound])) vec) ~@body) `(do ~@body))) (mlet [a (+ 1 2) b (- a 3) c (/ 10 b) d (inc c)] [a b c d]);; => [3 0 [:mlet/error #error {#_elided}] :mlet/unbound] Depending on how much complexity you're willing to bear within that macro, you could do smarter things like detecting which variables can still be computed, etc. Maybe also take a look at prismatic graph? https://github.com/plumatic/plumbing -- 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/d/optout.
Re: How to try/catch Let bindings?
You could use exceptions, is that a hard requirement or are you working to transition your mental model for Java code to Clojure? If you can catch the exceptions or not throw them to begin with there’s some other options; Another way you could do it is using core.async and channels as some others have mentioned. Yet another way would be using cats. A similar solution to what the problem you described is outlined partway through this article (there’s a lot there): https://blog.skyliner.io/fourteen-months-with-clojure-beb8b3e4bf00 A friend of mine used to say “get it writ, then get it right”. As long as you encapsulate the desired behaviour in the function you can try all of the different suggestions and take a decision of what feels more readable to you and others on your team. On Sat, 30 Sep 2017 at 23:14, Didier <didi...@gmail.com> wrote: > I'm curious how others handle this use case, which I feel should be pretty > common. > > Given you have a series of business process steps, where the flow is too > complex for the arrow macros, and you also like to name the step results > descriptively, so you use let: > > (let [a (do-a ...) > b (do-b . a . .) > c (do-c . a . b)] > (log/info "Success" {:a a >:b b >:c c}) > c) > > Now, say each steps could possibly throw an exception. So you want to > try/catch the let bindings: > > (try > (let [a (do-a ...) > b (do-b . a . .) > c (do-c . a . b)] > (log/info "Success" {:a a > :b b > :c c}) > c) > (catch Exception e > (log/error "Failed" {:a a > :b b > :c c}) > (throw e))) > > But, inside the catch, you need access to the let bindings a,b,c, in order > to recover from the failure, or like in my example, just to log so that > debugging of the issue is easier. > > Now the catch will not be in scope of the bindings, and this won't even > compile: "Can not find symbol a,b,c in context...". > > What would be the idomatic thing to do here? > > Is there another way to execute a set of complex steps which does not rely > on let and can be try/catched in the manner I describe? > > Or is there a way to re-write the let that satisfies my case, and remains > idiomatic, and does not add accidental complexities? > > Thank You. > > -- > 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/d/optout. > -- - sent from my mobile -- 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/d/optout.
Re: How to try/catch Let bindings?
Now that bertschi mentioned Haskell and side-effects, I noticed that the problem we have here totally looks like a monad: we have several steps of side-effecting computation, and each of them can fail, and when this happens you want to handle the failure while keeping the previous bindings. Now, when it comes to handling Java exceptions in a monadic way, we can look at the Try monad in Scala, that is exactly what we are searching for. We have several libraries that implement monadic sugar in Clojure, and `cats` [1] implements the try monad [2]. Example usage with `mlet` (monadic let, aka `do` in Haskell): => (require '[cats.core :as m]) nil => (require '[cats.monad.exception :as exc]) nil => (m/mlet [a (exc/try-on 1) b (exc/try-on a)] ;; a is visible in b scope of course, as in standard let (m/return (str "a: " a ", b: " b))) # boot.user=> (m/mlet [a (exc/try-on 1) b (exc/try-on (+ 1 nil))] ;; when you get an exception it blows up (m/return (str "a: " a ", b: " b))) # (m/mlet [a (exc/try-on 1) b (exc/try-or-else (+ 1 nil) a)] ;; but you have the a binding also in case of exception (m/return (str "a: " a ", b: " b))) # [1]: https://github.com/funcool/cats [2]: http://funcool.github.io/cats/latest/#exception Cheers, Fabrizio On Mon, Oct 2, 2017 at 4:39 AM, Didier <didi...@gmail.com> wrote: > I've seen this, I was still curious if the reason I was facing the issue > was that let is simply the wrong tool for my use case or not. > > If let is the correct tool, I would propose that clojure.core should had a > try/catch where the catch is in scope of the try. I feel the reason this is > contrived is accidental complexity due to limitations of Clojure. In Java, > this isn't an issue, because you're variables would be mutable: > > > Object a; > Object b; > Object c; > try { > a = doA(..); > b = doB(.., a, .., .., ..); > c = doC(.., .., a, .., b, ..); > } catch { > // The catch is in scope of a,b,c. > } > > Which I feel I can't think of any way in Clojure to do this, which does > not add accidental complexity. In that, there's nothing to the actual > problem which requires say the complexity of a let inside a let, a > try/catch around each steps, binding atoms, delays, promise, volatile and > then setting them inside the try, etc. All these seems to me like Clojure > just adds some accidental complexity to this common use case. > > What do others think? > > > On Saturday, 30 September 2017 16:42:48 UTC-7, Marcus Magnusson wrote: >> >> I've used try-let (link below) for this, it's worked great! >> >> https://github.com/rufoa/try-let >> > -- > 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/d/optout. > -- 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/d/optout.
Re: How to try/catch Let bindings?
On Monday, October 2, 2017 at 11:04:52 PM UTC+2, Didier wrote: > > > Even in an impure language such as Common Lisp we frown on such LET forms > > True, but as far as I know, in Common Lisp, the condition handler is > always in scope of where the error happened, so I wouldn't face this > problem. > > I also struggle to split this up into functions without making it even > more complicated. I'm intrigued by the interceptor pattern mentioned, I'll > have to try it out, I worry its overkill, but not sure. > > My opposition to turning this into a chain, is that it complects the order > of things, with the work of each step. My steps are pure functions, they > take inputs and return outputs. They don't know anything about the full > workflow, just their transformation. My orchestrating function is the one > which knows how to compose the smaller pure steps, so that it can fulfill > the business process. > No, your functions are not pure. Besides returning a value they can throw an exception, i.e. they have a side-effect! As we know from Haskell, this forces them to be evaluated in a sequential order ... just ask yourself what value the variable c should be bound to if an exception is thrown by doB. Both suggested solutions seem to be reasonable. While try-let ignores all bindings when an error occurs (check with macroexpand), the interceptor chain probably can see all bindings established before the error occured (I have not tested this though) and thus correctly imposes a sequential order. Best, Nils The interceptor chain seems to still complect this a little. At least it > has the steps know about each other since it relies on a common context, > and expects previous steps to properly assoc the data needed by later steps. > > -- 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/d/optout.
Re: How to try/catch Let bindings?
> Even in an impure language such as Common Lisp we frown on such LET forms True, but as far as I know, in Common Lisp, the condition handler is always in scope of where the error happened, so I wouldn't face this problem. I also struggle to split this up into functions without making it even more complicated. I'm intrigued by the interceptor pattern mentioned, I'll have to try it out, I worry its overkill, but not sure. My opposition to turning this into a chain, is that it complects the order of things, with the work of each step. My steps are pure functions, they take inputs and return outputs. They don't know anything about the full workflow, just their transformation. My orchestrating function is the one which knows how to compose the smaller pure steps, so that it can fulfill the business process. The interceptor chain seems to still complect this a little. At least it has the steps know about each other since it relies on a common context, and expects previous steps to properly assoc the data needed by later steps. -- 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/d/optout.
Re: How to try/catch Let bindings?
On Saturday, September 30, 2017 at 6:14:33 PM UTC-4, Didier wrote: > > I'm curious how others handle this use case, which I feel should be pretty > common. > > Given you have a series of business process steps, where the flow is too > complex for the arrow macros, and you also like to name the step results > descriptively, so you use let: > You are almost saying what I am thinking: this beast of a calculation has to be broken up (into separate functions)! :) > > (let [a (do-a ...) > b (do-b . a . .) > c (do-c . a . b)] > Even in an impure language such as Common Lisp we frown on such LET forms. I believe it was Lisp legend Paul Graham who suggested we imagine a tax on LET. Sometimes while sorting out something complex I do solve it in a series of LET bindings, but once I understand what I am about I am able to add clarity by shuffling the code into a nice functional form (and yes, sometimes break things out into standalone functions if only to make the source more approachable). I then think the exception handling will sort itself on its own. -kt -- 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/d/optout.
Re: How to try/catch Let bindings?
> On Oct 1, 2017, at 9:21 PM, Didierwrote: > > I can't emphasize enough the utility of the interceptor chain pattern, as > employed heavily in pedestal. > > Interesting... Its almost like a workflow framework, but for simpler in code > workflows. I'm reluctant to have a dependency on pedestal just for this > though. The dependencies required are pretty minimal, you just pull in the interceptor stuff by itself. Those guys did a good job of breaking pedestal into reusable pieces. [io.pedestal/pedestal.interceptor "0.5.2"] [io.pedestal/pedestal.log "0.5.2"] [io.dropwizard.metrics/metrics-core "3.1.2"] [org.clojure/core.match "0.3.0-alpha4" :exclusions [[org.clojure/clojurescript] [org.clojure/tools.analyzer.jvm]]] Plus core.async. I've rolled my own mini-interceptor too. If you don't need the "leave" interceptor concept and are happy with one-way execution, we're just talking about pushing functions onto a queue. Each function takes a context map that includes the queue itself. Then, implement an executor that dequeues each function and executes it. Capture any errors at this point and short-circuit execution. Having gone down that route I just ended up using pedestal.interceptor, after reading the source code and realizing it's so simple. I like using other people's heavily debugged code :) -- 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/d/optout.
Re: How to try/catch Let bindings?
Didier, I've done something similar a few times just using core.async -- no extra deps required ;-) d On 1 October 2017 at 23:21, Didier <didi...@gmail.com> wrote: > I can't emphasize enough the utility of the interceptor chain pattern, as >> employed heavily in pedestal. >> > > Interesting... Its almost like a workflow framework, but for simpler in > code workflows. I'm reluctant to have a dependency on pedestal just for > this though. > > On Sunday, 1 October 2017 21:00:31 UTC-7, Luke Burton wrote: > >> >> On Sep 30, 2017, at 3:14 PM, Didier <did...@gmail.com> wrote: >> >> Is there another way to execute a set of complex steps which does not >> rely on let and can be try/catched in the manner I describe? >> >> >> I can't emphasize enough the utility of the interceptor chain pattern, as >> employed heavily in pedestal. >> >> I use this *everywhere* now. I have code that interleaves interceptors >> into a chain to augment them with timing information, audit logs, and more. >> I have written code that maps a subset of an interceptor chain over a >> cluster of machines, then reduces the results back down locally. Most >> importantly, they are fantastically useful when it comes time to debug a >> complex business process … you can swap interceptors in and out easily, >> isolate stateful interceptors to enable better mocking during tests, and >> more. >> >> Here's a basic application of interceptors. It's really not much code >> considering what you get. This doesn't even scratch the surface of what >> they can do. >> >> (ns interceptor.test >> (:require >> [io.pedestal.interceptor.chain :as chain])) >> >> (def step1 >> {:name :step1 >>:enter (fn [ctx] >> (let [x "sheep"] >> (assoc ctx :result x)))}) >> >> (def step2 >> {:name :step2 >>:error (fn [ctx ex-info] >> (println "so much for step2:" (:exception-type (ex-data >> ex-info >>:enter (fn [{:keys [result] :as ctx}] >> >> (println "time to transform" result "into a number") >> (update ctx :result #(Long/parseLong %)))}) >> >> (defn run [] >> (chain/execute {} [step1 step2])) >> >> >> -- > 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/d/optout. > -- 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/d/optout.
Re: How to try/catch Let bindings?
Hi Didier The interceptor pattern is pretty tiny, certainly small enough to copy from project to project if you wanted. You can see re-frame's implementation here: https://github.com/Day8/re-frame/blob/master/src/re_frame/interceptor.cljc which is only around 100 SLOC. That doesn't handle exceptions like Pedestal, but shows the core of the idea. On Mon, Oct 2, 2017 at 5:22 PM Didier <didi...@gmail.com> wrote: > I can't emphasize enough the utility of the interceptor chain pattern, as >> employed heavily in pedestal. >> > > Interesting... Its almost like a workflow framework, but for simpler in > code workflows. I'm reluctant to have a dependency on pedestal just for > this though. > > On Sunday, 1 October 2017 21:00:31 UTC-7, Luke Burton wrote: > >> >> On Sep 30, 2017, at 3:14 PM, Didier <did...@gmail.com> wrote: >> >> Is there another way to execute a set of complex steps which does not >> rely on let and can be try/catched in the manner I describe? >> >> >> I can't emphasize enough the utility of the interceptor chain pattern, as >> employed heavily in pedestal. >> >> I use this *everywhere* now. I have code that interleaves interceptors >> into a chain to augment them with timing information, audit logs, and more. >> I have written code that maps a subset of an interceptor chain over a >> cluster of machines, then reduces the results back down locally. Most >> importantly, they are fantastically useful when it comes time to debug a >> complex business process … you can swap interceptors in and out easily, >> isolate stateful interceptors to enable better mocking during tests, and >> more. >> >> Here's a basic application of interceptors. It's really not much code >> considering what you get. This doesn't even scratch the surface of what >> they can do. >> >> (ns interceptor.test >> (:require >> [io.pedestal.interceptor.chain :as chain])) >> >> (def step1 >> {:name :step1 >>:enter (fn [ctx] >> (let [x "sheep"] >> (assoc ctx :result x)))}) >> >> (def step2 >> {:name :step2 >>:error (fn [ctx ex-info] >> (println "so much for step2:" (:exception-type (ex-data >> ex-info >>:enter (fn [{:keys [result] :as ctx}] >> >> (println "time to transform" result "into a number") >> (update ctx :result #(Long/parseLong %)))}) >> >> (defn run [] >> (chain/execute {} [step1 step2])) >> >> >> -- > 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/d/optout. > -- 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/d/optout.
Re: How to try/catch Let bindings?
> > I can't emphasize enough the utility of the interceptor chain pattern, as > employed heavily in pedestal. > Interesting... Its almost like a workflow framework, but for simpler in code workflows. I'm reluctant to have a dependency on pedestal just for this though. On Sunday, 1 October 2017 21:00:31 UTC-7, Luke Burton wrote: > > > On Sep 30, 2017, at 3:14 PM, Didier <did...@gmail.com > > wrote: > > Is there another way to execute a set of complex steps which does not rely > on let and can be try/catched in the manner I describe? > > > I can't emphasize enough the utility of the interceptor chain pattern, as > employed heavily in pedestal. > > I use this *everywhere* now. I have code that interleaves interceptors > into a chain to augment them with timing information, audit logs, and more. > I have written code that maps a subset of an interceptor chain over a > cluster of machines, then reduces the results back down locally. Most > importantly, they are fantastically useful when it comes time to debug a > complex business process … you can swap interceptors in and out easily, > isolate stateful interceptors to enable better mocking during tests, and > more. > > Here's a basic application of interceptors. It's really not much code > considering what you get. This doesn't even scratch the surface of what > they can do. > > (ns interceptor.test > (:require > [io.pedestal.interceptor.chain :as chain])) > > (def step1 > {:name :step1 >:enter (fn [ctx] > (let [x "sheep"] > (assoc ctx :result x)))}) > > (def step2 > {:name :step2 >:error (fn [ctx ex-info] > (println "so much for step2:" (:exception-type (ex-data > ex-info >:enter (fn [{:keys [result] :as ctx}] > > (println "time to transform" result "into a number") > (update ctx :result #(Long/parseLong %)))}) > > (defn run [] > (chain/execute {} [step1 step2])) > > > -- 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/d/optout.
Re: How to try/catch Let bindings?
> On Sep 30, 2017, at 3:14 PM, Didier <didi...@gmail.com> wrote: > > Is there another way to execute a set of complex steps which does not rely on > let and can be try/catched in the manner I describe? I can't emphasize enough the utility of the interceptor chain pattern, as employed heavily in pedestal. I use this *everywhere* now. I have code that interleaves interceptors into a chain to augment them with timing information, audit logs, and more. I have written code that maps a subset of an interceptor chain over a cluster of machines, then reduces the results back down locally. Most importantly, they are fantastically useful when it comes time to debug a complex business process … you can swap interceptors in and out easily, isolate stateful interceptors to enable better mocking during tests, and more. Here's a basic application of interceptors. It's really not much code considering what you get. This doesn't even scratch the surface of what they can do. (ns interceptor.test (:require [io.pedestal.interceptor.chain :as chain])) (def step1 {:name :step1 :enter (fn [ctx] (let [x "sheep"] (assoc ctx :result x)))}) (def step2 {:name :step2 :error (fn [ctx ex-info] (println "so much for step2:" (:exception-type (ex-data ex-info :enter (fn [{:keys [result] :as ctx}] (println "time to transform" result "into a number") (update ctx :result #(Long/parseLong %)))}) (defn run [] (chain/execute {} [step1 step2])) -- 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/d/optout.
Re: How to try/catch Let bindings?
I've seen this, I was still curious if the reason I was facing the issue was that let is simply the wrong tool for my use case or not. If let is the correct tool, I would propose that clojure.core should had a try/catch where the catch is in scope of the try. I feel the reason this is contrived is accidental complexity due to limitations of Clojure. In Java, this isn't an issue, because you're variables would be mutable: Object a; Object b; Object c; try { a = doA(..); b = doB(.., a, .., .., ..); c = doC(.., .., a, .., b, ..); } catch { // The catch is in scope of a,b,c. } Which I feel I can't think of any way in Clojure to do this, which does not add accidental complexity. In that, there's nothing to the actual problem which requires say the complexity of a let inside a let, a try/catch around each steps, binding atoms, delays, promise, volatile and then setting them inside the try, etc. All these seems to me like Clojure just adds some accidental complexity to this common use case. What do others think? On Saturday, 30 September 2017 16:42:48 UTC-7, Marcus Magnusson wrote: > > I've used try-let (link below) for this, it's worked great! > > https://github.com/rufoa/try-let > -- 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/d/optout.
How to try/catch Let bindings?
I've used try-let (link below) for this, it's worked great! https://github.com/rufoa/try-let -- 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/d/optout.
How to try/catch Let bindings?
I'm curious how others handle this use case, which I feel should be pretty common. Given you have a series of business process steps, where the flow is too complex for the arrow macros, and you also like to name the step results descriptively, so you use let: (let [a (do-a ...) b (do-b . a . .) c (do-c . a . b)] (log/info "Success" {:a a :b b :c c}) c) Now, say each steps could possibly throw an exception. So you want to try/catch the let bindings: (try (let [a (do-a ...) b (do-b . a . .) c (do-c . a . b)] (log/info "Success" {:a a :b b :c c}) c) (catch Exception e (log/error "Failed" {:a a :b b :c c}) (throw e))) But, inside the catch, you need access to the let bindings a,b,c, in order to recover from the failure, or like in my example, just to log so that debugging of the issue is easier. Now the catch will not be in scope of the bindings, and this won't even compile: "Can not find symbol a,b,c in context...". What would be the idomatic thing to do here? Is there another way to execute a set of complex steps which does not rely on let and can be try/catched in the manner I describe? Or is there a way to re-write the let that satisfies my case, and remains idiomatic, and does not add accidental complexities? Thank You. -- 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/d/optout.
Re: Beginner: let with Java object
I restarted the Emacs CIDER REPL, and now it seems to work fine. Maybe I just don't understand how to use this CIDER REPL properly. On 05/26/2017 07:58 AM, Gary Trakhman wrote: > There shouldn't be a difference, I would suspect a typo in your file. > > The error 'ClassCastException java.awt.image.BufferedImage cannot be cast to > clojure.lang.IFn tutorial.core/-main (core.clj:11)' would lead me to > look for things like '(img)' where the object ends up in call position > of the s-expression. > > On Fri, May 26, 2017 at 11:54 AM Christopher Howard > <christopher.how...@qlfiles.net <mailto:christopher.how...@qlfiles.net>> > wrote: > > When I run > > tutorial.core> (let [img (new-image 32 32)] (set-pixel img 10 10 cyan) > (show img)) > > from the REPL, this returns a javax.swing.JFrame object, and displays > the frame and image as expected. However, if put the same in > > (defn -main > "Generates image." > [& args] > (let [img (new-image 32 32)] > (set-pixel img 10 10 cyan) > (show img))) > > in more core.clj, and run (-main) from the REPL, I get error > > ClassCastException java.awt.image.BufferedImage cannot be cast to > clojure.lang.IFn tutorial.core/-main (core.clj:11) > > Why the difference? > > -- > https://qlfiles.net > > -- > 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 > <mailto: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 > <mailto:clojure%2bunsubscr...@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 > <mailto:clojure%2bunsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout. > > -- > 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 > <mailto:clojure+unsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout. -- https://qlfiles.net -- 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/d/optout.
Re: Beginner: let with Java object
There shouldn't be a difference, I would suspect a typo in your file. The error 'ClassCastException java.awt.image.BufferedImage cannot be cast to clojure.lang.IFn tutorial.core/-main (core.clj:11)' would lead me to look for things like '(img)' where the object ends up in call position of the s-expression. On Fri, May 26, 2017 at 11:54 AM Christopher Howard < christopher.how...@qlfiles.net> wrote: > When I run > > tutorial.core> (let [img (new-image 32 32)] (set-pixel img 10 10 cyan) > (show img)) > > from the REPL, this returns a javax.swing.JFrame object, and displays > the frame and image as expected. However, if put the same in > > (defn -main > "Generates image." > [& args] > (let [img (new-image 32 32)] > (set-pixel img 10 10 cyan) > (show img))) > > in more core.clj, and run (-main) from the REPL, I get error > > ClassCastException java.awt.image.BufferedImage cannot be cast to > clojure.lang.IFn tutorial.core/-main (core.clj:11) > > Why the difference? > > -- > https://qlfiles.net > > -- > 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/d/optout. > -- 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/d/optout.
Beginner: let with Java object
When I run tutorial.core> (let [img (new-image 32 32)] (set-pixel img 10 10 cyan) (show img)) from the REPL, this returns a javax.swing.JFrame object, and displays the frame and image as expected. However, if put the same in (defn -main "Generates image." [& args] (let [img (new-image 32 32)] (set-pixel img 10 10 cyan) (show img))) in more core.clj, and run (-main) from the REPL, I get error ClassCastException java.awt.image.BufferedImage cannot be cast to clojure.lang.IFn tutorial.core/-main (core.clj:11) Why the difference? -- https://qlfiles.net -- 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/d/optout.
RE: Let and For Doesn't Execute - Where Is My Misunderstanding?
They are lazy -- change "for" to "doseq" From: clojure@googlegroups.com [clojure@googlegroups.com] on behalf of Kevin Kleinfelter [kleinfelter.gro...@gmail.com] Sent: 17 May 2017 19:14 To: Clojure Subject: Let and For Doesn't Execute - Where Is My Misunderstanding? I'm stumped by the behavior of the following code fragment. Can someone help me understand what's happening? This code: (println "Holding:" (:class holding)) (let [t (:class holding)] (for [x t] (println "here" x)) (for [x t] (println "there" x Produces this output: holding: {:fundname Mutual Fund 1, :value 123.45, :class [{:class sell-me, :percent 100}]} class: [{:class sell-me, :percent 100}] Holding: [{:class sell-me, :percent 100}] there {:class sell-me, :percent 100} Why doesn't the 'for' with "here" print anything? I tried wrapping the fors with a do, but the output was the same: (println "class:" (:class holding)) (let [t (:class holding)] (do (for [x t] (println "here" x)) (for [x t] (println "there" x) Thanks! -- 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<mailto:clojure+unsubscr...@googlegroups.com>. For more options, visit https://groups.google.com/d/optout. -- 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/d/optout.
Re: Let and For Doesn't Execute - Where Is My Misunderstanding?
On 17 May 2017, at 19:14, Kevin Kleinfelter <kleinfelter.gro...@gmail.com> wrote: > I'm stumped by the behavior of the following code fragment. Can someone help > me understand what's happening? > > This code: > (println "Holding:" (:class holding)) > (let [t (:class holding)] > (for [x t] (println "here" x)) > (for [x t] (println "there" x > > Produces this output: > holding: {:fundname Mutual Fund 1, :value 123.45, :class [{:class sell-me, > :percent 100}]} > class: [{:class sell-me, :percent 100}] > Holding: [{:class sell-me, :percent 100}] > there {:class sell-me, :percent 100} > > Why doesn't the 'for' with "here" print anything? for produces a lazy seq so it does nothing unless you call it. The value of a let in Clojure with more than one subexpression after the binding is the value of the value of the last subexpression. So in your let, the second for is evaluated because it is called to provide the return value of the let. The first expression isn't evaluated because it isn’t part of the return value so it isn’t called. > I tried wrapping the fors with a do, but the output was the same: > (println "class:" (:class holding)) > (let [t (:class holding)] > (do > (for [x t] (println "here" x)) > (for [x t] (println "there" x) The documentation for do https://clojuredocs.org/clojure.core/do explains that do evaluates the expressions in order and returns the last. Your last expression is evaluated because it is returned. The first expression is not returned, so it isn’t being used and isn’t evaluated. One way of evaluating both would be to write: (let [t (:class holding)] (doseq [a (for [x t] (println "here" x)) b (for [x t] (println "there" x))] [a b])) https://clojuredocs.org/clojure.core/doseq This has a return value of nil and prints both “here” and “there”. You could also just use a let: (let [t (:class holding) a (for [x t] (println "here" x)) b (for [x t] (println "there" x))] [a b]) This prints both “here” and “there” and has a return value of a vector with two seqs of nils. If you don’t want the return value, the doseq is the right way to go. If you do want a return value use a let. Alan -- 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/d/optout.
Re: Let and For Doesn't Execute - Where Is My Misunderstanding?
Kevin Kleinfelter <kleinfelter.gro...@gmail.com> writes: > I'm stumped by the behavior of the following code fragment. Can someone > help me understand what's happening? > > *This code*: > (println "Holding:" (:class holding)) > (let [t (:class holding)] > (for [x t] (println "here" x)) > (for [x t] (println "there" x > > *Produces this output*: > holding: {:fundname Mutual Fund 1, :value 123.45, :class [{:class sell-me, > :percent 100}]} > class: [{:class sell-me, :percent 100}] > Holding: [{:class sell-me, :percent 100}] > there {:class sell-me, :percent 100} > > Why doesn't the 'for' with "here" print anything? 'for' is lazy. the result isn't realized anywhere. the second 'for' is realized because you print the result in the REPL (at least that is what I assume). try (doseq [x t] ...) -- Cheers, Ralf -- 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/d/optout.
Let and For Doesn't Execute - Where Is My Misunderstanding?
I'm stumped by the behavior of the following code fragment. Can someone help me understand what's happening? *This code*: (println "Holding:" (:class holding)) (let [t (:class holding)] (for [x t] (println "here" x)) (for [x t] (println "there" x *Produces this output*: holding: {:fundname Mutual Fund 1, :value 123.45, :class [{:class sell-me, :percent 100}]} class: [{:class sell-me, :percent 100}] Holding: [{:class sell-me, :percent 100}] there {:class sell-me, :percent 100} Why doesn't the 'for' with "here" print anything? I tried wrapping the fors with a do, but the output was the same: (println "class:" (:class holding)) (let [t (:class holding)] (do (for [x t] (println "here" x)) (for [x t] (println "there" x) Thanks! -- 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/d/optout.
Re: loop macro generates a wrapping let
Right, of course! It seems almost obvious now :P Thanks Kevin On Tuesday, March 7, 2017 at 12:42:08 AM UTC+1, red...@gmail.com wrote: > > On 03/06/2017 03:28 PM, juan.facorro wrote: > > While I was debugging some code I found something related to the *loop > > *macro that I found curious. I'm probably missing something but here it > > goes. > > > > The expression generated by the *loop* macro includes a wrapping *let > > *when there is any de-structuring in the bindings. > > > > (require '[clojure.walk :as walk]) > > (walk/macroexpand-all '(loop [[x & xs] xs a 3])) > > The init value of `a` could rely on `x` or `xs`, so those bindings need > to be established before the loop, which is what the outer loop does. > For example checkout `(walk/macroexpand-all '(loop [[x & xs] xs a x]))`. > > > > > Which returns: > > > > > > (let*[G__1249xsvec__1250G__1249x(clojure.core/nthvec__12500nil) > > xs(clojure.core/nthnextvec__12501) a3] (loop*[G__1249G__1249a a] > > (let*[vec__1251G__1249x(clojure.core/nthvec__12510nil) > > xs(clojure.core/nthnextvec__12511) aa]))) > > > > > > Since all bindings get re-defined in the inner *let*, why is the outer > > *let* even generated? Is there a reason for not having the following > > generated instead? > > > > > > (loop* [G__1249 xs a a] > > (let* [vec__1251 G__1249 > > x (clojure.core/nth vec__1251 0 nil) > > xs (clojure.core/nthnext vec__1251 1) > > a a])) > > > > > > The change in the loop macro is pretty simple and it seems to work (at > > least with the tests available in GitHub's clojure/clojure). > > > > > > (defmacro loop > > "Evaluates the exprs in a lexical context in which the symbols in > > the binding-forms are bound to their respective init-exprs or parts > > therein. Acts as a recur target." > > {:added "1.0", :special-form true, :forms '[(loop [bindings*] > exprs*)]} > > [bindings & body] > > (assert-args > > (vector? bindings) "a vector for its binding" > > (even? (count bindings)) "an even number of forms in binding > vector") > > (let [db (destructure bindings)] > > (if (= db bindings) > > `(loop* ~bindings ~@body) > > (let [vs (take-nth 2 (drop 1 bindings)) > > bs (take-nth 2 bindings) > > gs (map (fn [b] (if (symbol? b) b (gensym))) bs)] > > `(loop* ~(vec (interleave gs vs)) > > (let ~(vec (interleave bs gs)) > > ~@body)) > > > > > > But maybe this hasn't been changed because of the importance of the > > *loop* macro, or maybe the impact in compile- and run-time is > > insignificant to justify the change. > > > > Anyways... I thought I'd put the question out there. > > > > > > Cheers! > > > > Juan > > > > > > -- > > 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+u...@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+u...@googlegroups.com > > <mailto:clojure+u...@googlegroups.com >. > > For more options, visit https://groups.google.com/d/optout. > > > -- > And what is good, Phaedrus, > And what is not good— > Need we ask anyone to tell us these things? > -- 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/d/optout.
Re: loop macro generates a wrapping let
On 03/06/2017 03:28 PM, juan.facorro wrote: > While I was debugging some code I found something related to the *loop > *macro that I found curious. I'm probably missing something but here it > goes. > > The expression generated by the *loop* macro includes a wrapping *let > *when there is any de-structuring in the bindings. > > (require '[clojure.walk :as walk]) > (walk/macroexpand-all '(loop [[x & xs] xs a 3])) The init value of `a` could rely on `x` or `xs`, so those bindings need to be established before the loop, which is what the outer loop does. For example checkout `(walk/macroexpand-all '(loop [[x & xs] xs a x]))`. > > Which returns: > > > (let*[G__1249xsvec__1250G__1249x(clojure.core/nthvec__12500nil) > xs(clojure.core/nthnextvec__12501) a3] (loop*[G__1249G__1249a a] > (let*[vec__1251G__1249x(clojure.core/nthvec__12510nil) > xs(clojure.core/nthnextvec__12511) aa]))) > > > Since all bindings get re-defined in the inner *let*, why is the outer > *let* even generated? Is there a reason for not having the following > generated instead? > > > (loop* [G__1249 xs a a] > (let* [vec__1251 G__1249 > x (clojure.core/nth vec__1251 0 nil) > xs (clojure.core/nthnext vec__1251 1) > a a])) > > > The change in the loop macro is pretty simple and it seems to work (at > least with the tests available in GitHub's clojure/clojure). > > > (defmacro loop > "Evaluates the exprs in a lexical context in which the symbols in > the binding-forms are bound to their respective init-exprs or parts > therein. Acts as a recur target." > {:added "1.0", :special-form true, :forms '[(loop [bindings*] exprs*)]} > [bindings & body] > (assert-args > (vector? bindings) "a vector for its binding" > (even? (count bindings)) "an even number of forms in binding vector") > (let [db (destructure bindings)] > (if (= db bindings) > `(loop* ~bindings ~@body) > (let [vs (take-nth 2 (drop 1 bindings)) > bs (take-nth 2 bindings) > gs (map (fn [b] (if (symbol? b) b (gensym))) bs)] > `(loop* ~(vec (interleave gs vs)) > (let ~(vec (interleave bs gs)) > ~@body)) > > > But maybe this hasn't been changed because of the importance of the > *loop* macro, or maybe the impact in compile- and run-time is > insignificant to justify the change. > > Anyways... I thought I'd put the question out there. > > > Cheers! > > Juan > > > -- > 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 > <mailto:clojure+unsubscr...@googlegroups.com>. > For more options, visit https://groups.google.com/d/optout. -- And what is good, Phaedrus, And what is not good— Need we ask anyone to tell us these things? -- 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/d/optout.
loop macro generates a wrapping let
While I was debugging some code I found something related to the *loop *macro that I found curious. I'm probably missing something but here it goes. The expression generated by the *loop* macro includes a wrapping *let *when there is any de-structuring in the bindings. (require '[clojure.walk :as walk]) (walk/macroexpand-all '(loop [[x & xs] xs a 3])) Which returns: (let* [G__1249 xs vec__1250 G__1249 x (clojure.core/nth vec__1250 0 nil) xs (clojure.core/nthnext vec__1250 1) a 3] (loop* [G__1249 G__1249 a a] (let* [vec__1251 G__1249 x (clojure.core/nth vec__1251 0 nil) xs (clojure.core/nthnext vec__1251 1) a a]))) Since all bindings get re-defined in the inner *let*, why is the outer *let* even generated? Is there a reason for not having the following generated instead? (loop* [G__1249 xs a a] (let* [vec__1251 G__1249 x (clojure.core/nth vec__1251 0 nil) xs (clojure.core/nthnext vec__1251 1) a a])) The change in the loop macro is pretty simple and it seems to work (at least with the tests available in GitHub's clojure/clojure). (defmacro loop "Evaluates the exprs in a lexical context in which the symbols in the binding-forms are bound to their respective init-exprs or parts therein. Acts as a recur target." {:added "1.0", :special-form true, :forms '[(loop [bindings*] exprs*)]} [bindings & body] (assert-args (vector? bindings) "a vector for its binding" (even? (count bindings)) "an even number of forms in binding vector") (let [db (destructure bindings)] (if (= db bindings) `(loop* ~bindings ~@body) (let [vs (take-nth 2 (drop 1 bindings)) bs (take-nth 2 bindings) gs (map (fn [b] (if (symbol? b) b (gensym))) bs)] `(loop* ~(vec (interleave gs vs)) (let ~(vec (interleave bs gs)) ~@body)) But maybe this hasn't been changed because of the importance of the *loop* macro, or maybe the impact in compile- and run-time is insignificant to justify the change. Anyways... I thought I'd put the question out there. Cheers! Juan -- 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/d/optout.
Re: recursive bindings not available in let form?
Let bindings map pretty much directly to Java style local variables: (let [x 42] (let [x 3] (+ x 3)) Becomes something like this when compiled to byte code: x_1 = 42 x_2 = 3 return x_2 +3 So let bindings with the same names are kept separate via modifying the stored name in the byte code, and these local variables are never overwritten except via a loop. Let bindings in Clojure are not "reified" (not something you can reference), they are simply names for calculated values. Contrast this with a var. Vars however are reified. You can look at a var in Clojure: (def foo 42) #'foo => (deref #'foo) => 42 The #' reader macro says "get me the var with this name, but don't call deref on it; I want the actual var". That's not something you can do with let bindings since they are not a first class object in the language. Timothy On Sat, Dec 3, 2016 at 10:06 PM, Paul Gowder <paul.gow...@gmail.com> wrote: > That's a really neat post. Thank you for writing it! > > How do bindings created by let fit into that picture? > > The question of how vars work comes up enough that I recently wrote a blog > post on the subject. Maybe it will be useful to you. > http://blog.cognitect.com/blog/2016/9/15/works-on-my- > machine-understanding-var-bindings-and-roots > > -- > 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/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) -- 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/d/optout.
Re: recursive bindings not available in let form?
That's a really neat post. Thank you for writing it! How do bindings created by let fit into that picture? > The question of how vars work comes up enough that I recently wrote a blog > post on the subject. Maybe it will be useful to you. > http://blog.cognitect.com/blog/2016/9/15/works-on-my-machine-understanding-var-bindings-and-roots > -- 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/d/optout.
Re: recursive bindings not available in let form?
The question of how vars work comes up enough that I recently wrote a blog post on the subject. Maybe it will be useful to you. http://blog.cognitect.com/blog/2016/9/15/works-on-my-machine-understanding-var-bindings-and-roots Timothy On Fri, Dec 2, 2016 at 2:44 PM Paul Gowder <paul.gow...@gmail.com> wrote: > Thanks Bobby, Francis, Walter! Now trying to wrap my head around the idea > of def as a ref... > > On Friday, December 2, 2016 at 2:57:13 PM UTC-6, Francis Avila wrote: > > Let bindings are immutable bindings, not refs. They must act as if their > value could be substituted at the moment they are referenced. Def (i.e. a > ref) is a mutable container whose contents is examined when it is used (not > when referenced), which is why your second example works. > > > Why doesn't let work how you expect? Well, how would the following code > work if let worked as you intend? > > (let [a 1 > a (+ a 2)] > (= a 3)) > > However, fn accepts an optional name binding, so you can do this: > > (let [fib (fn fib [...] (fib ...))] fib) > > The inner fib reference is bound by the fn form, but the outer fib > reference is still bound by let. > > Or you can use letfn instead of let, which is the same as above with less > typing AND the bindings can all see one another simultaneously. It's best > for groups of closed-over but mutually recursive functions. > > (letfn [(fib [...] (fib ...))] (fib ...)) > > -- > 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/d/optout. > -- 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/d/optout.
Re: recursive bindings not available in let form?
Your "y" could also be "fib". You are permitted to use the same name inside the fn. On Fri, Dec 2, 2016 at 12:59 PM, Walter van der Laan < waltervanderl...@gmail.com> wrote: > AFAIK there are two options. > > You can add a symbol after fn: > > (let [fib (fn y [x] > (cond > (< x 2) x > :else (+ (y (- x 2)) (y (- x 1)] > (fib 5)) > > > -- 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/d/optout.
Re: recursive bindings not available in let form?
Thanks Bobby, Francis, Walter! Now trying to wrap my head around the idea of def as a ref... On Friday, December 2, 2016 at 2:57:13 PM UTC-6, Francis Avila wrote: > > Let bindings are immutable bindings, not refs. They must act as if their > value could be substituted at the moment they are referenced. Def (i.e. a > ref) is a mutable container whose contents is examined when it is used (not > when referenced), which is why your second example works. > > > Why doesn't let work how you expect? Well, how would the following code > work if let worked as you intend? > > (let [a 1 > a (+ a 2)] > (= a 3)) > > However, fn accepts an optional name binding, so you can do this: > > (let [fib (fn fib [...] (fib ...))] fib) > > The inner fib reference is bound by the fn form, but the outer fib > reference is still bound by let. > > Or you can use letfn instead of let, which is the same as above with less > typing AND the bindings can all see one another simultaneously. It's best > for groups of closed-over but mutually recursive functions. > > (letfn [(fib [...] (fib ...))] (fib ...)) > > -- 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/d/optout.
Re: recursive bindings not available in let form?
AFAIK there are two options. You can add a symbol after fn: (let [fib (fn y [x] (cond (< x 2) x :else (+ (y (- x 2)) (y (- x 1)] (fib 5)) Or, as Bobby already suggested, you can use letfn: (letfn [(fib [x] (cond (< x 2) x :else (+ (fib (- x 2)) (fib (- x 1)] (fib 5)) -- 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/d/optout.
recursive bindings not available in let form?
Let bindings are immutable bindings, not refs. They must act as if their value could be substituted at the moment they are referenced. Def (i.e. a ref) is a mutable container whose contents is examined when it is used (not when referenced), which is why your second example works. Why doesn't let work how you expect? Well, how would the following code work if let worked as you intend? (let [a 1 a (+ a 2)] (= a 3)) However, fn accepts an optional name binding, so you can do this: (let [fib (fn fib [...] (fib ...))] fib) The inner fib reference is bound by the fn form, but the outer fib reference is still bound by let. Or you can use letfn instead of let, which is the same as above with less typing AND the bindings can all see one another simultaneously. It's best for groups of closed-over but mutually recursive functions. (letfn [(fib [...] (fib ...))] (fib ...)) -- 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/d/optout.
Re: recursive bindings not available in let form?
Note that letfn does allow recursive bindings, though I couldn't comment as to the implementation details. On Friday, December 2, 2016 at 3:01:13 PM UTC-5, Paul Gowder wrote: > > Hi clojure-world, > > I think maybe this is actually related to the complexities of binding > referenced in the previous thread ( > https://groups.google.com/forum/?utm_source=digest_medium=email#!topic/clojure/zBXsrqTN2xs)... > > maybe? But it would be amazing if some wise person would help explain... > > So for obscure reasons, I found myself trying to use a naive recursive > fibonacci function interactively. So naturally, the first thing my fingers > went to was: > > (let [fib (fn [x] > (cond > (< x 2) x > :else (+ (fib (- x 2)) (fib (- x 1)] > (fib 5)) > > which threw an unable to resolve symbol error because it couldn't resolve > the recursive calls to fib inside the let binding. > > But swap out the let for a def and it works just fine: > > (def fib (fn [x] > (cond > (< x 2) x > :else (+ (fib (- x 2)) (fib (- x 1)) > (fib 5) > > Can someone clarify for me what's going on here? Why can a def binding > get access to its own name in the body of a function, but not a let binding? > > thanks! > > -Paul > -- 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/d/optout.
recursive bindings not available in let form?
Hi clojure-world, I think maybe this is actually related to the complexities of binding referenced in the previous thread (https://groups.google.com/forum/?utm_source=digest_medium=email#!topic/clojure/zBXsrqTN2xs)... maybe? But it would be amazing if some wise person would help explain... So for obscure reasons, I found myself trying to use a naive recursive fibonacci function interactively. So naturally, the first thing my fingers went to was: (let [fib (fn [x] (cond (< x 2) x :else (+ (fib (- x 2)) (fib (- x 1)] (fib 5)) which threw an unable to resolve symbol error because it couldn't resolve the recursive calls to fib inside the let binding. But swap out the let for a def and it works just fine: (def fib (fn [x] (cond (< x 2) x :else (+ (fib (- x 2)) (fib (- x 1)) (fib 5) Can someone clarify for me what's going on here? Why can a def binding get access to its own name in the body of a function, but not a let binding? thanks! -Paul -- 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/d/optout.
Re: def partial vs let partial
It's because the value of the + is captured when the partial is created (or when the var is implicitly derefed). The value of the var is implicitly captured (via deref) at the point where it appears in the form. It's a bit of a complex topic, but this blog post I wrote a few months ago may help a bit: http://blog.cognitect.com/blog/2016/9/15/works-on-my-machine-understanding-var-bindings-and-roots On Thu, Dec 1, 2016 at 1:30 PM, Matthew Hamrick <matthewjhamr...@gmail.com> wrote: > I'm confused by the following code. > Could someone explain to me why the def-ed partial has different behavior > to the letted one? > This is especially confusing to me since the #() special form one works as > I expect. > > (def sum-partial-def (partial reduce +)) > > (let [sum-partial (partial reduce +) > sum-# #(reduce + %1) > nums [1 2 3 4]] > [(sum-partial-def nums) >(reduce + nums) >(sum-# nums) >(sum-partial nums)]) ;; => [10 10 10 10] > > (with-redefs [+ (fn [a b] > (.add (.add (BigInteger. (str a)) > (BigInteger. (str b))) > (BigInteger/ONE)))] > (let [sum-partial (partial reduce +) > sum-# #(reduce + %1) > nums [1 2 3 4]] > [(sum-partial-def nums) > (reduce + nums) > (sum-# nums) > (sum-partial nums)])) ;; => [10 13 13 13] > > Thanks, > Matt > > -- > 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/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) -- 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/d/optout.
Re: def partial vs let partial
Sum-partial-def gets the original + definition because it is evaluated first, if you want late binding, try (partial reduce (var +)). On Dec 1, 2016 4:05 PM, "Matthew Hamrick" <matthewjhamr...@gmail.com> wrote: > I'm confused by the following code. > Could someone explain to me why the def-ed partial has different behavior > to the letted one? > This is especially confusing to me since the #() special form one works as > I expect. > > (def sum-partial-def (partial reduce +)) > > (let [sum-partial (partial reduce +) > sum-# #(reduce + %1) > nums [1 2 3 4]] > [(sum-partial-def nums) >(reduce + nums) >(sum-# nums) >(sum-partial nums)]) ;; => [10 10 10 10] > > (with-redefs [+ (fn [a b] > (.add (.add (BigInteger. (str a)) > (BigInteger. (str b))) > (BigInteger/ONE)))] > (let [sum-partial (partial reduce +) > sum-# #(reduce + %1) > nums [1 2 3 4]] > [(sum-partial-def nums) > (reduce + nums) > (sum-# nums) > (sum-partial nums)])) ;; => [10 13 13 13] > > Thanks, > Matt > > -- > 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/d/optout. > -- 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/d/optout.
def partial vs let partial
I'm confused by the following code. Could someone explain to me why the def-ed partial has different behavior to the letted one? This is especially confusing to me since the #() special form one works as I expect. (def sum-partial-def (partial reduce +)) (let [sum-partial (partial reduce +) sum-# #(reduce + %1) nums [1 2 3 4]] [(sum-partial-def nums) (reduce + nums) (sum-# nums) (sum-partial nums)]) ;; => [10 10 10 10] (with-redefs [+ (fn [a b] (.add (.add (BigInteger. (str a)) (BigInteger. (str b))) (BigInteger/ONE)))] (let [sum-partial (partial reduce +) sum-# #(reduce + %1) nums [1 2 3 4]] [(sum-partial-def nums) (reduce + nums) (sum-# nums) (sum-partial nums)])) ;; => [10 13 13 13] Thanks, Matt -- 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/d/optout.
Re: if-let/when-let
Here is the if-let*: (defmacro if-let* ([bindings then] `(if-let* ~bindings ~then nil)) ([bindings then else] (if (seq bindings) `(if-let [~(first bindings) ~(second bindings)] (if-let* ~(drop 2 bindings) ~then ~else) ~(if-not (second bindings) else)) then))) And when-let*: (defmacro when-let* ([bindings & body] (if (seq bindings) `(when-let [~(first bindings) ~(second bindings)] (when-let* ~(drop 2 bindings) ~@body)) `(do ~@body -- 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/d/optout.
if-let and friends with multiple bindings
If you have ever wished if-let and friends would allow multiple bindings wish no more. Check out... https://github.com/LockedOn/if-let -Karl -- 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/d/optout.
An elegant implementation of if-all-let
(defmacro if-all-let [bindings then else] (reduce (fn [subform binding] `(if-let [~@binding] ~subform ~else)) then (reverse (partition 2 bindings I quoted the function from p259 of Chas Emerick, Brian Carper, Christophe Grand-Clojure Programming-O'Reilly Media (2012) Why doesn't clojure.core adopt this? -- 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/d/optout.
Re: An elegant implementation of if-all-let
Disclaimer: I do not make decisions on what gets into clojure.core. Here is a page that gives some reasons why most things don't get into clojure.core: http://dev.clojure.org/display/design/Why+Feature+X+Was+Declined More specifically on if-all-let and things like it, many people seem to disagree on what they think is the most natural behavior for a variant of if-let with multiple bindings -- whether it should be 'and' or 'or' behavior, for example. Obviously that doesn't preclude a well-defined alternative from being adopted, hence the page above is probably a more accurate answer. Andy On Sat, Jul 11, 2015 at 6:36 AM, crocket crockabisc...@gmail.com wrote: (defmacro if-all-let [bindings then else] (reduce (fn [subform binding] `(if-let [~@binding] ~subform ~else)) then (reverse (partition 2 bindings I quoted the function from p259 of Chas Emerick, Brian Carper, Christophe Grand-Clojure Programming-O'Reilly Media (2012) Why doesn't clojure.core adopt this? -- 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/d/optout. -- 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/d/optout.
Re: let vs. let*
Hi, I fear that I have to excuse me for triggering a debate about principles of behavior patterns on this list. Of course, I tried to answer my question myself using Google. Perhaps I made a mistake on the selection of the right search pattern so I didn't find satisfactory results. The lmgtfy link posted by raould was helpful. Johannes On Thursday, June 25, 2015 at 3:22:02 PM UTC+2, Alex Miller wrote: raould, I find lmgtfy links to be a condescending way to answer a question and I would prefer that we not use them on this list. If you have an answer or a link to one, then respond with this, otherwise I do not see a reason to post this. Thanks, Alex On Thursday, June 18, 2015 at 3:35:53 PM UTC-5, raould wrote: http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout.
Re: let vs. let*
My apologies (sincerely). Won't use that again. -- 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/d/optout.
Re: let vs. let*
raould, I find lmgtfy links to be a condescending way to answer a question and I would prefer that we not use them on this list. If you have an answer or a link to one, then respond with this, otherwise I do not see a reason to post this. Thanks, Alex On Thursday, June 18, 2015 at 3:35:53 PM UTC-5, raould wrote: http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout.
Re: let vs. let*
I had to query it myself not knowing what this site was all about, nice tutorial, I think I understood it :) Luc P. raould, I find lmgtfy links to be a condescending way to answer a question and I would prefer that we not use them on this list. If you have an answer or a link to one, then respond with this, otherwise I do not see a reason to post this. Thanks, Alex On Thursday, June 18, 2015 at 3:35:53 PM UTC-5, raould wrote: http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout. -- Luc Préfontainelprefonta...@softaddicts.ca sent by ibisMail! -- 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/d/optout.
Re: let vs. let*
I don't think this is a let me google that for you question. Let vs let* in Clojure is not at all the same as the popular usages of these forms in popular lisp dialects like Common Lisp. I've thought it was confusing why let* existed in Clojure since let binding is only done in a sequential manner, but I think some answers given here are helpful. Just to point out Clojure dynamic var binding is done in a parallel/unordered way which resembles how Common Lisp let was done. However this is a completely different function and not a special form. Just for comparison with CL. -- 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/d/optout.
Re: let vs. let*
In common lisp, 'let' didn't evaluate it's bindings in any guaranteed order (well, it is specified as being evaluated in parallel), however, 'let*' evaluated it's bindings in order from left to right. This enabled you to use the sequentially previous bindings in the evaluation of later bindings in the same 'let*' init argument, (let* ((eval1 value) (eval2 (+ 1 eval1))) body_form). Clojure seems to have implemented 'let*' and as already mentioned put a wrapper around it so we could have the word 'let' :) On Thursday, June 18, 2015 at 3:29:55 PM UTC-5, Johannes wrote: Hi! I cannot figure out, what the difference between let and let* is. Can anyone enlighten me? Johannes -- 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/d/optout.
Re: let vs. let*
On Thursday, June 18, 2015 at 4:29:55 PM UTC-4, Johannes wrote: Hi! I cannot figure out, what the difference between let and let* is. Can anyone enlighten me? Let is a macro that wraps let* and adds destructuring. There's a similar relationship between fn and fn*, letfn and letfn*, and loop and loop*. The starred forms are true special forms that are directly meaningful to the compiler (with effects such as shadowing even local names when in operator position). -- 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/d/optout.
let vs. let*
Hi! I cannot figure out, what the difference between let and let* is. Can anyone enlighten me? Johannes -- 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/d/optout.
Re: let vs. let*
http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout.
Re: let vs. let*
thanks Am Donnerstag, 18. Juni 2015 22:35:53 UTC+2 schrieb raould: http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout.
Re: let vs. let*
Basically you the user should not worry about the starred versions On Thu, Jun 18, 2015 at 1:40 PM Johannes bra...@nordakademie.de wrote: thanks Am Donnerstag, 18. Juni 2015 22:35:53 UTC+2 schrieb raould: http://lmgtfy.com/?q=clojure+%22let+vs.+let*%22 -- 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/d/optout. -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
I'll chime in with my opinion on this topic. I think the existing if-let and similar forms that have a limitation of only allowing a single binding is a confusing restriction to place on the familiar binding vector construct. I've always been a little uneasy about repurposing binding vectors for this restricted single-binding use case. I'd probably have preferred something more like as-, where there is a direct form binding pair. However I guess that would ruin the ability to destructure. Just a thought, I can live with if-let and it's slightly awkward binding vector though. With that said, and as others have mentioned here, I can't imagine this proposed if-let-all macro having clear enough semantics to be something in Clojure core. There are just way too many caveats and ways to interpret it. I can see the motivation for it, but maybe there is a better design to achieve it. -- 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/d/optout.
Re: I created a new macro if-let-all
Where does if-let-all serve people best? Can anyone help me find the right clojure project to contribute to? On Friday, June 5, 2015 at 2:44:22 PM UTC+9, crocket wrote: The macro below is called if-let-all. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) You can use it as (if-let-all [a 2 b 3] (+ a b) oh no!!). false-case doesn't have access to local bindings. -- 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/d/optout.
Where should 'if-let-all' macro go?
It evaluates true-case only if every local binding evaluates to true values. false-case has no access to local bindings. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) I think this macro could benefit people if I found the right project where it should reside. Can anyone help me find the right project for if-let-all? -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
There are several 'utility' libraries for Clojure that may have something like this already, or their authors might be willing to add such a thing: https://github.com/Prismatic/plumbing https://github.com/amalloy/useful Andy On Tue, Jun 9, 2015 at 5:00 AM, crocket crockabisc...@gmail.com wrote: It evaluates true-case only if every local binding evaluates to true values. false-case has no access to local bindings. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) I think this macro could benefit people if I found the right project where it should reside. Can anyone help me find the right project for if-let-all? -- 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/d/optout. -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
Dunaj has support for multiple bindings in if-let since version 0.5. http://www.dunaj.org/dunaj.flow.api.html#if_let Related design page that discusses possible approaches is at https://github.com/dunaj-project/dunaj/wiki/Conditionals Jozef On Tuesday, June 9, 2015 at 4:00:35 PM UTC+2, Lars Andersen wrote: I actually wish this was how the if-let macro in core worked. Once in a blue moon I end up writing nested if-let statements or an if-let with a nested let. Both of these cases look so ridiculous I often re-write the the code just avoid it. On Tuesday, June 9, 2015 at 2:00:53 PM UTC+2, crocket wrote: It evaluates true-case only if every local binding evaluates to true values. false-case has no access to local bindings. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) I think this macro could benefit people if I found the right project where it should reside. Can anyone help me find the right project for if-let-all? -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
At least based on my uses, I agree that this would likely bring the most use of the now unused binding space in cores if-let. I can't think of any useful alternatives. Syntactically though, one could worry that the additional bindings would be read as regular let bindings and worry about the language clarity. I don't have the distance of a naive Clojure reader to position myself there. I remember, that when I started learning Clojure, I thought that I could just use the vector for additional regular let bindings. I think that I read the doc string first which would explain why I expected conditional evaluation only for the first binding. The other problem is that design wise, it opens up the possibility to abuse the vector for regular let bindings, a la These exprs are going to evaluate to logical truth anyways, as long as I have other things to worry about, they will get their own let later. Clojures design often helps writing clean code and this limitation could be seen as (very small) part of that. I must also say that I have rarely used or seen more than two nested if-lets. In such a case one should usually consider refactoring. On Wednesday, June 10, 2015 at 12:23:40 AM UTC+2, Fluid Dynamics wrote: There's a variant of this in one of my projects as well. If this is in several utility libraries *and* half the world keeps Greenspunning versions of it in their own projects, then it might be something that belongs in core ... -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
There's a variant of this in one of my projects as well. If this is in several utility libraries *and* half the world keeps Greenspunning versions of it in their own projects, then it might be something that belongs in core ... -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
On Jun 9, 2015, at 3:51 PM, Leon Grapenthin grapenthinl...@gmail.com wrote: Syntactically though, one could worry that the additional bindings would be read as regular let bindings and worry about the language clarity. One of the main points that I seem to recall from previous discussions has been around the actual behavior of this sort of code (if it was allowed): (if-let [a (some-a-fn) b (some-b-fn) c (some-c-fn)] (some-t-fn) (some-f-fn)) Should it short-circuit as soon as one of `a`, `b`, or `c` is falsey? Should it evaluate all three and require all three to be truthy? Should it evaluate all three and base the test on just the last one (a reasonable alternative semantic)? If `a` is truthy and `b` is falsey, why shouldn’t `a` be available in the false arm of the `if`? And, related, should the `b` and `c` expressions have access to the (truthy) values of `a`? There are arguments in favor of (and against) each position and thus no clear consensus on what to choose. Sean Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
I actually wish this was how the if-let macro in core worked. Once in a blue moon I end up writing nested if-let statements or an if-let with a nested let. Both of these cases look so ridiculous I often re-write the the code just avoid it. On Tuesday, June 9, 2015 at 2:00:53 PM UTC+2, crocket wrote: It evaluates true-case only if every local binding evaluates to true values. false-case has no access to local bindings. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) I think this macro could benefit people if I found the right project where it should reside. Can anyone help me find the right project for if-let-all? -- 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/d/optout.
Re: Where should 'if-let-all' macro go?
this if-let-all do not support destructure, I writed a improved https://gist.github.com/gfZeng/8e8e18f148d5742b064c On Tuesday, June 9, 2015 at 8:00:53 PM UTC+8, crocket wrote: It evaluates true-case only if every local binding evaluates to true values. false-case has no access to local bindings. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) I think this macro could benefit people if I found the right project where it should reside. Can anyone help me find the right project for if-let-all? -- 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/d/optout.
Re: I created a new macro if-let-all
Yes, if-and-let is similar to if-let-all. On Friday, June 5, 2015 at 10:47:24 PM UTC+9, Fluid Dynamics wrote: On Friday, June 5, 2015 at 1:53:07 AM UTC-4, crocket wrote: Ouch, I didn't write. Gary Fredericks wrote it. I simply modified his if-let-all macro a little bit. On Friday, June 5, 2015 at 2:44:22 PM UTC+9, crocket wrote: The macro below is called if-let-all. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) You can use it as (if-let-all [a 2 b 3] (+ a b) oh no!!). false-case doesn't have access to local bindings. Didn't I post something with a similar purpose a while back, called if-and-let? That one had some trickiness to avoid unexpectedly shadowing things unpredictably in false-case, as I recall. -- 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/d/optout.
Re: I created a new macro if-let-all
On Friday, June 5, 2015 at 1:53:07 AM UTC-4, crocket wrote: Ouch, I didn't write. Gary Fredericks wrote it. I simply modified his if-let-all macro a little bit. On Friday, June 5, 2015 at 2:44:22 PM UTC+9, crocket wrote: The macro below is called if-let-all. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) You can use it as (if-let-all [a 2 b 3] (+ a b) oh no!!). false-case doesn't have access to local bindings. Didn't I post something with a similar purpose a while back, called if-and-let? That one had some trickiness to avoid unexpectedly shadowing things unpredictably in false-case, as I recall. -- 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/d/optout.
I created a new macro if-let-all
The macro below is called if-let-all. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) You can use it as (if-let-all [a 2 b 3] (+ a b) oh no!!). false-case doesn't have access to local bindings. -- 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/d/optout.
Re: I created a new macro if-let-all
Ouch, I didn't write. Gary Fredericks wrote it. I simply modified his if-let-all macro a little bit. On Friday, June 5, 2015 at 2:44:22 PM UTC+9, crocket wrote: The macro below is called if-let-all. (defmacro if-let-all if-let-all evaluates every local binding sequentially and evaluates true-case only if every local binding is a truthy value. true-case has access to all local bindings, but false-case doesn't have access to local bindings. [bindings true-case false-case] (let [pairs (partition 2 bindings) names (mapv first pairs) exprs (map second pairs) exprs-in-if-let (fn self [[name1 more-names] [expr1 more-exprs]] `(if-let [~name1 ~expr1] ~(if more-names (self more-names more-exprs) names))) things (exprs-in-if-let names exprs)] `(if-let [~names ~things] ~true-case ~false-case))) You can use it as (if-let-all [a 2 b 3] (+ a b) oh no!!). false-case doesn't have access to local bindings. -- 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/d/optout.
Re: Let bindings and immutability
Think about values first, symbols after. Symbols are accessory, not values, values are the only things that exist at runtime. Symbols are only there for you poor human (I include myself in this statement) to grasp roughly what is going on by tracking intermediate values with names. The names you choose are irrelevant except for your own comprehension. There are no containers per se that you can alter transparently. Some special constructs (atoms, ...) allow you to persist other values, obviously you need to name these constructs but they are not symbols, they are a special kind of value. Your code will need the value they persist, not the construct itself. (swap! is of limited interest if you never refer to the atom value). Top level vars are like the universe of values where your code will operate, a frame. Once set vars do not change. (Ok, some may use alter root but it should be reserved to specific occasions). It's all about values. This is the semantic shift compared to most languages. I do not even think about the underlying objects supporting values in Clojure unless I need to (extending with protocols, type hints, weird stack traces, ...). Implementation details :) As for interop, you enter the mutable world and the familiar rules apply here. The above 'cosmology' sums up how I think when I dive into some Clojure code and it works 99.5% of the time. There's no confusion. Luc P. On 12/02/2015 01:53, Ben Wolfson wrote: The multiple-binding form of let can be recursively transformed into nested lets: (let [name1 value1 name2 value2 ... name value] body) (let [name1 value1] (let [name2 value2] ... (let [name value] body))) All you're doing with your let form is shadowing the name; there's no mutation. If you had something like this: (let [x 1] (let [x (inc x)] (println x)) ;; prints 2 (println x)) ;; prints 1 it would be more obvious; it's less apparent in your case because there's no room for the extra forms. That explains it but I think Clojure's syntax is misleading here. Without knowledge of this magic the mind doesn't readily translate: (let [x 1 x (inc x) x (inc x) x (inc x)] x) into: (let [x 1] (let [x (inc x)] (let [x (inc x)] (let [x (inc x)] x The single bracket pair in the original leads the unwitting newcomer to assume all the x'es are in the same scope. gvim -- 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/d/optout. -- Luc Préfontainelprefonta...@softaddicts.ca sent by ibisMail! -- 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/d/optout.
Re: Let bindings and immutability
The multiple-binding form of let can be recursively transformed into nested lets: (let [name1 value1 name2 value2 ... name value] body) (let [name1 value1] (let [name2 value2] ... (let [name value] body))) All you're doing with your let form is shadowing the name; there's no mutation. If you had something like this: (let [x 1] (let [x (inc x)] (println x)) ;; prints 2 (println x)) ;; prints 1 it would be more obvious; it's less apparent in your case because there's no room for the extra forms. On Wed, Feb 11, 2015 at 5:49 PM, gvim gvi...@gmail.com wrote: On 12/02/2015 01:44, Laurens Van Houtven wrote: Hi, You're confusing mutation with single assignment. You're not mutating anything: 1 is still 1, 2 is still 2; you're just assigning the same name to different numbers. The numbers themselves are immutable. It's x that bothers me, not the values assigned to it. I don't quite get it as x seems to behave here like any old mutable variable in Ruby or Python even if it's not called mutation. I suppose I've just never really got this (big) one :( gvim -- 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/d/optout. -- Ben Wolfson Human kind has used its intelligence to vary the flavour of drinks, which may be sweet, aromatic, fermented or spirit-based. ... Family and social life also offer numerous other occasions to consume drinks for pleasure. [Larousse, Drink entry] -- 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/d/optout.
Re: Let bindings and immutability
Local bindings are immutable. Your example demonstrates lexical shadowing of bindings. This is an equivalent program semantically. (let [x 1 x_1 (inc x) x_2 (inc x_1) x_3 (inc x_2)] x_3) By the rules of lexical scoping, you cannot access the first `x` but it is never mutated. Thanks, Ambrose On Wed, Feb 11, 2015 at 8:42 PM, gvim gvi...@gmail.com wrote: Why is this possible in a language based on immutability: (let [x 1 x (inc x) x (inc x) x (inc x)] x) ;;= 4 Maybe under the hood (ie. memory registers/pointers etc.) this isn't strictly mutation but as a relative newcomer to Clojure I find it goes against the grain of what I find elsewhere in the language. gvim -- 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/d/optout. -- 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/d/optout.
Re: Let bindings and immutability
2015-02-12 3:06 GMT+01:00 gvim gvi...@gmail.com: That explains it but I think Clojure's syntax is misleading here. Without knowledge of this magic the mind doesn't readily translate: In some other lisps, clojure's let is called let* for this reason. Their let binds only in parallel, similar to clojure's (binding []) form for vars. -- 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/d/optout.
Re: Let bindings and immutability
(let [x 0 f #(println x) x 1 g #(println x) x 2] (f) (g) x) there is no mutation of x, only scope shadowing hiding the other binding. Most functional languages (all that I know) allow shadowing. -- 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/d/optout.
Re: Let bindings and immutability
On 12/02/2015 01:53, Ben Wolfson wrote: The multiple-binding form of let can be recursively transformed into nested lets: (let [name1 value1 name2 value2 ... name value] body) (let [name1 value1] (let [name2 value2] ... (let [name value] body))) All you're doing with your let form is shadowing the name; there's no mutation. If you had something like this: (let [x 1] (let [x (inc x)] (println x)) ;; prints 2 (println x)) ;; prints 1 it would be more obvious; it's less apparent in your case because there's no room for the extra forms. That explains it but I think Clojure's syntax is misleading here. Without knowledge of this magic the mind doesn't readily translate: (let [x 1 x (inc x) x (inc x) x (inc x)] x) into: (let [x 1] (let [x (inc x)] (let [x (inc x)] (let [x (inc x)] x The single bracket pair in the original leads the unwitting newcomer to assume all the x'es are in the same scope. gvim -- 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/d/optout.
Re: Let bindings and immutability
I think that, from a user perspective, the important difference from mutation to shadowing is, that outer x is available even in the inner context, if captured by a closure. Likewise, a second thread, that runs an outer closure, would see the original x. Observe: (let [x :outer f (fn [] x) x :inner] (println (f)) ; = :outer (println x)) ; = :inner Shadowing can still be confusing to a smaller extent, so I like to call shadowed versions x, x', x'', aso. regards -- 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/d/optout.
Re: Let bindings and immutability
On 12/02/2015 01:44, Laurens Van Houtven wrote: Hi, You’re confusing mutation with single assignment. You’re not mutating anything: 1 is still 1, 2 is still 2; you’re just assigning the same name to different numbers. The numbers themselves are immutable. It's x that bothers me, not the values assigned to it. I don't quite get it as x seems to behave here like any old mutable variable in Ruby or Python even if it's not called mutation. I suppose I've just never really got this (big) one :( gvim -- 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/d/optout.
Let bindings and immutability
Why is this possible in a language based on immutability: (let [x 1 x (inc x) x (inc x) x (inc x)] x) ;;= 4 Maybe under the hood (ie. memory registers/pointers etc.) this isn't strictly mutation but as a relative newcomer to Clojure I find it goes against the grain of what I find elsewhere in the language. gvim -- 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/d/optout.
Re: Let bindings and immutability
Hi, On Feb 11, 2015, at 5:42 PM, gvim gvi...@gmail.com wrote: Why is this possible in a language based on immutability: (let [x 1 x (inc x) x (inc x) x (inc x)] x) ;;= 4 Maybe under the hood (ie. memory registers/pointers etc.) this isn't strictly mutation but as a relative newcomer to Clojure I find it goes against the grain of what I find elsewhere in the language. You’re confusing mutation with single assignment. You’re not mutating anything: 1 is still 1, 2 is still 2; you’re just assigning the same name to different numbers. The numbers themselves are immutable. hth lvh gvim -- 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/d/optout. -- 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/d/optout. signature.asc Description: Message signed with OpenPGP using GPGMail
Re: Let bindings and immutability
On 12 February 2015 at 02:06, gvim gvi...@gmail.com wrote: That explains it but I think Clojure's syntax is misleading here. Without knowledge of this magic the mind doesn't readily translate: (let [x 1 x (inc x) x (inc x) x (inc x)] x) into: (let [x 1] (let [x (inc x)] (let [x (inc x)] (let [x (inc x)] x It's not magic; it's just how the syntax is defined. The for and doseq forms have the same behaviour. Languages like Racket that are perhaps more focused on teaching do have separate let and let* forms. However, Clojure has a more practical focus, and there isn't much practical point in having a non-shadowing let. - James -- 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/d/optout.
Re: try-let
Old thread, but still works great, thanks! Den onsdag den 28. april 2010 03.25.26 UTC+2 skrev ataggart: Inspired from an earlier discussion, I've written a macro that allows let-style binding values to be try'd, and still available to catch/ finally clauses. E.g.: (try-let [from (API/open from-addr) to (API/open to-addr)] (do-stuff from to) (finally (if to (doto to .flush .close)) (if from (.close from (Setting aside the fact that the above example would probably be better implemented using with-open) Source: http://gist.github.com/377278 -- 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 javascript: Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+u...@googlegroups.com javascript: 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 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/d/optout.
Re: Wouldn't it be nice if if-let allowed more bindings?
On Wednesday, November 26, 2014 10:06:41 PM UTC-5, Michael Blume wrote: Instead of the deshadowing logic, why not (defn if-and-let* [bindings then-clause else-fn-name] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-fn-name) (~else-fn-name (defmacro if-and-let [bindings then-clause else-clause] (let [efname (gensym)] `(let [~efname (fn [] ~else-clause)] ~(if-and-let* bindings then-clause efname That ought to work too, but in a way it does the same basic thing, just relying on fn to capture the lexical bindings in effect. I think it might have more overhead, though, including that it constructs an object at runtime for the else clause closure which may or may not even be needed. I'm not sure what the overhead of a bunch of lets is, or of no-op pairs of let such as (let [x y] ... (let [y x] ... y)), though. Perhaps someone can run speed tests of both versions under various circumstances, see which one the runtime/JIT does a better job of optimizing. -- 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/d/optout.
Wouldn't it be nice if if-let allowed more bindings?
Wouldn't it be nice if if-let allowed more bindings? Try this, which I hereby dedicate into the public domain so that anyone may use it freely in their code without restrictions: (defn if-and-let* [bindings then-clause else-clause deshadower] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-clause deshadower) (let ~(vec (apply concat deshadower)) ~else-clause (defmacro if-and-let Like if-let, but with multiple bindings allowed. If all of the expressions in the bindings evaluate truthy, the then-clause is executed with all of the bindings in effect. If any of the expressions evaluates falsey, evaluation of the remaining binding exprs is not done, and the else-clause is executed with none of the bindings in effect. If else-clause is omitted, evaluates to nil if any of the binding expressions evaluates falsey. As with normal let bindings, each binding is available in the subsequent bindings. (if-and-let [a (get my-map :thing) b (do-thing-with a)] ...) is legal, and will not throw a null pointer exception if my-map lacks a :thing key and (do-thing-with nil) would throw an NPE. If there's something you want to be part of the then-clause's condition, but whose value you don't care about, including a binding of it to _ is more compact than nesting yet another if inside the then-clause. ([bindings then-clause] `(if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (let [shadowed-syms (filter #(or ((or env {}) %) (resolve %)) (filter symbol? (tree-seq coll? seq (take-nth 2 bindings deshadower (zipmap shadowed-syms (repeatedly gensym))] `(let ~(vec (apply concat (map (fn [[k v]] [v k]) deshadower))) ~(if-and-let* bindings then-clause else-clause deshadower) = (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] :nothing) :nothing = (if-and-let [x (:a {:a 42}) y (first [(/ x 3)])] [x y] :nothing) [42 14] = (if-and-let [x (:a {:a 42}) y (first [])] [x y] :nothing) :nothing Note that this is not quite as simple as the obvious naive implementation: (defmacro naive-if-and-let ([bindings then-clause] `(naive-if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) (naive-if-and-let ~(vec (drop 2 bindings)) ~then-clause ~else-clause) ~else-clause but what happens if a name used in the if-and-let is already bound in the enclosing context is instructive: = (let [x 6] (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 42 As you can see, the x in the else clause in naive-if-and-let sometimes sees the x binding in the if-and-let (if that succeeded) and sometimes sees the enclosing binding (if not), when it should always refer to the enclosing (let [x 6] ...). The non-naive if-and-let discovers all local bindings that might be shadowed by walking the left hand sides of the new bindings and tree-walking the data structure there to extract symbols, which it filters further against env. It outputs an enclosing let that saves all of these to non-shadowed locals named with gensyms, and wraps every else clause emission in a let that restores the original bindings of these symbols from these gensym locals. The tree-walking makes it work even with destructuring its the binding vector: = (let [x 6] (if-and-let [{x :a} {:a 42} y (first [(/ x 3)])] [x y] x)) [42 14] = (let [x 6] (if-and-let [{x :a} {:a 42} y (first [])] [x y] x)) 6 It also unshadows defs: = (def x 6) = (if-and-let [{x :a} {:a 42} y (first [])] [x y] x) 6 That's from the (or ... (resolve %)) part of the outer filter on the walked tree. Remove that and leave the outer filter as just (filter (or env {}) ...), and that last test produces 42 instead. Not that you should really be shadowing defs with locals anyway. That's always prone to cause problems. Not bad for only 18 lines of actual code, hmm? -- 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
Re: Wouldn't it be nice if if-let allowed more bindings?
Instead of the deshadowing logic, why not (defn if-and-let* [bindings then-clause else-fn-name] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-fn-name) (~else-fn-name (defmacro if-and-let [bindings then-clause else-clause] (let [efname (gensym)] `(let [~efname (fn [] ~else-clause)] ~(if-and-let* bindings then-clause efname On Wed Nov 26 2014 at 4:11:00 AM Fluid Dynamics a2093...@trbvm.com wrote: Wouldn't it be nice if if-let allowed more bindings? Try this, which I hereby dedicate into the public domain so that anyone may use it freely in their code without restrictions: (defn if-and-let* [bindings then-clause else-clause deshadower] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-clause deshadower) (let ~(vec (apply concat deshadower)) ~else-clause (defmacro if-and-let Like if-let, but with multiple bindings allowed. If all of the expressions in the bindings evaluate truthy, the then-clause is executed with all of the bindings in effect. If any of the expressions evaluates falsey, evaluation of the remaining binding exprs is not done, and the else-clause is executed with none of the bindings in effect. If else-clause is omitted, evaluates to nil if any of the binding expressions evaluates falsey. As with normal let bindings, each binding is available in the subsequent bindings. (if-and-let [a (get my-map :thing) b (do-thing-with a)] ...) is legal, and will not throw a null pointer exception if my-map lacks a :thing key and (do-thing-with nil) would throw an NPE. If there's something you want to be part of the then-clause's condition, but whose value you don't care about, including a binding of it to _ is more compact than nesting yet another if inside the then-clause. ([bindings then-clause] `(if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (let [shadowed-syms (filter #(or ((or env {}) %) (resolve %)) (filter symbol? (tree-seq coll? seq (take-nth 2 bindings deshadower (zipmap shadowed-syms (repeatedly gensym))] `(let ~(vec (apply concat (map (fn [[k v]] [v k]) deshadower))) ~(if-and-let* bindings then-clause else-clause deshadower) = (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] :nothing) :nothing = (if-and-let [x (:a {:a 42}) y (first [(/ x 3)])] [x y] :nothing) [42 14] = (if-and-let [x (:a {:a 42}) y (first [])] [x y] :nothing) :nothing Note that this is not quite as simple as the obvious naive implementation: (defmacro naive-if-and-let ([bindings then-clause] `(naive-if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) (naive-if-and-let ~(vec (drop 2 bindings)) ~then-clause ~else-clause) ~else-clause but what happens if a name used in the if-and-let is already bound in the enclosing context is instructive: = (let [x 6] (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 42 As you can see, the x in the else clause in naive-if-and-let sometimes sees the x binding in the if-and-let (if that succeeded) and sometimes sees the enclosing binding (if not), when it should always refer to the enclosing (let [x 6] ...). The non-naive if-and-let discovers all local bindings that might be shadowed by walking the left hand sides of the new bindings and tree-walking the data structure there to extract symbols, which it filters further against env. It outputs an enclosing let that saves all of these to non-shadowed locals named with gensyms, and wraps every else clause emission in a let that restores the original bindings of these symbols from these gensym locals. The tree-walking makes it work even with destructuring its the binding vector: = (let [x 6] (if-and-let [{x :a} {:a 42} y (first [(/ x 3)])] [x y] x)) [42 14] = (let [x 6] (if-and-let [{x :a} {:a 42} y (first [])] [x y] x)) 6 It also unshadows defs: = (def x 6) = (if-and-let [{x :a} {:a 42} y (first [])] [x y] x) 6 That's from the (or ... (resolve %)) part of the outer filter on the walked tree. Remove that and leave the outer filter as just (filter (or env {}) ...), and that last test produces 42 instead. Not that you should really be shadowing defs with locals anyway. That's always prone to cause problems. Not bad for only 18 lines of actual code, hmm? -- You
Re: Wouldn't it be nice if if-let allowed more bindings?
You've discovered the error (or Either) monad! https://brehaut.net/blog/2011/error_monads Michael Blume mailto:blume.m...@gmail.com November 26, 2014 at 8:06 PM Instead of the deshadowing logic, why not (defn if-and-let* [bindings then-clause else-fn-name] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-fn-name) (~else-fn-name (defmacro if-and-let [bindings then-clause else-clause] (let [efname (gensym)] `(let [~efname (fn [] ~else-clause)] ~(if-and-let* bindings then-clause efname -- 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 mailto:clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout. Fluid Dynamics mailto:a2093...@trbvm.com November 26, 2014 at 5:10 AM Wouldn't it be nice if if-let allowed more bindings? Try this, which I hereby dedicate into the public domain so that anyone may use it freely in their code without restrictions: (defn if-and-let* [bindings then-clause else-clause deshadower] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) ~(if-and-let* (drop 2 bindings) then-clause else-clause deshadower) (let ~(vec (apply concat deshadower)) ~else-clause (defmacro if-and-let Like if-let, but with multiple bindings allowed. If all of the expressions in the bindings evaluate truthy, the then-clause is executed with all of the bindings in effect. If any of the expressions evaluates falsey, evaluation of the remaining binding exprs is not done, and the else-clause is executed with none of the bindings in effect. If else-clause is omitted, evaluates to nil if any of the binding expressions evaluates falsey. As with normal let bindings, each binding is available in the subsequent bindings. (if-and-let [a (get my-map :thing) b (do-thing-with a)] ...) is legal, and will not throw a null pointer exception if my-map lacks a :thing key and (do-thing-with nil) would throw an NPE. If there's something you want to be part of the then-clause's condition, but whose value you don't care about, including a binding of it to _ is more compact than nesting yet another if inside the then-clause. ([bindings then-clause] `(if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (let [shadowed-syms (filter #(or ((or env {}) %) (resolve %)) (filter symbol? (tree-seq coll? seq (take-nth 2 bindings deshadower (zipmap shadowed-syms (repeatedly gensym))] `(let ~(vec (apply concat (map (fn [[k v]] [v k]) deshadower))) ~(if-and-let* bindings then-clause else-clause deshadower) = (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] :nothing) :nothing = (if-and-let [x (:a {:a 42}) y (first [(/ x 3)])] [x y] :nothing) [42 14] = (if-and-let [x (:a {:a 42}) y (first [])] [x y] :nothing) :nothing Note that this is not quite as simple as the obvious naive implementation: (defmacro naive-if-and-let ([bindings then-clause] `(naive-if-and-let ~bindings ~then-clause nil)) ([bindings then-clause else-clause] (if (empty? bindings) then-clause `(if-let ~(vec (take 2 bindings)) (naive-if-and-let ~(vec (drop 2 bindings)) ~then-clause ~else-clause) ~else-clause but what happens if a name used in the if-and-let is already bound in the enclosing context is instructive: = (let [x 6] (if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:b 42}) y (first [(/ x 3)])] [x y] x)) 6 = (let [x 6] (naive-if-and-let [x (:a {:a 42}) y (first [])] [x y] x)) 42 As you can see, the x in the else clause in naive-if-and-let sometimes sees the x binding in the if-and-let (if that succeeded) and sometimes sees the enclosing binding (if not), when it should always refer to the enclosing (let [x 6] ...). The non-naive if-and-let discovers all local bindings that might be shadowed by walking the left hand sides of the new bindings and tree-walking the data structure there to extract symbols, which it filters further against env. It outputs an enclosing let that saves all of these to non-shadowed locals named
assert inside an if-let
Hi, the following form doesn't compile and I see no reason why it shouldn't: (if-let [a a] a (assert a)) IMHO it is a bug. If anyone is of a different opinion please share. Thanks, -- László Török -- 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/d/optout.