2

I'd a like a function that assigns variables based on a rule list. That is,

SetParameters[{x->1, y->2}]

would set x=1 and y=2. The problem is when x and y already have values, this understandably leads to Set::setraw: Cannot assign to raw object 1. errors. Is there a way around this using non-standard evaluation?

My attempt so far, which doesn't work:

Clear[SetParameters];
SetAttributes[SetParameters, HoldAll];
SetParameters[rulelist_] := Module[{vars},
  vars = Unevaluated[rulelist][[All, 1]];
  Print[vars];
  Set[Evaluate@vars, rulelist[[All, 2]]];
]

Additional wrinkle:

@J.M.'s suggestion in the comments answered my original question, but afterwards I uncovered a complication: What if I want to define the rulelist ahead of time? E.g., rl = {x->1, y->2}; SetParameters[rl] Any way to make that work?

Chris K
  • 20,207
  • 3
  • 39
  • 74

1 Answers1

1

I'd use Mr.Wizard's step[] function for the most generality.

(* https://mathematica.stackexchange.com/a/1447 *)
step // ClearAll;
SetAttributes[step, HoldAll]
step[expr_] := Module[{P}, P = (P = Return[#, TraceScan] &) &;
   TraceScan[P, expr, TraceDepth -> 1]];

setParameters // ClearAll; SetAttributes[setParameters, HoldAll]; setParameters[rulelist : {__Rule}] := Hold[rulelist;] /. Rule -> Set // ReleaseHold; setParameters[rulelist_] := With[{r = step[rulelist]}, setParameters @@ r /; Head[r] === HoldForm];

Examples:

Clear[x, y];
rl = {x -> 1, y -> 2};
setParameters[rl]
{x, y}
(*  {1, 2}  *)

Clear[x, y, foo]; x = 1; y = 2; foo[a_, b_] := {x -> a, y -> b}; setParameters[foo[11, 22]] {x, y} (* {11, 22} *)

Clear[nada, rien]; nada = rien; setParameters[nada] (* setParameters[rien] *)

Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • An alternative to step[], but not as general: setParameters[rulelist_Symbol] := With[{r = Hold[rulelist] /. OwnValues[rulelist]}, setParameters @@ r /; Hold[rulelist] =!= r]; – Michael E2 Jun 10 '21 at 04:00
  • I can't get the alternative in your comment to work (just returns unevaluated) but the main answer in the text seems perfect. Thanks! – Chris K Jun 11 '21 at 19:47
  • @ChrisK It should work for rl but not for foo[11, 12]. That's the "not as general" restriction. You also need the setParameters[rulelist : {__Rule}] := Hold[rulelist;] /. Rule -> Set // ReleaseHold; def. to go with the OwnValues one in my first comment. – Michael E2 Jun 11 '21 at 20:00
  • Got it, that was the part I was missing. – Chris K Jun 11 '21 at 20:03