2

I have a command \cont used mainly in the form \cont{X, Y} and defined using \SplitArgument, as shown in the source below. How can I redefine (that is, extend the definition of)\cont so as to allow 4 arguments rather than 2, which get grouped in pairs as shown in the outout equation (2)?

Notice that I want to continue using a comma as separator when there are only 2 arguments, as in \cont{X, Y}. But I want to change the (main) separator to a semicolon when there are 4 arguments, while retaining commas as subsidiary separators, as in \cont{X, x; Y, y}.

\documentclass[fleqn]{memoir}
\usepackage{xparse}

\NewDocumentCommand{\cont}{ >{\SplitArgument{1}{,}} m }{\printcont#1} \NewDocumentCommand{\printcont}{mm}{{\mathcal{C}}({#1}\IfValueT{#2}{, {#2}})}

\begin{document}

\noindent Equation~(\ref{one}) shows use of \verb!\cont! with 2 arguments, as in \verb!\cont{X, Y}!, with comma as separator: \begin{equation}\label{one} \cont{X, Y} \end{equation}

\noindent How can we \emph{extend} the definition of \verb!\cont! so that\dots\[6pt] \mbox{}\qquad\verb!\cont{X, x; Y, y}! \[6pt] ---with commas and a single semicolon as separators----gives the same result as equation~(\ref{two}), below? \begin{equation}\label{two} \mathcal{C}[(X, x), (Y, y)] \end{equation}

\end{document}

extend def to allow 4 args not just 2

murray
  • 7,944

4 Answers4

3

The macro \cont defined only using TeX primitives:

\def\cont#1{\contA#1;\end}
\def\contA#1;#2\end{\ifx;#2;{\cal C}(#1)\else\contB#1;#2\fi}
\def\contB#1;#2;{{\cal C}\bigl[(#1),(#2)\bigr]}

%% test:

$$\displaylines{ \cont{X} \cr \cont{X, Y} \cr \cont{X;Y} \cr \cont{X,x;Y} \cr \cont{X, x;Y, y} }$$

\bye

wipet
  • 74,238
  • So short & swee - puts the LaTeX solutions to shamet! But as a general principle, some folks discourage using pure TeX code into LaTeX documents and urge use of LaTeX-only constructions. – murray Oct 14 '21 at 15:15
  • @murray Indeed. That's why I also gave +1. Actually this answer is not the right place for the following remark but as a general advice on macro-programming in plain TeX be aware that with delimited arguments you need to take care that unwanted removal of the outermost level of curly braces does not occur and that the user supplying arguments that might erroneously match argument delimiters or definition-text's \if...\fi-constructs and the like is very unlikely. – Ulrich Diez Oct 16 '21 at 13:11
  • @murray I never understood this discouragement related to the usage of plain TeX code in LaTeX documents. Better would be to encourage people to know what they are doing when they use plain TeX. And believe me: wipet is a professional who knows exactly what he is doing in TeX. :-) – Ulrich Diez Oct 16 '21 at 14:11
  • @UlrichDiez: "to know what they are doing when they use plain TeX" is just the reason I eschew plain TeX code, as TeX-wise I am impaired! And possibly why others denigrate use of plain TeX in LaTeX documents. – murray Oct 16 '21 at 16:22
  • @murray My experience is: In order to understand what is going on in LaTeX/expl3 you need deep understanding of TeX. Otherwise you are doomed when it comes to tracking down/resolving/working around some of the many issues you may encounter while relying on LaTeX/expl3. – Ulrich Diez Oct 16 '21 at 20:39
2

The following approach uses etoolbox's list processing capabilities to set the argument supplied by \cont, separating the argument (a list) by ; and then setting the list conditionally: A single item is set differently from a list of items.

enter image description here

\documentclass{article}

\usepackage{etoolbox}

