MathGroup Archive 2009

[Date Index] [Thread Index] [Author Index]

Search the Archive

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
>
>



  • Prev by Date: Re: Bug ??????
  • Next by Date: RootReduce ver 7
  • Previous by thread: Re: Replacement rules that contain function arguments
  • Next by thread: problem about MLPutRealArray