1

I was wondering if it was possible to create a macro such that, when I type an undefined control sequence like \Var, \PDAG, and so on, it automatically convert them in mathematical operators.

I am asking it to avoid creating a ton of \newcommands.

Thank you very much in advance.

5
  • 7
    Welcome to TeX.SX. No, it's not possible. But you can use \operatorname{Var}, for instance.
    – egreg
    Commented Jun 21, 2018 at 10:10
  • Do you know why you get errors and warnings from TeX?
    – Johannes_B
    Commented Jun 22, 2018 at 5:20
  • @egreg: Technically possible: add an \everymath and an \everydisplay that scan the whole math expression for undefined control sequences. I was hoping that LuaTeX would provide a callback to suppress an undefined control sequence error, but it doesn't seem so. Commented Jun 25, 2018 at 3:48
  • @BrunoLeFloch \def\foo{\baz};-)
    – egreg
    Commented Jun 25, 2018 at 8:23
  • That's not very common in math mode. And it's not too hard in general to avoid doing such a definition before defining \baz. Commented Jun 26, 2018 at 2:42

4 Answers 4

2

Here is a no-package template you can adapt to your needs.

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\expandafter\def\expandafter\MakeMyDay\@backslashchar
    #1@#2{% #1 = name without backslash
          % #2 = control sequence
% YOU CAN CUSTOMIZE HERE WHATEVER YOU WANT
    \newcommand{#2}{\operatorname{#1}}%
}

% lovely \expandafter's
\@tfor\x:=\Var\PDFAg\Egreg\Mond\Moon\Sun
  \do{\expandafter\expandafter\expandafter
      \expandafter\expandafter\expandafter
      \expandafter
      \MakeMyDay
      \expandafter\expandafter\expandafter
      \string\expandafter\x\expandafter @\x}%


\makeatother
\begin{document}
$\Var$, $\PDFAg$, $\Egreg$, $\Mond$, $\Moon$, $\Sun$

\end{document}

Output:

https://i.sstatic.net/bxdYb.png

1

Just my two cents:

\documentclass{article}
\usepackage{amsmath}

\makeatletter
% ---------------------------------------------------------------
% \name foo{bar} -> foo\bar
% \name {bar} -> \bar
\newcommand\name{}%
\long\def\name#1#{\UD@innername{#1}}%
\newcommand\UD@innername[2]{%
  \expandafter\UD@exchange\expandafter{\csname#2\endcsname}{#1}%
}%
%
\newcommand\UD@exchange[2]{#2#1}%
% ---------------------------------------------------------------
\newcommand\DefineOneNiceMathOperatorFromString[1]{%
  \name\newcommand{#1}{\ensuremath{\operatorname{#1}}}%
}%
% ---------------------------------------------------------------
\newcommand\DefineSeveralNiceMathOperatorsFromStrings[1]{%
  \@tfor\x:=#1\do{%
    \expandafter\DefineOneNiceMathOperatorFromString
    \expandafter{\x}%
  }%
}%
% ---------------------------------------------------------------
\newcommand\DefineOneNiceMathOperatorFromCsToken[1]{%
  \begingroup\escapechar=-1\relax
  \expandafter\endgroup
  \expandafter\DefineOneNiceMathOperatorFromString\expandafter{\string#1}%
}%
% ---------------------------------------------------------------
\newcommand\DefineSeveralNiceMathOperatorsFromCsTokens[1]{%
  \@tfor\x:=#1\do{%
    \expandafter\DefineOneNiceMathOperatorFromCsToken
    \expandafter{\x}%
  }%
}%
% ---------------------------------------------------------------
\makeatother

\DefineOneNiceMathOperatorFromString{Alice}

\DefineSeveralNiceMathOperatorsFromStrings{{Bob}{Carol}{Dave}{Ted}{Eve}}

\DefineOneNiceMathOperatorFromCsToken{\Mallory}

\DefineSeveralNiceMathOperatorsFromCsTokens{\Oscar\Peggy\Victor\Trudy\Trend}

\begin{document}

\verb|$\Alice$| yields: $\Alice$

\verb|$\Bob$| yields: $\Bob$

\verb|$\Carol$| yields: $\Carol$

\verb|$\Dave$| yields: $\Dave$

\verb|$\Ted$| yields: $\Ted$

\verb|$\Eve$| yields: $\Eve$

\verb|$\Mallory$| yields: $\Mallory$

\verb|$\Oscar$| yields: $\Oscar$

\verb|$\Peggy$| yields: $\Peggy$

\verb|$\Victor$| yields: $\Victor$

\verb|$\Trudy$| yields: $\Trudy$

\verb|$\Trend$| yields: $\Trend$

\hrulefill

\verb|$\name{Alice}$| yields: $\name{Alice}$

\verb|$\name{Bob}$| yields: $\name{Bob}$

\verb|$\name{Carol}$| yields: $\name{Carol}$

\verb|$\name{Dave}$| yields: $\name{Dave}$

\verb|$\name{Ted}$| yields: $\name{Ted}$

\verb|$\name{Eve}$| yields: $\name{Eve}$

\verb|$\name{Mallory}$| yields: $\name{Mallory}$

\verb|$\name{Oscar}$| yields: $\name{Oscar}$

\verb|$\name{Peggy}$| yields: $\name{Peggy}$

\verb|$\name{Victor}$| yields: $\name{Victor}$

\verb|$\name{Trudy}$| yields: $\name{Trudy}$

\verb|$\name{Trend}$| yields: $\name{Trend}$

\end{document}

enter image description here

1

You can't do it, but if you want a simple way for defining several operators in a simple way, here it is:

\makeatletter
\newcommand{\DeclareSeveralMathOperators}[1]{%
  \@for\next:=#1\do{%
    \begingroup\edef\x{\endgroup\p@DeclareMathOperator{\next}{\next}}\x
  }%
}
\protected\def\p@DeclareMathOperator#1{%
  \expandafter\DeclareMathOperator\csname #1\endcsname
}
\makeatother

