4

Based on my previous question I noticed (IMHO) that it is not so easy to make macros with delimited arguments with xparse instead plain-TeX's \def. As far as I know the LaTeX way - \newcommand - has no mechanism at all for defining this type of argument. It should be said that xparse has a mechanism for creating such arguments, but there are still some problems with this.

Here is another example in which it is very easy to create specially delimited arguments with \def, but it may take some skill to do it with xparse mechanism.

\def\braces(#1#2|#3#4){
    \ensuremath{
        \int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2
    }
}

So I guess I'll ask the community once again, for suggestions on how to do this with xparse (maybe in combination with LaTeX3 or only with LaTeX3). I hope, it will be instructive for me as well as for those reading this question. Besides, the correct and modern LaTeX way of defining commands is not \def and even not with \newcommand anymore, but using xparse.

1

4 Answers 4

3

I guess you want just the \chi part.

\documentclass{article}
\usepackage{amsmath}

\NewDocumentCommand{\braces}{>{\SplitArgument{1}{|}}r()}{\bracesaux#1}
\NewDocumentCommand{\bracesaux}{mm}{\bracesauxaux#1#2}
\NewDocumentCommand{\bracesauxaux}{mmmm}{%
  \chi_{#1}(1)\chi_{#2}(2)\chi_{#3}(1)\chi_{#4}(2)%
}

\begin{document}

\[
\braces(ab|cd)
\]

\end{document}

enter image description here

Whether this is better than with \def, you're the judge.

3
  • 1
    It's no better than \def, but at least it answers the question. Mar 11 at 17:34
  • I was wondering if, using the LaTeX3 syntax directly, it would be possible to parse through a single argument \NewDocumentCommand{\braces}{ r() }{ LaTeX3 code} ... Mar 11 at 17:43
  • @sergiokapone Not for this application, unless you go down to expl3. Anyway, I can't see how useful is the proposed syntax.
    – egreg
    Mar 11 at 18:04
10

The idea of \NewDocumentCommand, etc. ('ltcmd'), is that it provides a way to create 'LaTeX-like' commands readily. 'LaTeX-like' means largely using the idea of mandatory arguments in {...}, optional ones in [..], stars for 'special alternative' versions of commands, etc. However, there are a few wider cases it covers too, most obviously beamer-like optional <..>, picture-mode like mandatory (..) and verbatim grabbing (similar to \verb but with some differences). That covers a lot of what you want in a document, but it does not include in-depth parsing of arbitrary material. (The aim of the flexibility is to cover sufficient input scope that most things can be done using ltcmd.)

For more complex cases, one needs to build up ideas using classical TeX constructs (or using the expl3 equivalents). In most cases, this will take place within a regular argument. For example, siunitx parses numbers in a 'non-standard' way but the document-level command \num is defined using ltcmd with signature O{}m. One might look at TikZ as an extreme example: it defines its own input syntax, which is definitely not standard LaTeX but which is self-consistent - but only available within the scope of the tikzpicture environment or similar.

Note that a key idea for ltcmd is to separate out document command syntax from implementation. That means that in general, if you are using some delimited input form it would still be sensible to have the implementation separately: this allows re-working or re-using one or other aspect independent of the other.

My advice would be to think carefully about predictability before defining non-standard document command syntaxes.

5

Edit: The TeX - LaTeX Stack Exchange member matexmatics in a comment drew the attention of the author of the initial releases of this answer towards the fact that underscore (_) does not have category 8(subscript) in expl3 but does have category 11(letter) and therefore cannot be used for math-subsript in expl3 so that in expl3, instead of the underscore (_), one of the implicit characters \sb/\c_math_superscript_token needs to be used for math-subscript.


Deliberately fixating on the wrong tool for a task is not a good idea. Even ltcmd/xparse, no matter how modern it is, is not a jack-of-all-trades. There are tasks that are better to accomplish with tools other than ltcmd/xparse because ltcmd/xparse is not intended for them. So don't focus on doing things of this kind with ltcmd/xparse.

Just once more use \cs_new_protected:Npn from expl3/LaTeX 3—there is nothing wrong about doing that:

\ExplSyntaxOn
\cs_new_protected:Npn\braces(#1#2|#3#4){
    \ensuremath{
        \int \frac{\chi\sb#1(1)\chi\sb#2(1)\chi\sb#3(2)\chi\sb#4(2)}{r\sb{12}}~dV\sb1~dV\sb2
    }
}
\ExplSyntaxOff

I did not check whether typing the formula could be improved. I left \ensuremath in the code because you used it. If implementing things were up to me, instead of using \ensuremath I'd require the user to know that the macro works out only in math mode. \ensuremath is a pitfall for producing bad typesetting. E.g., you see people attempting to typeset a formula by lining up commands that do \ensuremath while TeX is in horizontal mode. This way fragments of the formula to typeset are typeset, which yields bad typography, instead of having TeX switch to math mode and produce the properly looking formula in one go.

[The following remark is opinion-based:]

Besides this, I take commands that might switch the typesetting mode under the hood for a source of confusion: When I author a document, then its up to me to decide about and to know about the kind of text phrase and thus about the typesetting mode. When I wish to write a paragraph of text, I have TeX switch to horizontal mode. When I wish to type maths, I have TeX switch to mathmode (inline or display). I wish to control that myself. ;-)



I don't see a way of doing this nicely in ltcmd/xparse:

Argument types that might come into consideration for implementing some sort of handling of argument delimiters are:

  • r and R and d and D, but with these you must specify non-empty delimiters both before and behind the argument, and besides this, delimiters must consist of single tokens.
  • e and E, but like d and D embellishment-arguments are optional, so in case you omit a delimiter implemented via e/E/d/D-type-argument, you probably won't get an error message unless you implement error-checking yourself. Besides, in case an embellishment-argument is to consist of more than one token or is to be left empty, it must be wrapped in curly braces, which with TeX's delimited arguments is not needed.

What you can do in your specific case, where the delimiters of arguments are to consist of single tokens, is applying an D-type-argument with delimiters ( and ) and default | with a pre-processor like \SplitArgument or \SplitList for splitting at the | and feeding the result thereof to an auxiliary macro which processes two arguments and either delivers an error message or makes four of them which in turn are fed to yet another auxiliary macro which processes four arguments and delivers the tokens which after expansion shall make it into TeX's typesetting-machinery—this way you can manage error-handling and texts of error-messages yourself and probably get a low-level-TeX-error in case the closing parenthesis ) is missing:

\documentclass{article}

%---------------------------------------------------------------------
% With older LaTeX releases you need this, with recent ones you don't:
\ifx\IfBlankTF\UndEFiNEd
\ExplSyntaxOn
\cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF
\ExplSyntaxOff
\fi
%---------------------------------------------------------------------

\NewDocumentCommand {\braces} {>{\SplitArgument{1}{|}}D(){|}} {%
  \bracesi#1%
}

\makeatletter
\NewDocumentCommand {\bracesi} {mm} {%
  \IfNoValueTF{#2}{\@secondoftwo}{%
    \IfBlankTF{#2}{\@secondoftwo}{%
      \expandafter\IfBlankTF\expandafter{\@firstoftwo{}#2}{\@secondoftwo}{%
        \IfBlankTF{#1}{\@secondoftwo}{%
          \expandafter\IfBlankTF\expandafter{\@firstoftwo{}#1}{\@secondoftwo}{%
            \@firstoftwo
          }%
        }
      }%
    }%
  }%
  {\bracesii#1#2}%
  {\message{^^J^^J!!!\on@line: Cannot get four arguments from the pattern!!!^^J}}%
}
\makeatother

\NewDocumentCommand {\bracesii} {mmmm} {%
  \ensuremath{%
    \int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
  }%
}

\begin{document}

\braces(ab|cd)

% \braces()

% \braces(|)

% \braces(a|)

% \braces(|b)

% \braces(a|b)

% \braces(a|bc)

% \braces(ac|b)

% \braces(ac|)

% \braces(a|bc)

% \braces(ab) 

% \braces ab

% \braces c)

% \braces cd)

% \braces(AB|C % ) missing - low level error

% \braces(AB % ) missing - low level error

\end{document}

Or you define a macro with D-type argument and delimiters ( and | and default empty which feeds that argument, with | appended, to an auxiliary macro which processes one m-type argument denoting whether stuff between ( and | forms two arguments and two more m-type-arguments denoting the two arguments between ( and |and a D-type-argument with delimiters | and ) and default empty and in turn either feeds all these arguments to yet another macro which processes four arguments and delivers the tokens, which after expansion shall make it into TeX's typesetting-machinery, or delivers an error message—this way you can manage error-handling and texts of error-messages yourself and get low-level-TeX-error-messages when either | and/or ) is missing:

\documentclass{article}

%---------------------------------------------------------------------
% With older LaTeX releases you need this, with recent ones you don't:
\ifx\IfBlankTF\UndEFiNEd
\ExplSyntaxOn
\cs_new_eq:NN \IfBlankTF \tl_if_blank:nTF
\ExplSyntaxOff
\fi
%---------------------------------------------------------------------

\makeatletter
\NewDocumentCommand {\braces} {D(|{}} {%
  \IfBlankTF{#1}{\@secondoftwo}{%
    \expandafter\IfBlankTF\expandafter{\@firstoftwo{}#1}{\@secondoftwo}{\@firstoftwo}%
  }%
  {\bracesi{\@firstoftwo}#1|}%
  {\bracesi{\@secondoftwo}{}{}|}%
}
\NewDocumentCommand {\bracesi} {mmmD|){}} {%
  #1{%
    \IfBlankTF{#4}{\@secondoftwo}{%
      \expandafter\IfBlankTF\expandafter{\@firstoftwo{}#4}{\@secondoftwo}{\@firstoftwo}%
    }%
  }{\@secondoftwo}%
  {\bracesii{#2}{#3}#4}%
  {\message{^^J^^J!!!\on@line: Cannot get four arguments from the pattern!!!^^J}}%
}
\makeatother

\NewDocumentCommand {\bracesii} {mmmm} {%
  \ensuremath{%
    \int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
  }%
}

\begin{document}

\braces(ab|cd)

% \braces() % | missing - low level error

% \braces(|)

% \braces(a|)

% \braces(|b)

% \braces(a|b)

% \braces(a|bc)

% \braces(ac|b)

% \braces(ac|)

% \braces(a|bc)

% \braces(ab) % | missing - low level error

% \braces ab % ) missing - low level error

% \braces c)

% \braces cd)

% \braces(AB|C % ) missing - low level error

% \braces(AB % | missing - low level error

\end{document}
8
  • Can \cs_new_protected be used directly in a document? Still, xparse is needed for document level commands. Mar 11 at 18:00
  • In the same way that commands with @ can be defined in a document if surrounded by \makeatletter ... \makeatother, commands like \cs_new_protected:Npn can be used if surrounded by \ExplSyntaxOn ... \ExplSyntaxOff. And it's not necessary to use xparse methods for document level commands, it's just a convenient interface to lower level methods.
    – Alan Munn
    Mar 11 at 18:09
  • @sergiokapone You need to switch to expl3-mode for using \cs_new_protected:Npn, but you can, e.g., in expl3-mode do \cs_new_eq:NN \MyProtectedNewLongDef \cs_new_protected:Npn and then outside expl3-mode use \MyProtectedNewLongDef. | Let's put it this way: xparse is a convenient interface for creating commands for the document-level. But it is not the only means allowed for creating document-level-commands. Mar 11 at 18:15
  • @UlrichDiez Unfortunately, I've been using LaTeX for so long that I understand all of this... But there are also principled prohibitions for me "don't use exp3 commands at the document level". Mar 11 at 18:27
  • 1
    @matexmatics Oops. The code works badly. Sorry. In expl3-mode you can use implicit characters \sb or \c_math_subscript_token instead of _. Instead of ^ you can use implicit characters \sp or \c_math_superscript_token. Sorry for overlooking that. (Things get more interesting when you want, e.g., a ^ of category 7 or a _ of category 8 as argument delimiter in expl3-mode.) Mar 11 at 19:42
2

The code in the question introduced additional spaces. Below, these are removed with some %.

Then with \braces(abc|xyz), the c and z are not in the subscript, as shown below.

\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
    \ensuremath{%
        \int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
    }%
}
\begin{document}
\braces(abc|xyz)
\end{document}

enter image description here

Even with \braces(a{bc}|x{yz}), the c and z are not in the subscript, as shown below.

\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
    \ensuremath{%
        \int \frac{\chi_#1(1)\chi_#2(1)\chi_#3(2)\chi_#4(2)}{r_{12}} dV_1 dV_2%
    }%
}
\begin{document}
\braces(a{bc}|x{yz})
\end{document}

enter image description here

The reason is that there are no braces around #1 in \chi_#1 and so on.

If braces are added with \chi_{#1} and so on then c and z are in the subscript.

Now suppose that ab should be placed in the first subscript and xy in the third subscript. Then \braces({ab}c|{xy}z) can be used, as shown below.

\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
    \ensuremath{%
        \int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
    }%
}
\begin{document}
\braces({ab}c|{xy}z)
\end{document}

enter image description here

Now suppose that c|d should be placed in the second subscript. The code \braces({ab}c|d|{xy}z) gives the result below.

\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
    \ensuremath{%
        \int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
    }%
}
\begin{document}
\braces({ab}c|d|{xy}z)
\end{document}

enter image description here

This can be fixed with \braces({ab}{c|d}|{xy}z), as shown below.

\documentclass[border=6pt]{standalone}
\def\braces(#1#2|#3#4){%
    \ensuremath{%
        \int \frac{\chi_{#1}(1)\chi_{#2}(1)\chi_{#3}(2)\chi_{#4}(2)}{r_{12}} dV_1 dV_2%
    }%
}
\begin{document}
\braces({ab}{c|d}|{xy}z)
\end{document}

enter image description here

At this point it might be more convenient to be able to type \braces{ab}{c|d}{xy}{z} with 4 pairs of braces. Such a syntax can be easily defined with \newcommand or \NewDocumentCommand.

5
  • 1
    Why \ensuremath?
    – egreg
    Mar 11 at 13:57
  • @egreg It's an atavism from my example. I needed it outside of math mode. Mar 11 at 14:27
  • 2
    No, you don’t “need” it. There’s no reason for it.
    – egreg
    Mar 11 at 15:46
  • "The code in the question introduced additional spaces. Below, these are removed with some %." -- afaik, nowadays, people remove extra spaces via \ExplSyntaxOn. ;-) Mar 11 at 18:23
  • @UlrichDiez Yes but \ExplSyntaxOn does not immediately work in this situation due to the underscore in \chi_. Mar 11 at 19:04

You must log in to answer this question.

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