MathGroup Archive 2009

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Is it possible to dynamically construct arguments to

  • To: mathgroup at smc.vnet.net
  • Subject: [mg105798] Re: [mg105783] Is it possible to dynamically construct arguments to
  • From: Leonid Shifrin <lshifr at gmail.com>
  • Date: Sat, 19 Dec 2009 06:27:10 -0500 (EST)
  • References: <hgd7ts$bn3$1@smc.vnet.net> <200912181125.GAA16684@smc.vnet.net>

Hi Leo,

Somehow I missed your original post. First, let me suggest a possible
refinement of Daniel's solution which will be protected against possible
global values that dummy variables may have:

In[1]:=
a0 = 1; b0 = 2;

Hold[With[{a = a0, b = b0}, a b]] /. {a0 -> 2, b0 -> 3} // ReleaseHold

Out[1]  = 2

Wrapping dummy variables in HoldPattern is all that is needed to make it
work also in this case:

In[2]:=
Hold[With[{a = a0, b = b0}, a b]] /. {HoldPattern[a0] -> 2,
   HoldPattern[b0] -> 3} // ReleaseHold

Out[2]= 6


Here are a couple of more ways, utilizing replacement rules:

This will work regardless of whether or not <var> has a global value. Using
a delayed rule allows us to keep the code a=3 unevaluated.

In[3]:=
Unevaluated[With[var, a*100]] /. HoldPattern[var] :> {a = 3}

Out[3]= 300

This is the same but we can use the global rule already stored in OwnValues
in this case (you must use delayed assignment though) :

In[4]:= Clear[aa];
aa := {a = 3}

In[5]:= Unevaluated[With[aa, a*100]] /. OwnValues[aa]

Out[5]= 300

For this I may be flamed, but in this particular case it works well:

In[6] =
Block[{Set}, With[Evaluate[aa], a*100]]

Out[6] =300;

However, generally using Block trick is not a good idea because you don't
fully control the evaluation stack associated with the <body> of With for
generic <body> and can't be sure that Set will  never be used there, and
besides it is especially dangerous to Block such an important command as
Set.

Here is a somewhat more sophisticated approach based on a partial evaluator,
which extends the above to allow you to store you initialization list also
in DownValues and SubValues:

ClearAll[symbolicHead];
SetAttributes[symbolicHead, HoldAll];
symbolicHead[f_Symbol[___]] := f;
symbolicHead[f_[___]] := symbolicHead[f];
symbolicHead[f_] := Head[Unevaluated[f]];

ClearAll[partialEval];
SetAttributes[partialEval, HoldAll];
partialEval[a_Symbol] /; OwnValues[a] =!= {} :=
  Unevaluated[partialEval[a]] /. OwnValues[a];
partialEval[a : f_Symbol[___]] /; DownValues[f] =!= {} :=
  Unevaluated[partialEval[a]] /. DownValues[f];
partialEval[a_] :=
  With[{sub =
     SubValues[
      Evaluate[symbolicHead[a]]]}, (Unevaluated[partialEval[a]] /.
      sub) /; sub =!= {}];

ClearAll[myWith];
SetAttributes[myWith, HoldAll];
myWith[initvars_, body_] :=
  With @@ Append[partialEval[initvars], Unevaluated[body]];

It allows you to store the initialization for variables separately and
globally as some OwnValues, DownValues or SubValues. The usage might be as
follows:

In[7]:=
Clear[aa,bb,cc,dd,a,b,c];
aa:={a=3};
bb[1]:={a=4};
cc[1][2]:={a=5};
dd[1][2][3]:={a=1,b=2,c=3};

In[12]:= myWith[aa,a*100]

Out[12]= 300

In[13]:= myWith[bb[1],a*100]

Out[13]= 400

In[14]:= myWith[cc[1][2],a*100]

Out[14]= 500

In[15]:= myWith[dd[1][2][3],c*100+b*10+a]

Out[15]= 321

In[16]:= {a, b, c}

Out[16]= {a, b, c}

It might be a good idea to add to this some warning messages when some of
the variables initialized in <initvars> are not utilized in the body -
without such checks breaking the scope globally is error-prone. Even with
such messages breaking the scope is error-prone because you can never
automatically spot it if you forgot to localize some variable and are
consequently using its global value in the body of <With> (and the latter is
often desirable when With is an inner construct inside Modules or other
scoping constructs - then variables local to those will look global to the
inner With of interest - so you can not just forbid it). So, consider all of
the above suggestions as just an illustration of some additional ways to
accomplish what you asked for, but not as my advice to actually start using
this in place of the standard With, unless the project is small and the
convenience really overweighs the risk of errors.

By the way, it is a little outside of the main line of discussion, but note
that With does evaluate the r.h.sides of the initialization list:

