Re: A version of With that binds variables sequentially
- To: mathgroup at smc.vnet.net
- Subject: [mg94574] Re: A version of With that binds variables sequentially
- From: dh <dh at metrohm.com>
- Date: Tue, 16 Dec 2008 06:04:07 -0500 (EST)
- References: <gi5jof$prg$1@smc.vnet.net>
Hi,
"With" only allowes local constants. "Module" not only allowes local
constants, but also local variables. This easily solves your problem:
Module[{a1=5,a2,a3},a2=f[a1];a3=g[a1,a2];h[a1,a2,a3]]
hope this helps, Daniel
D. Grady wrote:
> Many times when I'm programming, I write code like this:
>
> With[{a1 = 5},
> With[{a2 = f[a1]},
> With[{a3 = g[a1, a2]},
> h[a1, a2, a3]]]]
>
> I wish I could write this instead:
>
> With[{
> a1 = 5,
> a2 = f[a1],
> a3 = g[a1, a2]},
> h[a1, a2, a3]]
>
> Although With doesn't work this way, I didn't see any reason that it
> shouldn't, so I wrote a function called WithMany. It works by taking
> something in the second form above and holding all of the arguments,
> expanding out to the first form, and then releasing the hold.
>
> In spite of the simplicity of the idea, it was tricky for me to figure
> out the details of this function. I thought that someone else might
> find it helpful, and I also had some questions about it.
>
> Am I using a bad idiom with the nested With's? Is it better to just
> use Module and be done with it?
>
> Is there a way to get syntax highlighting for WithMany? I found the
> SyntaxInformation stuff, but it doesn't seem to expose the
> highlighting that's used for With, Module, or Block.
>
> Are there any cases where this function fails or does something
> unexpected?
>
> Is there a clearer way to write this function? It seems very
> complicated right now, especially in the fact that I need to use both
> a special symbol with attribute HoldAll and a special function with
> attribute HoldAll. Maybe someone sees a way to make it simpler?
>
> Really I'm just curious what other people think about this. Any
> comments would be appreciated.
>
> A simple example:
>
> WithMany[{
> a1 = 5,
> a2 = RandomChoice@Range@a1,
> a3 = f[a2, a1]},
> {a1, a2, a3}]
>
> {5, 1, f[1, 5]}
>
> The definition:
>
> ClearAll[WithMany];
> SetAttributes[WithMany, HoldAll];
> WithMany[args_, body_] :=
> Module[{heldArgs, f, W, structure},
> (* The very first thing that has to happen is to put args into a
> function with a hold attribute like HoldAll. Doing anything else
> means that args will be evaluated. *)
>
> heldArgs = Hold[args];
>
> (* args is coming to us as a list of bindings. We want to replace
> the List with Hold. We can do this because Hold is wrapping
> everything right now. *)
>
> heldArgs = Apply[Hold, heldArgs, {1}];
>
> (* Now we want to take the outermost Hold away so that we're left
> with Hold[bind1,bind2,bind3,...]. *)
> heldArgs = ReleaseHold[heldArgs];
>
> (* Now we want to put each binding inside a List because With
> requires that syntax. *)
> heldArgs = Map[List, heldArgs];
>
> (* Set up a symbol that will serve as a non-evaluating wrapper. *)
>
> SetAttributes[W, HoldAll];
>
> (* Next define a function to use in the Fold operation. This
> function needs to have the attribute HoldAll, otherwise it will
> evaluate its arguments prematurely. *)
> f = Function[
> {bod, binding},
> W[binding, bod],
> {HoldAll}];
>
> (* Use f to Fold W onto the bindings. This will create the correct
> structure without evaluating anything. *)
>
> (* If we had used With directly instead of W, then as soon as the
> first With statement is completely formed it will be evaluated,
> leaving the more outer With statements useless. *)
>
> (* Wrapping body in Unevaluated is neccessary to prevent body from
> being evaluated as soon as it appears in the arguments of Fold. *)
>
> structure = Fold[f, Unevaluated[body], Reverse@heldArgs];
>
> (* The final step is to replace all of the W symbols with With.
> Replacement still works inside of Hold, and the symbol W is local to
> this module so there's no danger of messing up the input. *)
> structure /. W -> With
> ]
>