# How to write a macro that takes a variable number of arguments

I am trying to make a new command called \com which can do the following:

• If no argument is provided to \com, $\com$ produces the symbol $\lambda$.
• If one argument is provided, e.g. $\com{f}$, the macro produces $\lambda [f]$ (with square brackets).
• If two arguments are provided, e.g. $\com{f}{x}$, the macro produces symbol $\lambda {f}(x)$ (with curly braces and round parentheses, resp.).

I have tried if else commands from the other posts but I am unable to make this work.

If some one can show me how to do this, I would be grateful.

• This is a command with two optional arguments, effectively.
– user31729
Mar 17, 2017 at 19:36
• That is true. But I won't know how to program this. Mar 17, 2017 at 19:37
• Should your third bullet say $\lambda \{f\}(x)$? Mar 18, 2017 at 13:44
• You can even aim higher and it's easier with xparse. \com = \lambda; \com[f] = \lambda[f]; \com{f}(x) = \lambda\{f\}(x). That way your code resembles the output and is easier to understand. Mar 18, 2017 at 14:46
• Related/duplicate: Variable number of arguments in a command
– Werner
Mar 18, 2017 at 23:45

This is quite easy with xparse and \NewDocumentCommand, having two optional arguments, however, you need to check for their existence.

Please note that oo could be replaced by gg to allow for optional {}{} arguments, but that's not recommended, but see below in this answer as an alternative.

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand{\com}{oo}{%
\lambda%
%Check if the first arg is given
\IfValueT{#1}{%
% Now check if has a 2nd argument as well.
\IfValueTF{#2}{% Yes, the 2nd one is present, use {f}(x) style
\{#1\}(#2)%
}{% No, use [f] style
[#1]%
}%
}%
}

\begin{document}

$\com$

$\com[f]$

$\com[f][x]$

\end{document}


Update with gg type (use it with care!) and another optional argument to use that instead of \lambda

\documentclass{article}

\usepackage{xparse}

\NewDocumentCommand{\com}{oo}{%
\lambda%
%Check if the first arg is given
\IfValueT{#1}{%
% Now check if has a 2nd argument as well.
\IfValueTF{#2}{% Yes, the 2nd one is present, use {f}(x) style
\{#1\}(#2)%
}{% No, use [f] style
[#1]%
}%
}%
}

\NewDocumentCommand{\comother}{O{\lambda}gg}{%
#1%
%Check if the first arg is given
\IfValueT{#2}{%
% Now check if has a 2nd argument as well.
\IfValueTF{#3}{% Yes, the 2nd one is present, use {f}(x) style
\{#2\}(#3)%
}{% No, use [f] style
[#2]%
}%
}%
}

\begin{document}

$\com$

$\com[f]$

$\com[f][x]$

$\comother$

$\comother{f}$

$\comother{f}{x}$

% Now with \beta instead of \lambda

$\comother[\beta]$

$\comother[\beta]{h}$

$\comother[\beta]{h}{y}$
\end{document}


Of course, the syntax uses the standard LaTeX convention of optional arguments in square brackets, in this case for both optional arguments.

Also, the OP implied that the command should be used not in math mode, so I have accommodated that.

\documentclass{article}
\newcommand\com[1][\relax]{\ifx\relax#1$\lambda$\else\def\firstarg{#1}\comhelp\fi}
\newcommand\comhelp[1][\relax]{\ifx\relax#1$\lambda [\firstarg]$%
\else$\lambda \{\firstarg\}(#1)$\fi}
\begin{document}
\end{document}


For a version that instead oeprates in math mode, here it is:

\documentclass{article}
\newcommand\com[1][\relax]{\ifx\relax#1\lambda\else\def\firstarg{#1}\comhelp\fi}
\newcommand\comhelp[1][\relax]{\ifx\relax#1\lambda [\firstarg]%
\else\lambda \{\firstarg\}(#1)\fi}
\begin{document}
$\com\quad\com[f]\quad\com[f][x]$
\end{document}


Here's a LuaLaTeX-based solution. It works as a preprocessor: The Lua function comscan runs at a very early stage of processing, before TeX gets to do its usual work. The Lua function find all instances of \com and replaces with a different macro, depending on whether \com is found to have 0, 1, or 2 arguments.

% !TeX program = lualatex
\documentclass{article}
\usepackage{luacode}
\begin{luacode}
function comscan ( s )
s = string.gsub ( s , "\\com(%b{})(%b{})" , "\\lambda\\{%1\\}(%2)" )
s = string.gsub ( s , "\\com(%b{})", "\\lambda[%1]" )
s = string.gsub ( s , "\\com(%A)" , "\\lambda%1" )
return ( s )
end
\end{luacode}
\providecommand{\command}{aaa} % dummy command
\begin{document}
$\com{f}{x}$, $\com{g}$, $\com$, \command
\end{document}

• One might also consider using the token scanner to do this without using the callback ... Mar 18, 2017 at 9:12
• @JosephWright - An excellent idea. :-) Do you want to provide a separate answer to show to achieve the OP's objective via the token scanner? (I'm afraid my knowledge of Lua(La)TeX isn't deep enough in this regard.)
– Mico
Mar 18, 2017 at 9:57

Since you are going to use non-standard arguments, I think you could aim to a more easier to read code. That way [f] outputs brackets, {f} outputs curly braces (here's where you avoid typing \{f\}) and (f) outputs parenthesis.

With this minimal code, you ensure that \com, \com[f] and \com{f}(g) behave as you would expect (the only intelligence given to the command is to convert {f} to \{f\}, the rest is left unchanged and works as you would expect).

\usepackage{xparse}
\NewDocumentCommand\com{g}{\lambda\IfValueT{#1}{\{#1\}}}


If you really need those to be treated as arguments and you need a bit more intelligence, then you need to define the full command

\NewDocumentCommand\com{o}{\lambda\IfValueTF{#1}{[#1]}{\comaux}}
\NewDocumentCommand\comaux{gd()}{\IfValueT{#2}{\{#1\}}\IfValueT{#2}{(#2)}}

• I mentioned the usage of g already yesterday in my answer (+1 anyway ;-) )
– user31729
Mar 18, 2017 at 16:14
• @ChristianHupfer Well, my answer was more into the “use natural markup” which can be easy with xparse; true that it uses g as your answer, but that was not the core of my answer so that's why I posted it. Mar 18, 2017 at 17:04