Re: [ANN] com.walmartlabs/cond-let 1.0.0

2018-10-05 Thread Howard Lewis Ship
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

2018-10-04 Thread Mark Engelberg
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

2018-10-04 Thread Alan Thompson
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

2018-10-04 Thread Howard Lewis Ship
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

2018-10-04 Thread Gary Trakhman
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

2018-10-04 Thread lei Shulang
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

2018-10-04 Thread Moe Aboulkheir
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

2018-10-04 Thread Gary Trakhman
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

2018-10-03 Thread Mark Engelberg
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

2018-10-03 Thread Matching Socks
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

2018-10-03 Thread Howard Lewis Ship
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!

2017-11-30 Thread Leif


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!

2017-11-29 Thread Ambrose Bonnaire-Sergeant
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!

2017-11-28 Thread Henrik Eneroth
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!

2017-11-28 Thread Eunmin Kim
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

2017-10-25 Thread Matching Socks
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

2017-10-24 Thread Justin Smith
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

2017-10-24 Thread yihao yang
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?

2017-10-08 Thread Gary Verhaegen
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?

2017-10-07 Thread Nathan Fisher
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?

2017-10-07 Thread Fabrizio Ferrai
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?

2017-10-06 Thread 'bertschi' via Clojure


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?

2017-10-02 Thread Didier
> 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?

2017-10-02 Thread hiskennyness


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?

2017-10-02 Thread Luke Burton


> On Oct 1, 2017, at 9:21 PM, Didier  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.

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?

2017-10-02 Thread Duncan McGreggor
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?

2017-10-02 Thread Daniel Compton
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?

2017-10-01 Thread Didier

>
> 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?

2017-10-01 Thread Luke Burton

> 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?

2017-10-01 Thread Didier
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?

2017-09-30 Thread Marcus Magnusson
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?

2017-09-30 Thread Didier
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

2017-05-26 Thread Christopher Howard
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

2017-05-26 Thread Gary Trakhman
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

2017-05-26 Thread Christopher Howard
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?

2017-05-17 Thread Phillip Lord

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?

2017-05-17 Thread 'Alan Forrester' via Clojure
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?

2017-05-17 Thread Ralf Schmitt
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?

2017-05-17 Thread Kevin Kleinfelter
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

2017-03-06 Thread juan.facorro
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

2017-03-06 Thread Kevin Downey
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

2017-03-06 Thread juan.facorro
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?

2016-12-04 Thread Timothy Baldridge
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?

2016-12-03 Thread Paul Gowder
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?

2016-12-03 Thread Timothy Baldridge
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?

2016-12-02 Thread Mark Engelberg
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?

2016-12-02 Thread Paul Gowder
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?

2016-12-02 Thread Walter van der Laan
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?

2016-12-02 Thread Francis Avila
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?

2016-12-02 Thread Bobby Eickhoff
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?

2016-12-02 Thread Paul Gowder
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

2016-12-01 Thread Timothy Baldridge
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

2016-12-01 Thread Gary Trakhman
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

2016-12-01 Thread Matthew Hamrick
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

2016-07-26 Thread Ertuğrul Çetin
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

2015-11-09 Thread Karl Mikkelsen
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

2015-07-11 Thread crocket
(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

2015-07-11 Thread Andy Fingerhut
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*

2015-06-26 Thread Johannes
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*

2015-06-26 Thread Raoul Duke
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*

2015-06-25 Thread Alex Miller
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*

2015-06-25 Thread Luc Préfontaine
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*

2015-06-20 Thread Mike Rodriguez
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*

2015-06-18 Thread Harley Waagmeester
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*

2015-06-18 Thread Fluid Dynamics
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*

2015-06-18 Thread Johannes
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*

2015-06-18 Thread Raoul Duke
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*

2015-06-18 Thread Johannes
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*

2015-06-18 Thread Michael Blume
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?

2015-06-10 Thread Mike Rodriguez
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

2015-06-09 Thread crocket
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?

2015-06-09 Thread crocket


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?

2015-06-09 Thread Andy Fingerhut
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?

2015-06-09 Thread Jozef Wagner
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?

2015-06-09 Thread Leon Grapenthin
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?

2015-06-09 Thread Fluid Dynamics
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?

2015-06-09 Thread Sean Corfield
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?

2015-06-09 Thread Lars Andersen
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?

2015-06-09 Thread Isaac Zeng
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

2015-06-06 Thread crocket
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

2015-06-05 Thread Fluid Dynamics
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

2015-06-04 Thread crocket


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

2015-06-04 Thread crocket
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

2015-02-12 Thread Luc Préfontaine
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

2015-02-11 Thread Ben Wolfson
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

2015-02-11 Thread Ambrose Bonnaire-Sergeant
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-11 Thread Herwig Hochleitner
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

2015-02-11 Thread Justin Smith
(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

2015-02-11 Thread gvim

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

2015-02-11 Thread Herwig Hochleitner
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

2015-02-11 Thread gvim

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

2015-02-11 Thread gvim

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

2015-02-11 Thread Laurens Van Houtven
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

2015-02-11 Thread James Reeves
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

2014-12-19 Thread Simon Stender Boisen
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?

2014-11-27 Thread Fluid Dynamics
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?

2014-11-26 Thread Fluid Dynamics
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?

2014-11-26 Thread Michael Blume
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?

2014-11-26 Thread Sam Ritchie

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

2014-11-19 Thread László Török
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.


  1   2   3   4   5   6   7   >