# Why these ways of defining a function with variable number of arguments fail?

First: I know about the correct way to define a function with variable number of arguments:

    Clear[f]
f[s__] := Plus[s]
f[1, 2, 3, 4]

(* 10 *)


BUT I can't understand why these ideas of mine fail:

My idea #1:

    Clear[f]
f[s_Sequence] := Plus[s]
f[1, 2, 3, 4]

(* f[1, 2, 3, 4] *)


I can't get it why it fails to work. If I understand Mathematica patterns (seemingly, I don't... ;P), any sequence of arguemnts passed to f should be matched and named s; and then this sequence should be further passed to Plus. Yet it doesn't even seem to be matched?

My idea #2:

Clear[f]
f[s : (_..)] := Plus[s]
Syntax::sntxf: "(_.." cannot be followed by ")".


Or, without the parentheses:

Clear[f]
f[s : _..] := Plus[s]
Syntax::tsntxi: "_.." is incomplete; more input is needed.


Again, I can't get why it fails to work. The way I understand Mathematica patterns it should work like this: first, .._ (equivalent to Repeated[_]) should match a sequence of any expressions matching _ (so, actually, a sequence of any expressions - so a sequence of 4 integers should qualify?), and then this sequence should be named s and further passed to Plus. Yet this definition even fails to pass the parser!

Could somebody very kindly explain to me where am I misunderstanding Mathematica patterns and why exactly are those examples failing to work?

Many thanks!

• For your first idea to work, you need to hold an explicit head Sequence[]. Such as in ClearAll[g, f]; SetAttributes[g, SequenceHold]; g[s_Sequence] := Plus[s]; f[s__] := Sequence[s]; g[1, 2]; g[f[1, 2]] Feb 12, 2015 at 0:03
• @belisarius ...aaand that's why Head[1,2,3] gives out errors and not Sequence, right? Feb 12, 2015 at 0:09
• Yup. But my knowledge ends there. I can't explain clearly why. Feb 12, 2015 at 0:12
• Two answers, targeting different parts of my question. Sorry, but I can't mark any of them accepted this way :) Feb 12, 2015 at 0:17
• When in doubt, ladies go first Feb 12, 2015 at 0:19

Re your Idea 2: Both

f[s : (_) ..] := Plus[s]
f[1,2,3]
( 6 *)


and

f[s : _ ..] := Plus[s]
f[1,2,3]
(* 6 *)


work as expected.

Without space or parentheses separating _ (Blank) from .. (Repeated), both (_..) and _.. are parsed as _. (i.e. Default, which represents an argument that can be omitted - see Default) followed by . which is bad syntax as indicated by the syntax highlighting:

Tip: If you double-click on the "_.." you see that the "_." are grouped together, and the second "." is not parsed with the first ".".

There are a few constructs which are not evaluated in the standard way in Mathematica. Unevaluated and Sequence are like this.

When Mathematica evaluates an expression, it will first walk through it and strip out any Sequence expressions, leaving only the body. This is a special step done during evaluation.

In[]:=
On[]
f[Sequence[1, 2, 3]]
Off[]

During evaluation of In[12]:= On::trace: On[] --> Null. >>

During evaluation of In[12]:= f::trace: f[Sequence[1,2,3]] --> f[1,2,3]. >>

Out[]= f[1, 2, 3]


Other than this special rule, Sequence behaves like a normal head. It behaves like a normal head in pattern matching as well. Thus _Sequence will only match expressions of the form Sequence[1,2,3], but never simply 1,2,3. Of course unless we prevent it, f[Sequence[1,2,3]] will be transformed to f[1,2,3] during the first stage of evaluation, so usually the pattern matcher doesn't even have a chance to see it.

To sum up, it is not technically correct to claim that Sequence[1,2,3] represents a sequence of expressions in any general context. What actually happens is that expressions of the form f[Sequence[1,2,3]] are transformed to f[1,2,3] during the first stage of the evaluation procedure. Pattern matching is unaffected.

Here are some examples demonstrating how Sequence works:

In[1]:= f[s_Sequence] := {s}

In[2]:= f[1, 2, 3]
Out[2]= f[1, 2, 3]

In[3]:= f[Sequence[1, 2, 3]]
Out[3]= f[1, 2, 3]

In[4]:= f[Unevaluated@Sequence[1, 2, 3]]
Out[4]= {1, 2, 3}

In[5]:= On[]
f[Unevaluated@Sequence[1, 2, 3]]
Off[]

During evaluation of In[5]:= On::trace: On[] --> Null. >>

During evaluation of In[5]:= f::trace: f[Unevaluated[Sequence[1,2,3]]] --> f[Sequence[1,2,3]]. >>

During evaluation of In[5]:= f::trace: f[Sequence[1,2,3]] --> {Sequence[1,2,3]}. >>

During evaluation of In[5]:= List::trace: {Sequence[1,2,3]} --> {1,2,3}. >>

Out[6]= {1, 2, 3}

In[8]:= Attributes[f] = {HoldAll}
Out[8]= {HoldAll}

In[9]:= f[Sequence[1, 2, 3]]
Out[9]= f[1, 2, 3]

In[10]:= Attributes[f] = {SequenceHold}
Out[10]= {SequenceHold}

In[11]:= f[Sequence[1, 2, 3]]
Out[11]= {1, 2, 3}


In the question you compare the patterns f[s__] and f[s_Sequence]. Note that these are different patterns:

FullForm[f_Sequence]
(* Pattern[f, Blank[Sequence]] *)

FullForm[f[s__]]
(* Pattern[s, BlankSequence[]] *)


As the comments point out, Blank[Sequence] would be matched by an expression with head Sequence, but Sequence automatically disappears during evaluations (that's the point of it).

Instead, there is a custom pattern BlankSequence which matches things as though they had head Sequence (but are in fact simply a comma-delimited sequence of expressions).

Your pattern f[a,b,c] is matched by f[s:BlankSequence] but not by f[s:Blank[Sequence]].

As the other answer points out, Idea#2 simply contained a syntax error.

• Is there anything new in this answer, that is not already covered in the previous answers & comments (and in the question itself)? Mar 3, 2015 at 11:49
• @gaazkam yes. The other answer explained why Sequence does not match. I explained why BlankSequence does match, and showed you how to tease this out for yourself by using FullForm.
– djp
Mar 3, 2015 at 12:33