Optional argument doesn't take effect in function definition

See my following code snippet:

In[160]:= f[{x__?MatrixQ} | x__?MatrixQ, y_ : 0] := {{x}, y}
f[IdentityMatrix[2]]
f[IdentityMatrix[2], b]
f[IdentityMatrix[2], IdentityMatrix[2]]

Out[161]= {{{{1, 0}, {0, 1}}}, 0}

Out[162]= {{{{1, 0}, {0, 1}}}, b}

Out[163]= {{{{1, 0}, {0, 1}}}, {{1, 0}, {0, 1}}}

Why did the optional parameter not take effect on the last call?

Regards,
Zhao

It matches either way. Possibly using Longest will force the match you prefer.

I tried with the following, but didn’t see any effect:

In[697]:= f[{x__?MatrixQ} | Longest[x__]?MatrixQ, y_ : 0] := {{x}, y}
f[IdentityMatrix[2]]
f[IdentityMatrix[2], b]
f[IdentityMatrix[2], IdentityMatrix[2]]

Out[698]= {{{{1, 0}, {0, 1}}}, 0}

Out[699]= {{{{1, 0}, {0, 1}}}, b}

Out[700]= {{{{1, 0}, {0, 1}}}, {{1, 0}, {0, 1}}}

Zhao, I see no problem. The function has two parameters, of which the second has an optional value, 0, used if no argument is passed.

This function call has two arguments:

f[IdentityMatrix[2], IdentityMatrix[2]]

Thats why the optional value is not used.

How should I modify this function definition so that the optional argument can take effect in all the call methods I listed?

What output do you want from this call?

f[IdentityMatrix[2], IdentityMatrix[2]]

I am looking forward to the following behavior:

f[IdentityMatrix[2], IdentityMatrix[2]]

Gives the following:

{{{{1, 0}, {0, 1}}}, {{1, 0}, {0, 1}}, 0}

And

f[IdentityMatrix[2], IdentityMatrix[2], b]

Gives the following:

{{{{1, 0}, {0, 1}}}, {{1, 0}, {0, 1}}, b}

Ok, try this:

In[47]:= g[{x__?MatrixQ} | x__?MatrixQ, y : Except[_List] : 0] := {{x}, y}
g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]

Out[48]= {{{{1, 0}, {0, 1}}}, 0}

Out[49]= {{{{1, 0}, {0, 1}}}, b}

Out[50]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[51]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

Nice trick. It works. But what’s the meaning of y : Except[_List] : 0? Why can we achieve the goal of discussion here in this form?

This is a question that can and should be resolved by checking the reference page for Except.

Wrap Longest around the full repeated pattern, like so.

In[127]:= 
g[{x__?MatrixQ} | Longest[x__?MatrixQ], 
  y : Except[_List] : 0] := {{x}, y}

In[128]:= g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]

(* Out[128]= {{{{1, 0}, {0, 1}}}, 0}

Out[129]= {{{{1, 0}, {0, 1}}}, b}

Out[130]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[131]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b} *)

Zhao, I will try to explain. This is the function definition:

g[{x__?MatrixQ} | x__?MatrixQ, y : Except[_List] : 0] := {{x}, y}

It can take one or two arguments.

The first argument can be a sequence of one or more matrices. The sequence can be enclosed in curly brackets, but it does not have to be.

The second argument, if passed, can be anything except a list. If nothing is passed the value 0 will be used.
When receiving the call

g[matrixA, matrixB]

it has first to be decided if there are one or two arguments. matrixB is a list (any matrix is a list), so it cannot be the second argument. It has to be part of the first arguments matrix sequence,

Note that this will work only if the first argument is not enclosed in curly brackets,

However, as you can see, even without using Longest, I can still achieve the goals discussed here:

In[24]:= g[{x__?MatrixQ} | x__?MatrixQ, y : Except[_List] : 0] := {{x}, y}
g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]

Out[25]= {{{{1, 0}, {0, 1}}}, 0}

Out[26]= {{{{1, 0}, {0, 1}}}, b}

Out[27]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[28]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

So, I still can’t figure out the intention of using Longest here.

It seems that all the following methods can achieve the goals discussed here:

In[94]:= g[{x__?MatrixQ} | x__?MatrixQ, y : Except[_List] : 0] := {{x}, y}
g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]
g[{IdentityMatrix[2], IdentityMatrix[2]}]
g[{IdentityMatrix[2], IdentityMatrix[2]},b]

Out[95]= {{{{1, 0}, {0, 1}}}, 0}

Out[96]= {{{{1, 0}, {0, 1}}}, b}

Out[97]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[98]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

Out[99]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[100]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

In[101]:= g[{x__?MatrixQ} | Longest[x__?MatrixQ], y : Except[_List] : 0] := {{x}, y}
g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]
g[{IdentityMatrix[2], IdentityMatrix[2]}]
g[{IdentityMatrix[2], IdentityMatrix[2]},b]

Out[102]= {{{{1, 0}, {0, 1}}}, 0}

Out[103]= {{{{1, 0}, {0, 1}}}, b}

Out[104]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[105]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

Out[106]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[107]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

In[108]:= g[{x__?MatrixQ} | Longest[x__?MatrixQ], y : 0] := {{x}, y}
g[IdentityMatrix[2]]
g[IdentityMatrix[2], b]
g[IdentityMatrix[2], IdentityMatrix[2]]
g[IdentityMatrix[2], IdentityMatrix[2], b]
g[{IdentityMatrix[2], IdentityMatrix[2]}]
g[{IdentityMatrix[2], IdentityMatrix[2]},b]

Out[109]= {{{{1, 0}, {0, 1}}}, 0}

Out[110]= {{{{1, 0}, {0, 1}}}, b}

Out[111]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[112]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

Out[113]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

Out[114]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, b}

So, I’m still not sure if I should use Longest and Except at the same time here.

The intent is to match the longest possible pattern. Kind of what the name implies. I’m sure the reference page will have more detail.

Using Longest or not does not make any difference:

In[50]:= 
g[{x__?MatrixQ} | x__?MatrixQ, y : Except[_List] : 0] := {{x}, y}
h[{x__?MatrixQ} | Longest[x__?MatrixQ], y : Except[_List] : 0] := {{x}, y}

In[52]:= 
g[IdentityMatrix[2], IdentityMatrix[2]]
h[IdentityMatrix[2], IdentityMatrix[2]]

Out[52]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0} 
Out[53]= {{{{1, 0}, {0, 1}}, {{1, 0}, {0, 1}}}, 0}

It’s an either-or proposition regarding Longest vs. Except, in this particular case.

But your example use both Longest and Except at the same, which is why I asked further.