In[17] =
With[{a = (Print["*"]; 1)}, Hold[a]]

During evaluation of In[17]:= *

Out[17] =
Hold[1]

Usually this is what is needed. But this also means that  you really *can
not* directly use With to insert partially evaluated expressions into some
code. The solution of Albert does indeed "blind" With to interpret the list
{a=...} as initializer rather than assignment to global <a> , but it does
not prevent the following:

In[18]:=

aa = Hold[{a = (Print["*"]; 1)}];
With[{vardef = Unevaluated @@ aa}, With[vardef, Hold[a]]]

During evaluation of In[19]:= *

Out[20]= Hold[1]

which indicates that the r.h.s of the initializer gets evaluated also in
this case. Wrapping the r.h.s in Unevaluated as in With[{a =
Unevaluated[(Print["*"]; 1)]}, Hold[a]] may work in some cases though, but
this must be done by hand for all initializers in the initialization list,
and besides, Unevaluated wrapper will be kept inside all heads with the
relevant Hold*-attributes - which may or may not be harmless).

Rather, you usually use With  to insert evaluated pieces into places located
deep inside  an otherwise unevaluated (at the stage of insertion)
expression.   If you want to keep your initializers'  r.h.sides unevaluated
but use the advantages of With over replacement rules (the capability of
automatic nesting / name collision resolution with inner scoping constructs,
for instance), it is also possible but less straightforward.  The following
wrapper can be wrapped around any With and forbid it to evaluate the
expressions  - r.h.sides in the initialization list:

ClearAll[withNoEval];
SetAttributes[withNoEval, HoldAll];
withNoEval[With[vars_, body_]] :=
  Module[{myHold, heldVars  = Hold[vars]},
   SetAttributes[myHold, HoldAll];
   heldVars = heldVars /. Verbatim[Set][x_, y_] :> Set[x, myHold[y]];
   With @@
    Append[heldVars,
     Unevaluated[Unevaluated[body] /. myHold[x__] :> x]]];

For example:

In[21]:= With[{a = (Print["*"]; 1), b = (Print["**"]; 2)}, Hold[a*b]]

During evaluation of In[21]:= *

During evaluation of In[21]:= **

Out[21]= Hold[1 x 2]

In[22]:= withNoEval[
 With[{a = (Print["*"]; 1), b = (Print["**"]; 2)}, Hold[a*b]]]

Out[22]= Hold[(Print["*"]; 1) (Print["**"]; 2)]

Here is  by the way how Albert's solution can be modified to easily
incorporate this functionality:

In[23]:=
aa = Hold[{a = (Print["*"]; 1)}];
With[{vardef = Unevaluated @@ aa}, withNoEval@With[vardef, Hold[a]]]

Out[24]= Hold[Print["*"]; 1]

In this form, it will generalize to several variables in the initialization
list.

This should be ok in most cases (not sure about heads with SequenceHold
attribute possibly present in the <body> of original With) when you might
need such functionality, but will cause some performance hit with respect to
pure With (this solution won't work with <myWith> function above, however).

Finally, if you are interested in playing with scoping (With in particular),
there are a couple of  threads on similar topics that I am aware of (perhaps
many other threads in the past as well, of which I am not aware due to my
rather young age  as the group member):

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


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


Hope this helps.

Regards,
Leonid



On Fri, Dec 18, 2009 at 3:25 AM, dh <dh at metrohm.com> wrote:

>
>
> Hi Leo,
>
> First, Wrap the with in Hold. In the "With" write dummy values for the
>
> local variables. Then replace the dummys by actual values and finally
>
> relese the Hold:
>
>
>
> Hold[With[{a = a0, b = b0}, a b]] /. {a0 -> 2, b0 -> 3} // ReleaseHold
>
>
>
> Daniel
>
>
>
> Leo Alekseyev wrote:
>
> > I've been trying to construct a list of local variables for the With
>
> > construct dynamically, with no avail.  I tried various combinations of
>
> > Unevaluated, Hold, and even ToBoxes/MakeExpression.  I've read that
>
> > With[] evaluates its initialization lists in a non-standard way (cf
>
> >
> http://library.wolfram.com/conferences/devconf99/villegas/UnevaluatedExpressions/Links/index_lnk_7.html
> )
>
> > -- is this the problem?..  Is it possible to achieve something like
>
> > the code below?
>
> >
>
> > (* this doesn't wok *)
>
> > Clear[aa, a];
>
> > aa = List[Unevaluated[a = 3]];
>
> > With[aa, a*100] // Print; (* want 300 *)
>
> >
>
>


  • Prev by Date: Re: Find maxima in lists of data
  • Next by Date: Re: CellChangeTimes?
  • Previous by thread: Re: Is it possible to dynamically construct arguments to With[]?
  • Next by thread: Re: Is it possible to dynamically construct arguments to With[]?