Re: Flat riddle
- To: mathgroup@smc.vnet.net
- Subject: [mg11505] Re: Flat riddle
- From: Ersek_Ted%PAX1A@mr.nawcad.navy.mil
- Date: Fri, 13 Mar 1998 12:21:57 -0500
Continuing with the detailed reply from Robby Villegas: I said: ******************* |> At http://www.wolfram.com/support/Kernel/Symbols/findsymbol.cgi |> Wolfram Research Technical Support points out that you will run into |> trouble if you have a function (f) with the Flat attribute, and the |> rule ( f[p_]:=p ). |> If (f) has these properties then ( f[1,2] ) will result in infinite |> iteration. | | Robby said: ******************* |If you want f to ungroup its arguments that have head f, and also to |act as the identity on a single argument, I recommend that you avoid |attributes and use definitions instead. Here is a foundation that |I think will establish the basic properties you want for f: | | ClearAll[f] | | f[elems___] /; MemberQ[Unevaluated[{elems}], _f] := | Flatten[Unevaluated @ f[elems], Infinity, f] | | f[singleton_] := singleton | | f[] = 0 (* Degenerate case: replace 0 with whatever you like *) | |From here, you can add definitions for several arguments that have the |luxury of assuming a canonical form where arguments don't have head f. |For instance, I think this one will implement the formula you wanted: | | f[p1_, p2_, q_] := {f[p1, p2], q} | |As a rule of thumb, if I want f to group its arguments, I prefer to do this |myself with definitions that make the intention explicit, rather than |leaving it up to the Flat attribute, which has a pre-set order for trying |groupings. | | Now I reply with: ***************** I used that example to demonstrate that the Flat attribute I gave (f) did affect pattern matching for expressions with the head (f). If (f) is Flat the pattern matcher will try to find a way to "unflatten" (f) to make it fit a pattern. I wanted to give my function (f) this capability. Maybe it is impossible to make a user defined function that can do the things Plus and Times can do. Specifically, I would want the following: (1) Layers of (f) are flattened during evaluation. (2) The pattern matcher "unflattens" (f) to make a pattern match. (3) ( ClearAll[p]; f[p] ) evaluates to (p). (4) ( ClearAll[a,b]; f[a,b] ) does not lead to infinite iteration. I don't have a need for this capability. I just find it disconcerting that a user can't create a function that has the same nuances as Plus and Times. Robby also wrote: *************** | |There is an undocumented hack that I want to warn you against because I |have seen it proposed from time to time. Relying on it in your code is |risky, since its behavior may change some day. The hack is to set the |attributes after the making the function definitions. | |(* risky *) h[] = 0; | |(* risky *) h[x_] := x | |(* risky *) h[p1_, p2_, q_] := {h[p1, p2], q} | |(* risky *) Attributes[h] = Flat; | | |In[14]:= ClearAll[h] | |In[15]:= h[] = 0; | |In[16]:= h[x_] := x; | |In[17]:= h[p1_, p2_, q_] := {h[p1, p2], q} | |In[18]:= Attributes[h] = Flat; | |In[19]:= {h[], h[1], h[1, 2], h[1, 2, 3], h[h[1], h[2, 3]]} | |Out[19]= {0, 1, h[1, 2], {h[1, 2], 3}, {h[1, 2], 3}} | | I found that when I do this (h) is Flat for evaluation purposes, but the pattern matcher doesn't "unflatten" (h) to make an expression match a pattern. | |> One Mathematica expert has told me it's impossible. I couldn't believe |> it, so I continued searching for a solution. I think I found one. |> |> In[1]:= |> $Post=ReplaceAll[#,f[a_]->a]&; |> Attributes[f]={Flat,OneIdentity}; | | |One problem I have with this, and I gather it makes you uncomfortable, too, |is that it clobbers $Post to implement simplification of a specific |function. What if you have fifteen functions where you're having |difficulty getting simplifications to work? Do you keep adding rules |to $Post? | ******************************** Yes. That is way I asked the group to suggest a better approach. | |A deeper problem with it is the ReplaceAll, which replaces all f[a_] |everywhere in the expression, even if you purposely wrapped them in |Hold, or used them in something like the body of Function where they |are supposed to remain unevaluated: | |In[1]:= $Post = ReplaceAll[#, HoldPattern[f[a_]] :> a]&; | |In[2]:= Attributes[f] = {Flat, OneIdentity}; | |In[3]:= f[p_, q_] := {p, q} /; Length[p] == 2 | |In[4]:= Hold[ f[1], f[2, 3, 4] ] | |Out[4]= Hold[1, f[2, 3, 4]] | |It's even difficult to see what rule is attached to $Post now: | |In[5]:= $Post | |Out[5]= #1 /. HoldPattern[a_] :> a & | *********************************** I hadn't thought of all this. It's pretty scary! | |It's better to set things up so the rewrites occur within the normal |evaluation procedure. | ************************************ I agree. Ted Ersek