Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Variables within With statement

23 views
Skip to first unread message

Harvey P. Dale

unread,
Dec 15, 2011, 4:53:45 AM12/15/11
to
Is there any easy way to have one variable within a With
statement take its value from a prior variable in the same With
statement? For example, if I evaluate With[{a = 5, b = 10 a}, a + b], I
get 5 + 10a, and what I want is 55. I can get there like this: With[{a
= 5}, With[{b = 10 a}, a + b]] -- which does produce 55 -- but it would
be nicer if I could use a single With statement and get b, within it, to
take its value from a.

Thanks.

Harvey

Tomas Garza

unread,
Dec 16, 2011, 5:54:58 AM12/16/11
to
There is no way to obtain what you want. The definition of With specifies that in expr occurrences of the symbols x, y, ... should be replaced by Subscript[x, 0], Subscript[y, 0], .... and makes no reference to the order in which they are written. That is to say, the replacement is simultaneous. Try writing the variables in reverse order:
In[1]:= With[{x = a, b = a + 5}, a + b]
Out[1]= 5 + 2 a

In[3]:= With[{b = a + 5, x = a}, a + b]
Out[3]= 5 + 2 a
In both cases their FullForm gives
Plus[5,Times[2,a]]
-Tomas
> Date: Thu, 15 Dec 2011 04:51:48 -0500
> From: hp...@nyu.edu
> Subject: Variables within With statement
> To: math...@smc.vnet.net

Ulrich Arndt

unread,
Dec 16, 2011, 5:41:11 AM12/16/11
to
Any special reason for With usage?
Otherwise use Block

Block[{ a = 5, b = a 10}, a + b]

Ulrich

Leonid Shifrin

unread,
Dec 16, 2011, 5:42:43 AM12/16/11
to
This question has been asked before. The real problem is to integrate such
a use case nicely with existing uses for With. In particular, we may want
it to work correctly with the shared local variables, and as a r.h.s. of
the assignment operator. There were a few threads devoted to it both
here and on StackOverflow. Here is my implementation of the scoping
construct which does that:

ClearAll[LetL];
SetAttributes[LetL, HoldAll];
LetL /: Verbatim[SetDelayed][lhs_, rhs : HoldPattern[LetL[{__}, _]]] :=
Block[{With}, Attributes[With] = {HoldAll};
lhs := Evaluate[rhs]];
LetL[{}, expr_] := expr;
LetL[{head_}, expr_] := With[{head}, expr];
LetL[{head_, tail__}, expr_] :=
Block[{With}, Attributes[With] = {HoldAll};
With[{head}, Evaluate[LetL[{tail}, expr]]]];

What this does it to generate the nested With statements at run-time, and
then execute them. For example:

In[63]:= a=1;b=2;
LetL[{a=3,b=a+4},{a,b}]

Out[64]= {3,7}

You can see it better by using Trace:

In[66]:= Trace[LetL[{a=3,b=a+4},{a,b}],_With]
Out[66]=
{{{{With[{b=a+4},{a,b}]},With[{a=3},With[{b=a+4},{a,b}]]},With[{a=3},With[{b=a+4},{a,b}]]},With[{a=3},With[{b=a+4},{a,b}]],With[{b$=3+4},{3,b$}]}

Care was taken to avoid variable captures from the top-level (e.g. global
values for a and b above were ignored, as they should have been).

It is disccused more fully here:

http://stackoverflow.com/questions/5866016/question-on-condition/5869885#5869885

And the original discussion is in this thread:

http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/3a5ae92bda1c7511

A similar discussion can be found here:

https://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/6fa6b0ad9d5d111c

with it's continuation here:

http://stackoverflow.com/questions/4198961/what-is-in-your-mathematica-tool-bag/5692010#5692010

Whether or not any of the suggested solutions can be called easy is a
matter of opinion. I used my version in many places and had no problems
with it.

