2
$\begingroup$

For example, I have

varList={"a1","a2",...}

a1, a2,... are all variables, they maybe assigned values already.

What I want to do is temporarily Block all variables in varList for a segment of my code. This means equivalent to Block[{a1,a2,...},other code].

So maybe a function myBlock similar to Block,

myBlock[varList,other code]

How to do this?

$\endgroup$
6
$\begingroup$
myBlock // ClearAll

myBlock // Attributes = {HoldAll};

  (*for a standardBlock syntax *)
myBlock[varList : {(_Symbol | _Set) ..}, code_] := Block[varList, code]


  (*for string spec hidden in a symbol *)
myBlock[varList_Symbol, code_] /; ValueQ[varList] := myBlock[Evaluate@varList, code]


  (* for list of string specs*)
myBlock[varList : {__String}, code_] := 
  Join @@ ToExpression[varList, StandardForm, Hold] /. 
  Hold[vars__] :> Block[{vars}, code]

a1 = 1

{ myBlock[{"a1"}, a1 = 2; a1], a1 }

{ myBlock[{a1}, a1 = 3; a1]  , a1 }

{ myBlock[{a1 = 4}, a1]      , a1 }

{ myList = {"a1"}
; myBlock[myList, a1 = 5; a1], a1 }

{ myList = {"a1 = 6", "a2"}
; myBlock[myList, a1]        , a1 }

1

{2,1}

{3,1}

{4,1}

{5,1}

{6,1}

$\endgroup$
  • 1
    $\begingroup$ You could make use of the Listable attribute of ToExpression, e.g., ToExpression[varList,StandardForm,Hold] $\endgroup$ – Carl Woll Jan 22 '18 at 18:04
  • $\begingroup$ @CarlWoll +1 sure I could, If I only knew. All those years of mapping ;( $\endgroup$ – Kuba Jan 22 '18 at 19:02
  • $\begingroup$ Thank you so much! Learned a lot. I took some time rereading Wagner's "power programming...", finally has some progress in understanding Hold stuff(which should be know years ago) , and came out my version as an answer. What is more, I actually struggled to construct a function let's call it convert, so that Block[Evaluate@convert@varList,code] will work. But I failed, so I thought maybe it is not possible for such convert function, what do you think? : ) $\endgroup$ – matheorem Jan 23 '18 at 8:09
  • $\begingroup$ @Kuba Oh, there is also string mix symbol case missing, though rare, but... $\endgroup$ – matheorem Jan 23 '18 at 8:42
  • $\begingroup$ @Kuba I updated a unified version. Now it is fully settled down :) $\endgroup$ – matheorem Jan 23 '18 at 14:37
1
$\begingroup$

This answer is enlightened by Kuba. Thanks.

update

By utilizing RowBox and the fact that ToString doesn't change string. I provide a unified version of myBlock with a single definition that is fully compatible with built-in Block, and at the same time support list of symbols in string form or a list of mixture of symbol and string form(currently not supported by Kuba's version).

ClearAll[myBlock];
SetAttributes[myBlock, HoldAll];
myBlock[varList_, code_] := 
  Module[{toStringWithHold, varStringList, holdVars},
   toStringWithHold = Function[x, ToString[Unevaluated[x]], {HoldAll}];
   varStringList = toStringWithHold /@ Unevaluated[varList];
   varStringList = 
    Flatten@StringSplit[Riffle[varStringList, ","], "=" -> "="];
   holdVars = 
    ToExpression[RowBox@Prepend[Append[varStringList, "}"], "{"], 
     StandardForm, Hold];
   holdVars /. Hold[x_] :> Block[x, code]];

It uses RowBox technique, also thanks to Kuba

So now take a look at below

a1 = 100;
a2 = 200;
{myBlock[{a1, a2}, a1 = 1; a2 = 2; {a1, a2}], {a1, a2}}
{myBlock[{"a1", "a2"}, a1 = 1; a2 = 2; {a1, a2}], {a1, a2}}
{myBlock[{"a1", a2}, a1 = 1; a2 = 2; {a1, a2}], {a1, a2}}
{myBlock[{"a1=1", a2 = 2}, {a1, a2}], {a1, a2}}
{varList = {"a1", "a2"}; myBlock[varList, a1 = 1; a2 = 2; {a1, a2}], {a1, a2}}
{varList = {"a1=1", "a2=2"}; myBlock[varList, {a1, a2}], {a1, a2}}

They all gives

{{1, 2}, {100, 200}}

Which means that myBlock correctly block variables, and doesn't affect global value.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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