MathGroup Archive 2000

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

Search the Archive

Re: Flat, OneIdentity attributes

Ersek, Ted R schrieb:
> For the most part I understand how Flat and OneIdentity are related and I
> demonstrate this using Version 4 in the examples below.
> In the first example (f) has the attributes Flat and OneIdentity.
> The pattern matcher treats f[a,2,3] as f[a,f[2,3]] then uses the
> replacement rule and {1,{2,3}} is returned.
> In[1]:=
> ClearAll[f];
> Attributes[f]={Flat,OneIdentity};
> f[1,2,3]//.f[a_,b_]:>{a,b}
> Out[3]=
> {1,{2,3}}
> ---------------------------------------------------
> In the next example the only attribute (f) has is Flat.
> In this case the pattern matcher treats f[1,2,3] as
> f[f[1],f[f[2],f[3]]] then uses the replacement rule and
> {f[1],{f[2],f[3]}} is returned.
> In[4]:=
> ClearAll[f];
> Attributes[f]={Flat};
> f[1,2,3]//.f[a_,b_]:>{a,b}
> Out[6]=
> {f[1],{f[2],f[3]}}
> OneIdentity the pattern matcher doesn't wrap (f) around a single argument
> when it tries different ways of nesting (f).
> --------------------------------
> In the next example (f) has the attributes Flat, OneIdentity and the rule is
> used.
> In[7]:=
> ClearAll[f]
> Attributes[f]={Flat,OneIdentity};
> f[2]/.f[n_Integer]:>n+10
> Out[9]=
> 12
> --------------------------------
> For reasons I can't understand the rule isn't used in the next example. Can
> anyone explain why?
> In[10]:=
> ClearAll[f]
> Attributes[f]={Flat};
> f[2]/.f[n_Integer]:>n+10
> Out[12]=
> f[2]
> ---------------------------------------------
> Regards,
> Ted Ersek
> For Mathematica tips, tricks see

Hello Ted,

the answer to your question is given in The Book, Section 2.3.7 p.274
(4th ed.), where it says:

In an ordinary function that is not flat, a pattern such as x_ matches
an individual argument of the function. But in a function f[a, b, c, ... ]
that is flat, x_ can match objects such as f[b, c] which effectively
correspond to a sequence of arguments. However, in the case where x_
matches a single argument in a flat function, the question comes up as
to whether the object it matches is really just the argument a itself,
or f[a]. Mathematica chooses the first of these cases if the function
carries the attribute OneIdentity, and chooses the second case

You can observe that behaviour, if you take a simple test:
In[1]:= ClearAll[f];
In[2]:= f[a] /. f[x_] :> h[x]
Out[2]= h[a]
-- normal case: f[_] matches f with one argument, x_ matches a
In[3]:= ClearAll[f];
Attributes[f] = {Flat};
In[5]:= f[a] /. f[x_] :> h[x]
Out[5]= h[f[a]]
-- now again  f[_] matches f with one argument, but x_ matches f[a]
because of Attribute Flat (f[a] is converted to f[f[a]] for pattern
In[6]:= ClearAll[f];
Attributes[f] = {Flat, OneIdentity};
In[8]:= f[a] /. f[x_] :> h[x]
Out[8]= h[a]
-- here f[_] matches f with one argument, and x_ matches a_ because of

For your example, Ted, you had Plus[x,10] instead of h[x], which doesn't
change anything, but you had n_Integer instead of x_ here, so n_Integer
could not match f[2] in case of Flat only. The other cases did match

For fun let's look at some other cases:

In[9]:= ClearAll[f];
In[10]:= f[f[a]] /. f[x_] :> h[x]
Out[10]= h[f[a]]
-- ok, clear
In[11]:= ClearAll[f];
Attributes[f] = {Flat};
In[13]:= f[f[a]] /. f[x_] :> h[x]
Out[13]= h[f[a]]
--  because of flatness there can be no difference between this lhs. and
simple f[a] as above in Out[5], so again x_ matches f[a]
Attributes[f] = {Flat, OneIdentity};
In[16]:= f[f[a]] /. f[x_] :> h[x]
Out[16]= h[a]
-- again as above, for the same reason

What happens with two arguments?
In[17]:= ClearAll[f];
In[18]:= f[a, b] /. f[x_] :> h[x]
Out[18]= f[a, b]
-- no match, obviously
In[19]:= ClearAll[f];
Attributes[f] = {Flat};
In[21]:= f[a, b] /. f[x_] :> h[x]
Out[21]= h[f[a, b]]
-- a match: f[_] to f again with *one* argument. but we have two? No,
the lhs. is equivalent to f[f[a,b]] because of flatness and x_ matches
In[22]:= ClearAll[f];
Attributes[f] = {Flat, OneIdentity};
In[24]:= f[a, b] /. f[x_] :> h[x]
Out[24]= h[f[a, b]]
-- OneIdentity is not involved here

A variant
In[57]:= ClearAll[f];
In[58]:= f[a, f[b]] /. f[x_] :> h[x]
Out[58]= f[a, h[b]]
-- f[x_] matches f[b]
In[59]:= ClearAll[f];
Attributes[f] = {Flat};
In[61]:= f[a, f[b]] /. f[x_] :> h[x]
Out[61]= h[f[a, b]]
-- f[a,f[b]] is equivalent to f[f[a,b]]
In[62]:= ClearAll[f];
Attributes[f] = {Flat, OneIdentity};
In[64]:= f[a, f[b]] /. f[x_] :> h[x]
Out[64]= h[f[a, b]]
-- same here

Interestingly things are somewhat different with BlankSequence[]
In[27]:= ClearAll[f];
Attributes[f] = {Flat};
In[29]:= f[a] /. f[x__] :> h[x]
Out[29]= h[a]
-- f[f[a]] is not tried here, x__ matches directly to a. ReplaceList
shows this is the only match.

In[35]:= ClearAll[f];
Attributes[f] = {Flat};
In[37]:= f[f[a]] /. f[x__] :> h[x]
Out[37]= h[a]
-- this match is consistent with Out[29], as it should

In[43]:= ClearAll[f];
Attributes[f] = {Flat};
In[45]:= f[a, b] /. f[x__] :> h[x]
Out[45]= h[a, b]
-- now x__ matches the Sequence[a, b], again consistent with Out[29]

In[51]:= ClearAll[f];
Attributes[f] = {Flat};
In[53]:= f[a, f[b]] /. f[x__] :> h[x]
Out[53]= h[a, b]
-- no surprise

In all these test cases here with Pattern[x, BlankSequence[]] there is
no difference between Attributes[f] = {Flat} and Attributes[f] = {Flat,

Kind regards, yours

  • Prev by Date: Re: Flat, OneIdentity attributes
  • Next by Date: Cell Group
  • Previous by thread: Flat, OneIdentity attributes
  • Next by thread: Re: Flat, OneIdentity attributes