Another approach that you may take is if you *insist* to use literal *With*
but change its properties. You can use code-generation techniques similar
to the one exposed here:

http://stackoverflow.com/questions/8373526/error-generating-localized-variables-as-constants/8377522#8377522

to achieve that. Actually, my version above also does that, but it
generates nested `With` statements at run-time.

Hope this helps.

Regards,
Leonid

DrMajorBob

unread,
Dec 16, 2011, 5:57:08 AM12/16/11
to
It would be nicer, but you can't do it.

Bobby

On Thu, 15 Dec 2011 03:51:48 -0600, Harvey P. Dale <hp...@nyu.edu> wrote:

> Is there any easy way to have one variable within a With
> statement take its value from a prior variable in the same With
> statement? For example, if I evaluate With[{a = 5, b = 10 a}, a + b], I
> get 5 + 10a, and what I want is 55. I can get there like this: With[{a
> = 5}, With[{b = 10 a}, a + b]] -- which does produce 55 -- but it would
> be nicer if I could use a single With statement and get b, within it, to
> take its value from a.
>
> Thanks.
>
> Harvey
>


--
DrMaj...@yahoo.com

Simon

unread,
Dec 16, 2011, 6:07:26 AM12/16/11
to
This has come up a few time recently on this mathgroup and stackoverflow:

https://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/6fa6b0ad9d5d111c
http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/3a5ae92bda1c7511
http://stackoverflow.com/a/5692010/421225
http://stackoverflow.com/a/4191096/421225

For what it's worth, here's the various versions I keep floating around

SetAttributes[Let, HoldAll];
SyntaxInformation[Let] = {"ArgumentsPattern" -> {{__}, _}};
Let[{}, expr_] := expr
Let[{a_, b___}, expr_] := With[{a}, Let[{b}, expr]]
SetAttributes[WithRules, HoldRest]
WithRules[rules_, expr_] := With@@Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]
SetAttributes[LetRules, HoldRest]
LetRules[rules_, expr_] := Let@@Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]

Simon

markholtuk

unread,
Dec 17, 2011, 2:39:51 AM12/17/11
to
You could try delaying assignment of a, as follows:

In[1]:= With[{a := a = 5, b = 10 a}, a + b]

Out[1]= 55

Cheers,

Mark

Shizu

unread,
Dec 17, 2011, 2:48:36 AM12/17/11
to
In Block[], global variables have local values.
So, this will work:

Clear[a];
Block[{a = 5, b = 10 a}, a + b]


In With[], rhs of an assignment(eg., 10 a) is evaluated before With[] as a whole.
So, b = 10 a, and a's value is global.
And so, this doesn't work for your case:

Clear[a];

Alexander Elkins

unread,
Dec 17, 2011, 2:49:37 AM12/17/11
to
Here is an implementation which nests each variable in its own separate With
statement using Fold:

