Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm trying to have several initializer lists in a With function and choose which one I want to use. So far I have this:

With[Evaluate@{Unevaluated@{a = 2, b = 3}, Unevaluated@{a = 4, b = 6}}[[1]], a + b]

which doesn't work on a pretext that "Local variable specification Unevaluated[{a=2,b=3}] is not a List.", and gives me With[Unevaluated[{a = 2, b = 3}], a + b] for an answer. Now, if I just feed this same purportedly erroneous expression back to the kernel, it evaluates just fine with the correct result of 5, showing that Unevaluated list not being a list is a rather moot point. But how do I connect Unevaluated with With without me in between?

share|improve this question
    
What are you trying to accomplish? Your series of Evaluate and Unevaluated seem designed to confuse. –  bill s Jul 1 '13 at 16:37
    
I want to calculate either With[{a = 2, b = 3}, a+b] or With[{a = 4, b = 5}, a+b], selecting which one I want in a single place. –  panda-34 Jul 1 '13 at 16:44
    
case[1] := {a -> 2, b -> 3}; case[2] := {a -> 4, b -> 6}; a + b /. case[2] What do you mean by a single place? –  BlacKow Jul 1 '13 at 16:50
    
What is the criteria by which you sill select the first or the second With? –  bill s Jul 1 '13 at 17:07
    
Maybe you can have Module instead of With? selector[n_] := Module[{}, case = {{a -> 2, b -> 3}, {a -> 4, b -> 6}}; a + b /. case[[n]]]; selector /@ {1, 2} –  BlacKow Jul 1 '13 at 17:09

2 Answers 2

up vote 10 down vote accepted

You can use injector pattern for that:

{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[1]] /. Hold[init_] :> With[init, a + b]

(* 5  *)

{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[2]] /. Hold[init_] :> With[init, a + b]

(* 10 *)

but you can see that Hold is preferred over Unevaluated in such cases.

As an alternative, you can define your own version of With, that would take the held version of initialization:

ClearAll[with]; 
SetAttributes[with, HoldRest];
with[Hold[init_], body_] := With[init, body];

and then

with[{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[1]], a + b]

(* 5 *)

with[{Hold[{a = 2, b = 3}], Hold[{a = 4, b = 6}]}[[2]], a + b]

(* 10 *)

EDIT

As a bonus, here is a way to use your code verbatim - wrap it in Block:

Block[{With},        
    SetAttributes[With,HoldAll];        
    With[Evaluate[{Unevaluated[{a=2,b=3}],Unevaluated[{a=4,b=6}]}[[2]]],
        a+b
    ]
]

(* 10 *)

The explanation of why this works is left as an exercise to the reader :)

share|improve this answer
    
Thanks!, now by using Thread[Hold[{{a = 2, b = 3}, {a = 4, b = 6}}]], I can have all initializers in a nice single matrix. –  panda-34 Jul 1 '13 at 17:37
    
@panda-34 Yes, that's right. Thanks for the accept. –  Leonid Shifrin Jul 1 '13 at 17:39

Variations of this question have been asked before, e.g.: How to set Block local variables by code?
You may also find this question (and linked) of interest: Assigning values to a list of variable names

Your question stands out because of your use of Unevaluated and the confusion that arises. It is key to understand that Unevaluated must appear as the explicit head of an argument before evaluation for it to be stripped. For this an other details of the use of Unevaluated please read this.

In this case you can use Function or (another) With to pass your extracted Unevaluated expression to With:

sets = {Unevaluated@{a = 2, b = 3}, Unevaluated@{a = 4, b = 6}};

With[#, a + b] &[First @ sets]

With[{x = First @ sets}, With[x, a + b]]
5

5

You could also leverage this property of Part to avoid having to apply Unevaluated (or Hold) to every set list manually. Note that with Unevaluated you need the outer { } to prevent this evaluating inside Set.

sets = {Unevaluated[{a = 2, b = 3}, {a = 4, b = 6}]};  (* ignore syntax warning *)

With[#, a + b] &[sets[[1, {1}]]]
With[#, a + b] &[sets[[1, {2}]]]
5
10

Or using the injector pattern than Leonid showed and Hold:

sets = Hold[{a = 2, b = 3}, {a = 4, b = 6}];

sets[[{1}]] /. _[x_] :> With[x, a + b]
sets[[{2}]] /. _[x_] :> With[x, a + b]
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.