\DeclareListParser{\contlist}{;}% Processes a list using ; as separator \newcounter{contcount} \newcommand{\cont}[1]{% \setcounter{contcount}{0}% Reset counter \renewcommand{\do}[1]{\stepcounter{contcount}}% Count items in list \contlist{#1}% Count elements in list \ifnum\value{contcount}<2 \mathcal{C}(#1)% Singular element \else % \value{contcount}>1 \mathcal{C}[ % https://tex.stackexchange.com/a/89187/5764 \newcommand{\contitemsep}{\renewcommand{\contitemsep}{,}}% Delayed definition of \contitemsep \renewcommand{\do}[1]{\contitemsep(##1)}% How each item in list should be printed \contlist{#1}% Print entire list ] \fi }

\begin{document}

\noindent Equation~(\ref{one}) shows use of \verb!\cont! with 2 arguments, as in \verb!\cont{X, Y}!, with comma as separator: \begin{equation}\label{one} \cont{X, Y} \end{equation}

\noindent How can we \emph{extend} the definition of \verb!\cont! so that\dots

\qquad\verb!\cont{X, x; Y, y}!

---with commas and a single semicolon as separators----gives the same result as equation~(\ref{two}), below? \begin{equation}\label{two} \cont{X, x; Y, y} \end{equation}

\end{document}

Werner
  • 603,163
2

I'd issue the \mathcal{C} immediately and then pass control to another command that checks for a semicolon and takes the appropriate action.

\documentclass[fleqn]{memoir}
\usepackage{amsmath}

\NewDocumentCommand{\cont}{>{\SplitArgument{1}{;}}m}{% \mathcal{C}% \printcont#1% } \NewDocumentCommand{\printcont}{mm}{% \IfNoValueTF{#2}{% \conttwo{#1}% }{% [\conttwo{#1},\conttwo{#2}]% }% } \NewDocumentCommand{\conttwo}{>{\SplitArgument{1}{,}}m}{% \printconttwo#1% } \NewDocumentCommand{\printconttwo}{mm}{% (#1\IfValueT{#2}{,#2})% }

\begin{document}

\begin{gather} \cont{X} \ \cont{X, Y} \ \cont{X;Y} \ \cont{X,x;Y} \ \cont{X, x;Y, y} \end{gather}

\end{document}

enter image description here

If you want to add \bigl and \bigr to the brackets with \cont*, then pass the argument throughout.

\documentclass[fleqn]{memoir}
\usepackage{amsmath}

\NewDocumentCommand{\cont}{s>{\SplitArgument{1}{;}}m}{% \mathcal{C}% \printcont{#1}#2% } \NewDocumentCommand{\printcont}{mmm}{% \IfNoValueTF{#3}{% \conttwo{#2}% }{% \IfBooleanT{#1}{\bigl}[% \conttwo{#2},\conttwo{#3} \IfBooleanT{#1}{\bigr}]% }% } \NewDocumentCommand{\conttwo}{>{\SplitArgument{1}{,}}m}{% \printconttwo#1% } \NewDocumentCommand{\printconttwo}{mm}{% ({#1}\IfValueT{#2}{, {#2}}) }

\begin{document}

\begin{gather} \cont{X} \ \cont{X, Y} \ \cont{X;Y} \ \cont{X,x;Y} \ \cont{X, x;Y, y} \ \cont{X,x;Y} \ \cont{X, x;Y, y} \end{gather}

\end{document}

enter image description here

egreg
  • 1,121,712
  • I'd still like a way to add a starred version, \cont*, that simply changes the (outermost) fences to \bigl[ ... \bigr]. Is it possible to do that, with WithSuffix or otherwise? – murray Oct 13 '21 at 14:23
  • @murray you can use an s-type argument and check via \IfBooleanTF. – Ulrich Diez Oct 13 '21 at 15:01
  • @murray Added as requested. Again, forget \WithSuffix. – egreg Oct 13 '21 at 16:39
  • @egreg: Thank you! I'm still struggling with understanding the syntax, specifically, where and how does the test for the star occur in the definitions? – murray Oct 13 '21 at 19:24
  • @murray It happens in \contfour, which argument #1 of \cont is passed to. – egreg Oct 13 '21 at 19:46
  • @egreg: I see no \contfour there! – murray Oct 13 '21 at 20:00
  • @murray Sorry, I meant \printcont – egreg Oct 13 '21 at 20:04
  • @murray \cont has an s-type argument as its first argument. This means if there was a star, #1 is the control-word-token \BooleanTrue. If there was no star, #1 is the control-word-token \BooleanFalse. You can use \IfBooleanTF{#1}{tokens in case there was a star}{tokens in case there was no star}/\IfBooleanT{#1}{tokens in case there was a star}/\IfBooleanF{#1}{tokens in case there was no star} for testing. You can also pass the control-word-token #1 as m-type-argument to other macros and have them do the test via \IfBooleanTF/\IfBooleanT/\IfBooleanF. – Ulrich Diez Oct 13 '21 at 20:25
  • What advantage, if any, is there in using \ExplSyntaxOn (and \ExplSyntaxOff later) rather than \usepackage{xparse} when a preamble is going to have definitions such as \cont and its subsidiary macros? And, in fact, do I need either of these at all when I am using current LaTeX2e <2021-06-01> , which automatically loads L3 programming layer <2021-10-12> ? – murray Oct 14 '21 at 22:44
  • @murray Oh, sorry! The \ExplSyntaxOn remained from some previous experiment. – egreg Oct 15 '21 at 05:54
2

This variant is reluctant with adding parentheses and with this variant \cont{X,Y} is the same as \cont{X;Y} and \cont*{X,Y} is the same as \cont*{X;Y}, i.e., you get square brackets only if both comma and semicolon occurs in \cont's non-star-argument.

\documentclass[fleqn]{memoir}
\usepackage{amsmath}

\NewDocumentCommand{\cont}{s>{\SplitArgument{1}{;}}m}{% % #1 - \BooleanTrue/\BooleanFalse - flag / control-word-token % denoting the presence/non-presence of star. % #2 - user-provided argument, split in two brace-nested arguments, one holding % "things before first semicolon", the other holding "things behind first semicolon". \conttwo#2{#1}% } \NewDocumentCommand{\conttwo}{>{\SplitArgument{1}{,}}mm}{% % #1 - things before first semicolon, split in two brace-nested arguments at first comma. % #2 - things behind first semicolon % You need to check if #2 is the NoValue-marker as % xparse-argument-processors like \SplitArgument do not work on % the NoValue-Marker \IfNoValueTF{#2}{\printcont{#2}}{\contthree}{#2}#1% } \NewDocumentCommand{\contthree}{>{\SplitArgument{1}{,}}m}{% % #1 - things behind first semicolon, split in two brace-nested arguments at first comma. \printcont#1% } \NewDocumentCommand\printcont{mmmmm}{% % #1 - first component of things behind first semicolon after splitting these things at first comma. % #2 - second component of things behind first semicolon after splitting these things at first comma. % #3 - first component of things before first semicolon after splitting these things at first comma. % #4 - second component of things before first semicolon after splitting these things at first comma. % #5 - \BooleanTrue/\BooleanFalse - flag denoting presence of star. \mathcal{C}% \IfNoValueTF{#1}{% (#3\IfNoValueF{#4}{,#4})% <-only commas }{% \IfNoValueTF{#4}{% \IfNoValueTF{#2}{(#3,#1)}% <-only semicolons {\IfBooleanT{#5}{\bigl}[#3,(#1,#2)\IfBooleanT{#5}{\bigr}]}% }% {\IfBooleanT{#5}{\bigl}[(#3,#4),\IfNoValueTF{#2}{#1}{(#1,#2)}\IfBooleanT{#5}{\bigr}]}% }% }%

\begin{document}

\Huge

\begin{tabular}{|l|l|} \hline (\cont{X})&(\cont{X}) \ \hline (\cont{X, Y})&(\cont{X, Y}) \ \hline (\cont{X;Y})&(\cont{X;Y}) \ \hline (\cont{X,x;Y})&(\cont{X,x;Y}) \ \hline (\cont{X;Y, y})&(\cont{X;Y, y}) \ \hline (\cont{X, x;Y, y})&(\cont{X, x;Y, y})\ \hline \end{tabular}

\end{document}

enter image description here

Ulrich Diez
  • 28,770
  • 1
    I especially like the "forgiving" nature of the 2nd variant, where the brackets appear only with both commas and semicolon, so that for a simple argument, both X, Y and X; Y give the same result. – murray Oct 13 '21 at 19:22
  • 1
    I also appreciate the explanatory comments in the code! – murray Oct 15 '21 at 01:14