2

I want to define a command \NewSmartOp such that:

\NewSmartOp \MYOP \myop

would produce the following code (or anything equivalent):

\makeatletter
  \def\MYOP{\@ifstar\MYOP@star\MYOP@nostar}
  \def\MYOP@star#1{\myop\!\left( #1 \right)}
  \def\MYOP@nostar#1{\myop #1}
\makeatother

I guess I need \expandafter and perhaps \csname … \endcsname but otherwise I have no clue how to generate these definitions, especially regarding how to form a new command name \MYOP@star from \MYOP, and also how to deal with these #1 that must be kept as-is in the produced definitions (by contrast with being expanded by the definition producing them).

Background (reading optional)

For a bit of context: when typing math I want to abstract from concrete syntax as much as possible. For instance, for cardinality of set S, perhaps I’d like it to be rendered as card S (with parentheses only when needed, e.g. card(S₁ ∪ S₂)), but perhaps at some point in the future I’d like to switch syntax to |S|. So I would define:

\DeclareMathOperator \card {card}
\NewSmartOp \CARD \card % option 1
%\newcommand* \CARD[1] {\left\lvert # \right\rvert} % option 2

after which

  • I might use the operator directly (low-level, my TeX typing reflects the concrete syntax): \card S or \card(S);
  • but I’d rather use a command with an argument to which I defer the concrete syntax (high-level, my TeX typing reflects the abstract syntax tree): \CARD {S}.

This ideal seems hard to achieve fully because I cannot(?) find out automatically when parentheses are needed, so the compromise I adopted is to have stared versions of these “smart operators” add parentheses: \CARD* {S_1 \cup S_2}.

2 Answers 2

2

I'm not sure why not defining \CARD directly:

\NewDocumentCommand{\CARD}{sm}{%
  \operatorname{card}%
  \IfBooleanT{#1}{\left(}%
  #2%
  \IfBooleanT{#1}{\right)}%
}

If you want an abstract version:

\NewDocumentCommand{\NewOP}{mm}{%
  \NewDocumentCommand{#1}{sm}{%
    \operatorname{#2}%
    \IfBooleanT{##1}{\left}(%
    ##2%
    \IfBooleanT{##1}{\right})%
  }%
}

so you can do \NewOp{\CARD}{card}

However, using \left( and \right) can produce unwanted oversized parentheses. You've been warned.

You might use \DeclarePairedDelimiter from mathtools.

\documentclass{article}
\usepackage{amsmath,mathtools}

\NewDocumentCommand{\NewOp}{mm}{%
  \NewDocumentCommand{#1}{t+s}{%
    \operatorname{#2}
    \IfBooleanT{##1}{%
      \IfBooleanTF{##2}{\parentheses*}{\parentheses}%
    }%
  }%
}
\DeclarePairedDelimiter{\parentheses}{(}{)}

\NewOp{\card}{card}

\begin{document}

\begin{gather*}
\card{S} \\
\card+{S_1\cup S_2} \\
\card+{\hat{S}_1\cup\hat{S}_2} \\
\card+[\big]{\hat{S}_1\cup\hat{S}_2} \\
\card+*{\hat{S}_1\cup\hat{S}_2}
\end{gather*}

\end{document}

You denote that you want parentheses by following the command with +. This will call a paired delimiter and the * denotes that you want automatically sized ones.

However, you see from the last line that the result is suboptimal.

enter image description here

7
  • Ah, my bad, it was much easier than I anticipated: not even a single \expandafter! “why not defining \CARD directly” → If you mean without \@CARD and such, then I simply applied the recipe I found there for star-able commands; if you mean without a \NewSmartOp helper, then it’s because it’s a boilerplate pattern I will repeat many times (… i.e. the usual case for macros). You taught me about \operatorname, though. :-)
    – Maëlan
    May 11, 2022 at 22:28
  • @Maëlan I'm sorry, but the edit was wrong. For several reasons: I guess you want to add parentheses only if you want them to be automatically resized, but that's incorrect. If you want that, please do it for your document.
    – egreg
    May 11, 2022 at 22:31
  • How? The question was asking that the stared version puts (large) parentheses and that the non-stared version puts no parentheses (at all). This is not what the current code is doing (it puts parentheses in either case, only it makes them large in the stared version), but this is what my edit was doing. I tested this. Or am I missing something? Edit: “that's incorrect. If you want that, please do it for your document.” Okay… That’s precisely what I want and asked for, and my own documents are exactly what I write. Typographical good tastes are off-topic.
    – Maëlan
    May 11, 2022 at 22:34
  • @Maëlan I'm firmly against using \left and \right indiscriminately around delimiters. In some cases they're useful, in most cases they produce oversized parentheses. Try \left(\hat{b}\right), for instance. If you want parentheses, use them explicitly in the input (or use something like mathtools offers with \DeclarePairedDelimiter).
    – egreg
    May 11, 2022 at 22:37
  • I can see your point and don’t generally oppose it. TBH I wondered whether I should enforce systematic use of \left and \right, but it was just too much having to care for that additional bit. Defining yet another version of all commands that put parentheses… Still it was not the question, but I leave your answer as the solution anyway, since it taught me how to solve my problem.
    – Maëlan
    May 11, 2022 at 22:41
2

This kind of “high-level”, abstract, semantic syntax is more or less exactly the purpose of my package semantex:

\documentclass{article}

\usepackage{semantex}

\NewVariableClass\MyVar[output=\MyVar]

\NewObject\MyVar\card{\operatorname{card}}

\begin{document}

\begin{gather*}
    \card{S} \\
    \card[par]{S} \\
    \card[no par]{S} \\
    \card{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=\big]{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=auto]{ \hat{S}_1 \cup \hat{S}_2 }
\end{gather*}

\SetupObject\card{no par}

\begin{gather*}
    \card{S} \\
    \card[par]{S} \\
    \card[no par]{S} \\
    \card{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=\big]{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=auto]{ \hat{S}_1 \cup \hat{S}_2 }
\end{gather*}

\SetupObject\card{
    symbol={},
    par,
    left par=\lvert,
    right par=\rvert,
}

\begin{gather*}
    \card{S} \\
    \card[par]{S} \\
    \card[no par]{S} \\
    \card{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=\big]{ \hat{S}_1 \cup \hat{S}_2 } \\
    \card[par=auto]{ \hat{S}_1 \cup \hat{S}_2 }
\end{gather*}

\end{document}

enter image description here

You must log in to answer this question.

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