# Creating a Block from a list of rules

How can I create a function which works like Block but takes a list of rules as its first argument, rather than a list of assignments?

The function needs to be able to work with rules supplied either as an explicit list or via a symbol, and it should work when some of the symbols to be blocked have global values.

Test code:

a = 100;
code := a + b;
rules := {a -> 1, b -> 2};

(* using an explicit list of rules *)
ruleBlock[{a -> 1, b -> 2}, code]
(* 3 *)

(* using a symbol *)
ruleBlock[rules, code]
(* 3 *)

(* global values are unaffected *)
{a, b}
(* {100, b} *)


I have a working solution (below) but I have had to write separate functions for List and Symbol patterns, and I find the code a bit cumbersome. I would like to know if there is a simpler, cleaner way to write ruleBlock.

SetAttributes[ruleBlock, HoldAll]

ruleBlock[rules_List, code_] :=
Replace[Apply[Set, Hold[rules], {2}], Hold[x_] :> Block[x, code]]

ruleBlock[rules_Symbol, code_] :=
Replace[Apply[Set, OwnValues[rules] /. HoldPattern[{_ :> r_}] :> Hold[r], {2}],
Hold[x_] :> Block[x, code]]

-
You've got a bit of a problem in the case rules assigned to a symbol if the LHS of some of those rules already has a global value, as they will evaluate. How do you want to handle that? – Mr.Wizard Sep 5 '13 at 13:07
Oh, I see you're digging out OwnValues. I forget who I'm talking to as most people wouldn't think to use := to hold a list of values like this, but I would. :-) – Mr.Wizard Sep 5 '13 at 13:10
@Mr.Wizard, the rule list might also be defined with = before the global values are assigned. Ideally there wouldn't be any global values for the LHS of the rules, but I am working with a large body of code written by an incompetent fool (i.e. myself, several years ago...) – Simon Woods Sep 5 '13 at 13:24
You made my profile quotes. :-) – Mr.Wizard Sep 5 '13 at 13:26

## 1 Answer

The only alternative that comes to mind is to use my step function to extract a definition rather than digging around in *Values lists; this has the advantage of being more robust as it will work with other kinds of definitions as well.

SetAttributes[ruleBlock, HoldAll]

ruleBlock[L_List, body_] := Block @@ Join[Apply[Set, Hold[L], {2}], Hold[body]]

ruleBlock[obj_, body_] := step[obj] /. _[x_] :> ruleBlock[x, body]


An extension you may wish to consider is handling for the undocumented := syntax of Block which holds the RHS of assignments. This adds considerable code length but also flexibility. As above but with:

ruleBlock[L_List, body_] := Block @@ Join[
Replace[Hold[L], {(a_ -> b_) :> (a = b), (a_ :> b_) :> (a := b)}, {2}],
Hold[body]
]

-
This is great, thanks. Much more readable than mine, and as you say, more robust. I love the Block @@ Join[Hold[x], Hold[y]] construction - I always forget that Join works with any head. – Simon Woods Sep 5 '13 at 14:24
@Simon You're welcome. I wasn't sure if it would be useful to you. I think I finally figured out what I was trying to do re: :=. One remaining issue: ruleBlock["null", code] returns "null" because "null" is inert. If you want the original expression returned you'll have to add a Condition. – Mr.Wizard Sep 5 '13 at 14:37
Oh it's definitely useful. Another nice feature, I've just realised, is that if I have a chain of definitions like r1:={a->1}; r2:=r1; r3:=r2 I can use r3 and your code will recursively call ruleBlock until the symbol resolves to a list. – Simon Woods Sep 5 '13 at 15:39
@Simon Yes, I should have explicitly stated that. I used it for the that reason in (19900). – Mr.Wizard Sep 5 '13 at 16:02