Re: Replacement rules that contain function arguments
- To: mathgroup at smc.vnet.net
- Subject: [mg105359] Re: [mg105317] Replacement rules that contain function arguments
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Sun, 29 Nov 2009 05:11:25 -0500 (EST)
- References: <200911280604.BAA01286@smc.vnet.net>
Hi Leo, If you insist on breaking the scope in such a way (by essentially mixing lexical scope with globals), then your solution With Block seems pretty much the easiest. If you are willing to name your formal parameter differently - say <kk> (and there should be no reason why not), then the following will also work: rrules := {kij :> Table[k[[i]] k[[j]], {i, 1, 3}, {j, 1, 3}]} foo[kk_] := kij /. (rrules /. HoldPattern[k] :> kk); foo[{1, 1, 1}] You can automate the above construction with a bit of meta - programming: if you always have some expression to which you want to apply some rules, then the following function generator will do: ClearAll[makeF]; SetAttributes[makeF, HoldAll]; makeF[fname_Symbol[vars : __Symbol], expr_, rules_] := Module[{varspt = List @@ Map[HoldPattern, Hold[vars]], newvars = List @@ Map[Unique, Hold @@ Map[Unevaluated, Unevaluated[{vars}]]], }, ClearAll[fname]; With[{pattern = Sequence @@ Map[Pattern[#, Blank[]] &, newvars], crules = Thread[varspt -> newvars]}, fname[pattern] := expr /. (rules /. crules)]]; For example: In[1] := Clear[i, j, k, fn,kij,q,ffn]; i = 1; j = 2; k = 3; kij = 4; q = 5; rrules := {kij :> Table[k[[i]] k[[j]], {i, 1, 3}, {j, 1, 3}]} rrulesNew := {kij :> Table[k[[i]] q[[j]], {i, 1, 3}, {j, 1, 3}]} makeF[fn[k], kij, rrules]; ?fn Global`fn fn[k$760_]:=kij/.(rrules/.{HoldPattern[k]->k$760}) In[2]:= fn[{1,2,3}] Out[2]= {{1,2,3},{2,4,6},{3,6,9}} In[3]:= makeF[ffn[k,q],kij,rrulesNew]; In[4]:= ffn[{1,2,3},{7,8,9}] Out[4]= {{7,8,9},{14,16,18},{21,24,27}} I gave the symbols global definitions to demonstrate that we ignore possible global values in our construction, without the use of dynamic scoping. You just have to define your function (the first parameter of our function generator) with parameters exactly matching (by name) the symbols which you want to be substituted (that seems to be what you want). You can get a bit fancier and define your own syntactic sugar like this: ClearAll[applyGlobal]; applyGlobal /: SetDelayed[f_[args__], applyGlobal[expr_, rules_]] := With[{vars = Hold[args] /. Verbatim[Pattern][var_, Blank[]] :> var}, Function[Null, makeF[f[##], expr, rules], HoldAll] @@ vars]; With this, you can define your function in a way that will look familiar: In[5]:= Clear[fffn]; fffn[k_] := applyGlobal[kij, rrules] In[6]:= ?fffn Global`fffn fffn[k$832_]:=kij/.(rrules/.{HoldPattern[k]->k$832}) In[7]:= fffn[{1,2,3}] Out[7]= {{1,2,3},{2,4,6},{3,6,9}} But you can see the main problem of this approach just by looking at the definition of fffn: the pattern variable on the left can be found nowhere on the right. So, one thing you still must ensure is that the names of your variables on the l.h.s (with patterns) will match exactly the names used in your global rules. Therefore, this is still more error-prone than the good old lexical scoping. You may ask yourself whether the convenience of using this kind of constructs (which mix globals with lexical scoping) will outweigh the possibility of errors. For interactive small projects, that may occasionally be the case. For larger projects, if I were you, I probably wouldn't bother using them. Hope this helps. Regards, Leonid On Fri, Nov 27, 2009 at 10:04 PM, Leo Alekseyev <dnquark at gmail.com> wrote: > Dear Mathgroup, > > I am trying to understand what happens when a pattern from function > definition appears in the list of replacement rules. In particular, > consider this: > > (* Example (A): *) > Clear[foo,kij,k]; > foo[k_] := kij /. {kij :> Table[k[[i]] k[[j]], {i, 1, 3}, {j, 1, 3}]} > foo[{1, 1, 1}] > (* gives {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}} as expected *) > > (* But now, let's put replacement rules into a variable: *) > (* Example (B): *) > rrules := {kij :> Table[k[[i]] k[[j]], {i, 1, 3}, {j, 1, 3}]} > foo[k_] := kij /. rrules > foo[{1, 1, 1}] > (* rrules gets evaluated first, hence this fails *) > > My question is -- is there a good way to control evaluation such that > even though rules are defined in a variable, evaluation proceeds as in > Example (A)? > > Below are a couple of things I found to work, but they are somewhat > syntactically cumbersome. > > (* Example (C): works, but have to manually turn off messages *) > foo[k_] := Evaluate[Off[Part::"partd"]; kij /. rrules]; On[ > Part::"partd"] > foo[{1, 1, 1}] > > (* Example (D): works, but have to rename function argument and wrap > in a block *) > foo[kk_] := Block[{k = kk}, kij /. rrules]; > foo[{1, 1, 1}] > > Thanks, > --Leo > >
- References:
- Replacement rules that contain function arguments (evaluation order)
- From: Leo Alekseyev <dnquark@gmail.com>
- Replacement rules that contain function arguments (evaluation order)