9

The document says:

OneIdentity is an attribute that can be assigned to a symbol f to indicate that f[x], f[f[x]], etc. are all equivalent to x for the purpose of pattern matching.

Consider the expressions below:

In[1]:= SetAttributes[f, OneIdentity]
In[2]:= Nest[f, x, 10]    
Out[2]= f[f[f[f[f[f[f[f[f[f[x]]]]]]]]]]

We cannot get f[x] as the document says.

In[1]:= MatchQ[x, Times[n_. , x_]]
Out[1]= True

Also, the example in the document seems a little confusing. What does the pattern Times[n_.,x_] mean?

I'm quite confused about it. Please explains this.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Nate
  • 193
  • 3
  • 5
    It treats the expression as equivalent to x for the purpose of pattern matching. It doesn't evaluate to x. – march Aug 20 '16 at 05:11

1 Answers1

8

What the documentation means is that for a symbol f with attribute OneIdentity, pattern forms like f[_.,x], f[_.,f[_.,x]], etc. (Note the Possible Issues section!) will not only match expression like f[4,a] but also an expression without a Head f.

Take the CirclePlus, which has no built-in meaning or any attribute, as an example.

Clear[CirclePlus]
ClearAttributes[CirclePlus, Attributes@CirclePlus];
DefaultValues[CirclePlus] = {};
Attributes[CirclePlus]
{}

This will work as expected:

k⊕y /. a_⊕x_ :> {a, x}
k⊕y /. a_.⊕x_ :> {a, x}
{k, y}
{k, y}

But this won't work because a_.⊕x_ or (a_:1)⊕x_ won't match y:

y /. a_.⊕x_ :> {a, x}
y /. (a_: 1)⊕x_ :> {a, x}
y
y

Instead of introducing a special rule like x_:>{1,x}, we can add the OneIdentity to CirclePlus:

SetAttributes[CirclePlus, OneIdentity]

Now this works as well:

y /. (a_: 1)⊕x_ /; (Echo[a]; True) :> {a, x}
1
{1, y}

This still won't work

y /. a_.⊕x_ :> {a, x}

until CirclePlus gets DefaultValues:

Default[CirclePlus] := RandomReal[];

Now a_.⊕x_ will match y:

y /. a_.⊕x_ /; (Echo[a]; True) :> {a, x}
0.217426
{0.217426, y}

And nested CirclePlus will also match y:

y /. a_.⊕(b_.⊕x_) /; (Echo[{a, b}]; True) :> {a, b, x}
{0.934169, 0.157904}
{0.934169, 0.157904, y}
y /. a_.⊕(x_⊕b_.) /; (Echo[{a, b}]; True) :> {a, b, x}
{0.319821, 0.490549}
{0.319821, 0.490549, y}

or match 4⊕y:

4⊕y /. a_.⊕(x_⊕b_.) /; (Echo[{a, b}]; True) :> {a, b, x}
{4, 0.861579}
{4, 0.861579, y}
Silvia
  • 27,556
  • 3
  • 84
  • 164