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