Different behaviours of Default Argument

8

2

I don't really understand the behaviour of Default Argument. If I execute this command in Mathematica:

In: {f[a], f[a + b]} /. f[x_ + y_.] -> p[x, y]  

Out: {p[a, 0], p[b, a]}

Why is the a and b swapped?

How can I explain the different behaviour of the above compared with the each of the following:

In: {f[a], f[a + b]} /. f[x_ + y_] -> p[x, y]  

Out: {f[a], p[a, b]}

In: {f[a], f[a + b]} /. f[x_. + y_] -> p[x, y]  

Out: {p[0, a], p[a, b]}

In: {f[a], f[a + b]} /. f[x_. + y_.] -> p[x, y]  

Out: {p[a, 0], p[a, b]}

And similarly for:

In: {f[a], f[a b]} /. f[x_ y_.] -> p[x, y]  

Out: {p[a, 1], p[b, a]}

In: {f[a], f[a b]} /. f[x_  y_] -> p[x, y]

Out: {f[a], p[a, b]}

In: {f[a], f[a b]} /. f[x_. y_] -> p[x, y]

Out: {p[1, a], p[a, b]}

In: {f[a], f[a b]} /. f[x_. y_.] -> p[x, y]

Out: {p[a, 1], p[a, b]}

From Mathematica help, what I understand is that Mathematica will return the default value if the argument of _. is not inputted. But I still cannot make the above statements any sense. Besides the obvious observable output such as reordering, I don't really understand the logic behind _. How does it relate to sum and multiplication? When will _. be useful in other than this situation?

Thanks.

user71346

Posted 2013-05-19T02:56:30.813

Reputation: 395

1A look at the output of TracePrint[{f[a], f[a + b]} /. f[x_ + y_.] -> p[x, y]] shows that there is some reordering done; that is, x_ + y_. is automagically reordered as y_. + x_, since Plus[] is orderless, and I'm guessing Optional[] comes before Pattern[] in canonical order. – J. M.'s ennui – 2013-05-19T03:16:48.823

@J.M. Thanks. I know it is reordered, but what is the logic behind it. Why adding _. can reorder it, why it is only the first case that a and b are reordered? – user71346 – 2013-05-19T04:56:50.223

1I did give my guess that Optional[] (y_. is internally represented as Optional[Pattern[y, Blank[]]]) comes before Pattern[] (x_ is internally represented as Pattern[x, Blank[]]) in canonical order, which is why you're seeing the reordering. But there might be a deeper explanation... – J. M.'s ennui – 2013-05-19T04:58:43.867

4Both Times[] and Plus[] are Orderless (use Attributes[] to see this), so they both sort their arguments for the purpose of having a canonical form. – J. M.'s ennui – 2013-05-19T05:10:49.760

Answers

6

Good question. I see this was largely answered in the comments yesterday, but since no one posted a formal answer I shall.

Cases 2, 3, and 4 appear relatively straightforward. (Incidentally you should be using :>, RuleDelayed here, rather than ->, to localize the pattern names x and y.) The first case that swaps positions needs a closer look however. First, observe this case:

{f[c], f[c + b]} /. f[x_. + y_.] :> p[x, y]
{p[c, 0], p[b, c]}

This is because the LHS of /. is evaluated before matching, and f[c + b] evaluates to f[b + c]. This is because of the Orderless attribute of Plus.

Considering the first case, the RHS of /. is also evaluated, and again reordering (sorting) takes place:

Trace[
 {f[a], f[a + b]} /. f[x_ + y_.] :> p[x, y]
] // Column
{{{x_ + y_., y_. + x_}, f[y_. + x_]}, f[y_. + x_] :> p[x, y], f[y_. + x_] :> p[x, y]}
{f[a], f[a + b]} /. f[y_. + x_] :> p[x, y]
{p[a, 0], p[b, a]}

Here f[x_ + y_.] evaluates to f[y_. + x_]. You need to prevent the evaluation of Plus if you do not want this ordering to take place. On the left side this can be done with Unevaluated:

Unevaluated[{f[c], f[c + b]}] /. f[x_. + y_.] :> p[x, y]
{p[c, 0], p[c, b]}

It is however ineffective on the right side:

{f[a], f[a + b]} /. Unevaluated[f[x_ + y_.] :> p[x, y]]
{p[a, 0], p[b, a]}

Surprisingly, so is HoldPattern:

{f[a], f[a + b]} /. HoldPattern[f[x_ + y_.]] :> p[x, y]
{p[a, 0], p[b, a]}

I don't know why. Perhaps there is an evaluation leak within ReplaceAll that causes this to evaluate anyway, or more likely I am forgetting something about the interaction of pattern matching and the Orderless attribute.

Mr.Wizard

Posted 2013-05-19T02:56:30.813

Reputation: 259 163

+1. It seems that it is a bug in pattern matcher: defining HoldPattern@f[x_ + y_: 0] := p[x, y] and then evaluating f[a + b] gives p[b, a]. And with f[Unevaluated[Plus[x_, y_: 0]]] := p[x, y] we can create the definition f[x_+(y_:0)]:=p[x,y]. But it also gives p[b, a]. The same is true for definitions f[HoldPattern[Plus[x_, y_: 0]]] := p[x, y] and f[HoldPattern[Plus][x_, y_: 0]] := p[x, y]. – Alexey Popkov – 2013-05-20T10:17:35.443

@Alexey Is there perhaps some property of Orderless or Flat, etc., that would explain this? There are aspects of the pattern matcher that are not obvious. e.g. http://mathematica.stackexchange.com/a/18068/121

– Mr.Wizard – 2013-05-20T10:32:02.703

3@AlexeyPopkov, I don't think it's a bug. HoldPattern prevents evaluation of the pattern (compare Unevaluated[Print[a + b]] /. HoldPattern@Print[y_ + x_] :> p[x, y] with and without the HoldPattern) but I don't believe it is intended to prevent the pattern matcher from respecting the Orderless attribute. Remember that ReplaceAll is just using the first of potentially multiple ways to match the pattern. If you use ReplaceList instead of ReplaceAll in the examples, the results don't seem so odd. – Simon Woods – 2013-05-20T11:33:22.503

@Simon Probably you are right. But how to prevent applying attributes? – Alexey Popkov – 2013-05-20T14:57:32.510

Mr Wizard, you used this property of Orderless in a nice answer of yours, that I think I bountied. – Rojo – 2013-05-20T15:35:35.727

2@AlexeyPopkov I'm not sure it is possible other than blocking the attribute. Probably you shouldn't use Orderless on symbols where you care about the ordering. You could, but I don't think it's a good habit, try to make the "first thing tried" be the one you want. In this case you could do it by using {f[a], f[a + b]} /. HoldPattern[f[HoldPattern[x_] + y_.]] :> p[x, y] – Rojo – 2013-05-20T15:37:02.797

1Optional[...] is sorted before Pattern[...], but after HoldPattern[...] – Rojo – 2013-05-20T15:37:50.643

@Rojo Interesting idea, thank you. In this particular case this solution looks reliable because it is based on documented canonical order. – Alexey Popkov – 2013-05-20T15:55:20.570

@Rojo I am familiar with the basic effect of Orderless on pattern matching as you know; what I am not sure about is the order in which possibilities are themselves checked. Your variation to match this particular order is clever; thanks for posting it. – Mr.Wizard – 2013-05-21T05:29:26.117