NestedWith[l_,e_] :=Identity@@
Fold[Unevaluated@With[{#2},#1]&,Unevaluated@Unevaluated@e,
Reverse@Thread@Unevaluated@Unevaluated@l] /;
If[Head@Unevaluated@l === List, True,
Message[With::lvlist, ToString@Unevaluated@l]; False]

SetAttributes[NestedWith,HoldAll]

NestedWith::usage=
StringReplace[Replace[With::usage,Messages[With]],"With"->"NestedWith"];

SyntaxInformation[NestedWith]={"ArgumentsPattern"->{{__},_}};
For example:

In[1]:=a=Exp[2];b=Exp[3];c=Exp[4];

In[2]:=NestedWith[{a=5,b=10a,cb},a+b+c]
Out[2]= 1055

Which matches:

In[3]:=With[{a=5},With[{b=10a},With[{cb},a+b+c]]]
Out[3]= 1055

Alexander

"Harvey P. Dale" <hp...@nyu.edu> wrote in message
news:jccg39$mb4$1...@smc.vnet.net...

Szabolcs

unread,
Dec 20, 2011, 3:09:08 AM12/20/11
to
On Saturday, 17 December 2011 08:39:51 UTC+1, markholtuk wrote:
> You could try delaying assignment of a, as follows:
>
> In[1]:= With[{a := a = 5, b = 10 a}, a + b]
>
> Out[1]= 55
>

Please note that this solution modifies the global variable 'a', and therefore defeats the purpose of With (which is defining *local* constants).

The original question is a good one, I often wish for such a functionality too (and it's no coincidence that so many custom implementations can be found all over the web).

Dan

unread,
Dec 21, 2011, 7:00:51 AM12/21/11
to
> {{{{With[{b=a+4},{a,b}]},With[{a=3},With[{b=a+4},{a,b}]]},With[{a=3},With[{=ADb=a+4},{a,b}]]},With[{a=3},With[{b=a+4},{a,b}]],With[{b$=3+4},{3,b$}]}
>
> Care was taken to avoid variable captures from the top-level (e.g. global
> values for a and b above were ignored, as they should have been).
>
> It is disccused more fully here:
>
> http://stackoverflow.com/questions/5866016/question-on-condition/5869...
>
> And the original discussion is in this thread:
>
> http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_...
>
> A similar discussion can be found here:
>
> https://groups.google.com/group/comp.soft-sys.math.mathematica/browse...
>
> with it's continuation here:
>
> http://stackoverflow.com/questions/4198961/what-is-in-your-mathematic...
>
> Whether or not any of the suggested solutions can be called easy is a
> matter of opinion. I used my version in many places and had no problems
> with it.
>
> Another approach that you may take is if you *insist* to use literal *With*
> but change its properties. You can use code-generation techniques similar
> to the one exposed here:
>
> http://stackoverflow.com/questions/8373526/error-generating-localized...
>
> to achieve that. Actually, my version above also does that, but it
> generates nested `With` statements at run-time.
>
> Hope this helps.
>
> Regards,
> Leonid
>
> On Thu, Dec 15, 2011 at 12:51 PM, Harvey P. Dale <h...@nyu.edu> wrote:
>
>
>
> > Is there any easy way to have one variable within a With
> > statement take its value from a prior variable in the same With
> > statement? For example, if I evaluate With[{a = 5, b = 10 a}, a + b], I
> > get 5 + 10a, and what I want is 55. I can get there like this: With[{a
> > = 5}, With[{b = 10 a}, a + b]] -- which does produce 55 -- but it would
> > be nicer if I could use a single With statement and get b, within it, to
> > take its value from a.
>
> > Thanks.
>
> > Harvey- Hide quoted text -
>
> - Show quoted text -

Why is this method more desirable than using a nested With,Module?

With[{a = 5}, Module[{b = 10 a}, a+b]]

There must be a significant advantage if you must go through so much
trouble, but I don't see it.

-- Dan

Leonid Shifrin

unread,
Dec 22, 2011, 4:28:18 AM12/22/11
to
With is different from Module. Module creates temporary symbols, variables
created by Module can be modified in the body of Module, and Module can
not inject pieces into unevaluated code as With can. From that simple
example you cited, it may not be apparent, but there are cases when With is
appropriate while Module is not.

markholtuk

unread,
Dec 22, 2011, 4:26:11 AM12/22/11
to
On Dec 20, 8:09 am, Szabolcs <szhor...@gmail.com> wrote:
> On Saturday, 17 December 2011 08:39:51 UTC+1, markholtuk wrote:
> > You could try delaying assignment of a, as follows:
>
> > In[1]:= With[{a := a = 5, b = 10 a}, a + b]
>
> > Out[1]= 55
>
> Please note that this solution modifies the global variable 'a', and therefore defeats the purpose of With (which is defining *local* constants).


Indeed. Apologies for this. The Christmas run-up appears to be having
its usual effect on my IQ!

0 new messages