Full example (operators as in jfbu's example):

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand{\DeclareSeveralMathOperators}[1]{%
  \@for\next:=#1\do{%
    \begingroup\edef\x{\endgroup\p@DeclareMathOperator{\next}{\next}}\x
  }%
}
\protected\def\p@DeclareMathOperator#1{%
  \expandafter\DeclareMathOperator\csname #1\endcsname
}
\makeatother

\DeclareSeveralMathOperators{Var,PDFAg,Egreg,Mond,Moon,Sun}

\begin{document}

$\Var$, $\PDFAg$, $\Egreg$, $\Mond$, $\Moon$, $\Sun$

\end{document}

Much simpler if you use expl3; with \exp_args:Nc we transform {##1} into the control sequence having ##1 as name before \DeclareMathOperator enters into action. As usual, ##1 stands for the current item in the list which we feed to \DeclareSeveralMathOperators:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\DeclareSeveralMathOperators}{m}
 {
  \clist_map_inline:nn { #1 }
   {
    \exp_args:Nc \DeclareMathOperator { ##1 } { ##1 }
   }
 }
\ExplSyntaxOff

\DeclareSeveralMathOperators{Var,PDFAg,Egreg,Mond,Moon,Sun}

\begin{document}

$\Var$, $\PDFAg$, $\Egreg$, $\Mond$, $\Moon$, $\Sun$

\end{document}

enter image description here

0

Philosophically speaking/as a moot point one could raise the question whether you also need tests for finding out whether
- a given control sequence token is already defined.
- a given control sequence name denotes a control sequence token which is already defined.

If eTeX extensions are available, one can use the primitives \ifdefined for the further and \ifcsname for the latter.

If they are not available, a macro \@ifundefined can be implemented as in older releases of the LaTeX2e kernel which does form the control sequence token from the \csname..\endcsname construct and then does check whether the meaning of that token does equal the meaning of the \relax-primitive.
(\csname..\endcsname does within the current scope (even if \globaldefs is positive it does so only in the current scope) assign the control sequence token in question the meaning of the \relax-primitive in case it is undefined.)

\newcommand\@ifundefined[1]{%
  \expandafter\ifx\csname#1\endcsname\relax
    \expandafter\@firstoftwo 
  \else
    \expandafter\@secondoftwo
  \fi 
}

With the older-LaTeX2e-kernel-approach undefined control sequences will within the current scope be defined to \relax after testing the first time on them. With the older-LaTeX2e-kernel-approach one cannot distinguish cases where control sequences were already defined to \relax before testing took place from cases where control sequences weren't defined at all before testing took place.

By introducing some trickery with grouping/scoping, it is possible both to avoid permanently assigning within the current scope the meaning of the \relax-primitive to undefined control sequences and to distinguish the above mentioned cases:

\documentclass{article}

\begingroup
\makeatletter
\@firstofone{%
  \endgroup
  \newcommand\old@ifundefined[1]{%
    \expandafter\ifx\csname #1\endcsname\relax
      \expandafter\@firstoftwo 
    \else
      \expandafter\@secondoftwo
    \fi 
  }%
  \newcommand\CheckWhetherUndefined[1]{%
    \begingroup
    \expandafter\expandafter\expandafter\expandafter
    \expandafter\expandafter\expandafter\endgroup
    \old@ifundefined{#1}%
    {% -> defined equal to \relax or undefined
      \begingroup
      \expandafter\expandafter\expandafter\endgroup
      \old@ifundefined{#1}{%
        % -> defined to equal \relax
        \@secondoftwo
      }{%
        % -> undefined
        \@firstoftwo
      }%
    }{% -> defined
      \@secondoftwo
    }%
  }%
}%

\begin{document}

\makeatletter
\ttfamily\selectfont

\def\foo{defined}
\let\bar=\relax

\verb|\meaning\foo| $\to$ \meaning\foo

\verb|\meaning\bar| $\to$ \meaning\bar

\verb|\meaning\UnDeFINed| $\to$ \meaning\UnDeFINed

Test with \string\CheckWhetherUndefined:

\verb|\CheckWhetherUndefined{foo}{undefined}{defined}| $\to$
\CheckWhetherUndefined{foo}{undefined}{defined}

\verb|\CheckWhetherUndefined{bar}{undefined}{defined}| $\to$
\CheckWhetherUndefined{bar}{undefined}{defined}

\verb|\CheckWhetherUndefined{UnDeFINed}{undefined}{defined}| $\to$
\CheckWhetherUndefined{UnDeFINed}{undefined}{defined}

Test with \LaTeXe's \string\old@ifundefined:

\verb|\old@ifundefined{foo}{undefined}{defined}| $\to$
\old@ifundefined{foo}{undefined}{defined}

\verb|\old@ifundefined{bar}{undefined}{defined}| $\to$
\old@ifundefined{bar}{undefined}{defined}

\verb|\old@ifundefined{UnDeFINed}{undefined}{defined}| $\to$
\old@ifundefined{UnDeFINed}{undefined}{defined}

\end{document}

enter image description here

But there are still some issues left:

If you wish to go the \old@ifundefined/\CheckWhetherUndefined-route with control sequence tokens also instead of given names, you need to derive the names from the control sequence tokens. You can do so by using \string and removing the leading escape character if present. In order to find out whether a leading escape character is present and if so, whether that character is a character token of category code 12 (other) or a space token, you can evaluate the current value of the integer parameter \escapechar. Alternatively it can be ensured that no leading escape character will be present by (within a local scope) assigning \escapechar a negative value.

But this does not take into account that somebody might like to apply the test on an active character token.

Besides this, tests where grouping/introducing local scopes and assigning values to integer parameters like \escapechar is needed, do not work in expansion contexts, as grouping/scoping and assigning does not take place at the same time when expansion takes place as expansion and grouping/scoping/assigning do take place in different sections of (La)TeX' digestive apparatus.

One also needs to keep in mind that implementing whatsoever tests does usually take place in terms of macros while macros do process things argument-wise and thus not necessarily token-wise.

How to catch up scenarios where more than one token is passed as an argument?
How to catch up scenarios where the first token of the argument is an opening brace of catcode 1?
How to catch up scenarios where a (single) non-control-sequence-token is passed as an argument?
How to catch up scenarios where the argument is empty?
How to catch up scenarios where the test should not be about a control sequence token but about an active character token?

Probably a fully expandable test without eTeX-extensions would be nice for finding out whether the very first token of the argument is something that is undefined.

I've implemented such a test in the example below.

The gist of the test is:

First a dot-character and thus something that is not undefined is attached to make sure that the argument is not empty.
Then it is expandably checked whether the first token of the argument is an opening brace/an explicit catcode-1-character token. If so, it is obvious that with that argument there is no first token being something undefined.
Otherwise that first token of the argument can be "hit" via \meaning, and after obtaining the result of that "hitting" checking can take place on whether now the argument has the leading phrase "undefined" consisting of characters of category code 12(other):

\documentclass{article}
\makeatletter
%%----------------------------------------------------------------------
%% Paraphernalia:
%%----------------------------------------------------------------------
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@Exchange[2]{#2#1}%
%%----------------------------------------------------------------------
%% Expandably within two expansion steps check whether argument is empty:
%%----------------------------------------------------------------------
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
%%
%% A concern in his posting is that the argument is hit with \string
%% after some expansions which in edge cases might result in unbalancing
%% surrounding \if..\fi-constructs if the macro is used inside of such
%% \if..\fi-constructs.
%%
%% That challenging concern sickened me. ;-)
%%
%% Therefore I decided to implerment a variant where this cannot happen
%% as expansion is forced by \romannumeral:
%%
%% After the first expansion-step, \string is not applied yet.
%% After the second expansion-step, any possibly disturbing remainders
%% are already removed due to \romannumeral-expansion.
%%
%% No eTeX- or whatsoever extensions. No \if.. .Only \romannumeral,
%% digit 0, space token for terminating \romannumeral-expansion,
%% \string, \expandafter, \UD@firstoftwo, \UD@secondoftwo, {, }.
%%
%% May 20, 2016
%%
%% Ulrich Diez (e-mail: [email protected])
%%......................................................................
\newcommand\UD@CheckWhetherNull[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
  \UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
  \UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%----------------------------------------------------------------------
%% Expandably within two expansion steps check whether argument's first 
%% token is a catcode-1-character
%%----------------------------------------------------------------------
%% \UD@CheckWhetherLeadingBrace{<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has leading
%%                        catcode-1-token>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked has no leading
%%                        catcode-1-token>}%
%%......................................................................
\newcommand\UD@CheckWhetherLeadingBrace[1]{%
  \romannumeral0\expandafter\UD@secondoftwo\expandafter{\expandafter{%
  \string#1.}\expandafter\UD@firstoftwo\expandafter{\expandafter
  \UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
  \UD@firstoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
}%
%%----------------------------------------------------------------------
%% Expandably within two expansion steps check whether macro argument 
%% has an undefined token as its first token:
%%----------------------------------------------------------------------
%% \CheckWhetherArgumentHasAFirstTokenThatIsUndefined%
%%                      {<Argument which is to be checked>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked does have an
%%                        undefined token as its first token.>}%
%%                      {<Tokens to be delivered in case that argument
%%                        which is to be checked does not have an
%%                        undefined token as its first token.>}%
%%......................................................................
\begingroup
\newcommand\CheckWhetherArgumentHasAFirstTokenThatIsUndefined[1]{%
  \endgroup
  \newcommand\CheckWhetherArgumentHasAFirstTokenThatIsUndefined[1]{%
    \romannumeral0\UD@CheckWhetherLeadingBrace{##1}%
    {\expandafter\expandafter\UD@firstoftwo{ }{}\UD@secondoftwo}%
    {\expandafter\UD@secondoftwo\string{\expandafter
     \CheckWhetherArgumentHasAFirstTokenThatIsUndefinedB
     \meaning##1.#1}{}}%
  }%
  \newcommand\CheckWhetherArgumentHasAFirstTokenThatIsUndefinedB{}%
  \long\def\CheckWhetherArgumentHasAFirstTokenThatIsUndefinedB##1#1{%
    \UD@CheckWhetherNull{##1}%
    {\UD@Exchange{\UD@firstoftwo}}{\UD@Exchange{\UD@secondoftwo}}%
    {\UD@Exchange{ }{\expandafter\expandafter\expandafter\expandafter
     \expandafter\expandafter\expandafter}\expandafter\expandafter
     \expandafter}\expandafter\UD@secondoftwo\expandafter{\string}%
  }%
}%
\begingroup
\edef\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{%
  \endgroup
  \noexpand\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{%
    \string u\string n\string d\string e\string f%
    \string i\string n\string e\string d%
  }%
}%
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined
%%----------------------------------------------------------------------
%% A macro for those who prefer nesting \if-conditionals:
%%   (Be aware that after reading the closing brace behind
%%    <Argument which is to be checked> TeX' reading-apparatus will be 
%%    in state M (middle of line) and therefore you need to use
%%    comment-characters for avoiding unwanted spaces!!!)
%%----------------------------------------------------------------------
%%   \if\ArgumentHasAFirstTokenThatIsUndefined{<Argument which is to be checked>}%
%%     <Tokens to be delivered in case that argument
%%      which is to be checked does have an
%%      undefined token as its first token.>
%%  \else
%%     <Tokens to be delivered in case that argument
%%      which is to be checked does not have an
%%      undefined token as its first token.>
%%  \fi
%%......................................................................
\newcommand\ArgumentHasAFirstTokenThatIsUndefined[1]{%
  0\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{#1}{0}{1}%
}%
\makeatother

\begin{document}
\parindent=0ex
\parskip=\baselineskip
\footnotesize
\nonfrenchspacing
\ttfamily\selectfont

Testing \string\CheckWhetherArgumentHasAFirstTokenThatIsUndefined

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{{in braces}}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{{in braces}}{true}{false}

\verb|\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{}{true}{false}| $\to$\\
\CheckWhetherArgumentHasAFirstTokenThatIsUndefined{}{true}{false}

Testing \string\if\string\ArgumentHasAFirstTokenThatIsUndefined

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{a}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{a}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{a\biZarre\fi}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{\TeX\biZarre\fi}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{\uNdEfInED\biZarre\fi}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{{in braces}}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{{in braces}}true\else false\fi

\verb|\if\ArgumentHasAFirstTokenThatIsUndefined{}true\else false\fi| $\to$\\
\if\ArgumentHasAFirstTokenThatIsUndefined{}true\else false\fi

\end{document}

enter image description here

2
  • Note that \@ifundefined in the LaTeX kernel now uses \ifcsname
    – Joseph Wright
    Commented Jun 24, 2018 at 21:00
  • @JosephWright Thanks for pointing this out. I edited my answer for taking this into account. Commented Jun 24, 2018 at 21:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .