19
$\begingroup$

How can we define a function that works like f[x_]=ComputeSomething[x] and treats x as a variable that does not have a value? We could call this function LocalSet and the computation should be done when the assignment is made as in the following example.

var=3;
LocalSet[f[var_],Normal[Series[Exp[var],{var,0,3}]]];
DownValues[f]

(*
---> {HoldPattern[f[var_]]:>1+var+var^2/2+var^3/6}
*)

var
(*
---> 3
*) 

Notice I don't want to be limited to a pattern variable (x_). The function called LocalSet should figure out what symbols are used for patterns and evalute the right side with those variables in a Block construct.

$\endgroup$
0

1 Answer 1

16
$\begingroup$

Perhaps something like this:

SetAttributes[localSet, HoldAll]

localSet[lhs_, rhs_] := 
  Union @@ Cases[
    Unevaluated[lhs], 
    Verbatim[Pattern][p_, _] :> HoldComplete[p],
    Infinity,
    Heads -> True
  ] /. _[x___] :> Block[{x}, lhs = rhs;]

Test:

var=3;
localSet[f[var_],Normal[Series[Exp[var],{var,0,3}]]]
DownValues[f]
{HoldPattern[f[var_]] :> 1 + var + var^2/2 + var^3/6}
$\endgroup$
11
  • $\begingroup$ I came up with almost exactly the same code. Hope you don't mind my edit to make it work in more general cases and avoid returning a value. $\endgroup$
    – Szabolcs
    Feb 19, 2012 at 9:40
  • 2
    $\begingroup$ It not only about returning a value. It's about evaluating the expression, which might have side effects or unintended consequences. Consider f[x_?NumericQ] := (Print["numeric"]; x); n = 5; localSet[g[n_], f[n]], which has different behaviour when the semicolon is omitted. I think it's important here that the expression not be evaluated with n having a value---there's no telling what that might lead to. $\endgroup$
    – Szabolcs
    Feb 19, 2012 at 12:12
  • 1
    $\begingroup$ +1. I would write the same code, except including Heads->True option in Cases, if you want to cover SubValues. Right now an attempt to assign to say f[var_][1] will produce an error. If you want to be totally safe, I'd also use HoldComplete in place of Hold. $\endgroup$ Feb 19, 2012 at 13:54
  • 1
    $\begingroup$ @Mr.Wizard The possible troublesome symbols will be deeper than level one during the call to localSet[f[...],rhs], because they will be inside f. So, as long as localSet is HoldAll, you don't have to care about them, exactly due to the depth-1 limitation for UpValues search. But when you destructure, you have Hold[sym], and here HoldComplete is essential. $\endgroup$ Feb 19, 2012 at 20:56
  • 1
    $\begingroup$ Well, to make it a little bit moore robust it would be better to use a preorder ReplaceAll based Cases that stops inside Verbatims. Something along the lines of Module[{tag},Reap[Unevaluated[lhs]/.{i_Verbatim:>i, Verbatim[Pattern][p_, _]/;Sow[HoldComplete[p], tag]:>Null}, tag][[1, -1]]] $\endgroup$
    – Rojo
    Jul 19, 2013 at 17:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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