1

I want to write a macro \createTheorem that creates two environments: a normal one and a "capitalised" one.

For example, \createTheorem{defi}{Definition} will create :

  • an environment \begin{defi}...\end{defi}
  • and an environment \begin{Defi}...\end{Defi}.

How would you do that? I would like to know why my code doesn't work.

My code

Here is what I have tried. It doesn't work, the error being

Missing \endcsname inserted. \protect l.13 \documentclass{article}

\usepackage{amsmath}

\newtheorem{theoremForCounter}{theoremForCounter}

\newcommand{\createTheorem}[2] { \def\nameNewTheoremCapitalized{\MakeUppercase{#1}} \newtheorem{#1}[theoremForCounter]{#2} \newtheorem{\nameNewTheoremCapitalized}[theoremForCounter]{#2} }

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi} This is a test. \end{defi}

\begin{Defi} This is a test. \end{Defi}

\end{document}

Colas
  • 6,772
  • 4
  • 46
  • 96

3 Answers3

1

As mentioned above, MakeUppercase is not expandable. You can use expl3 functions str_uppercase:f instead which is expandable:

%! TEX program = lualatex
\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn \newcommand{\createTheorem}[2] { \def\nameNewTheoremCapitalized{\str_uppercase:f{\tl_head:n{#1}}\tl_tail:n{#1}} \newtheorem{#1}{#2} \exp_args:Nx\newtheorem{\nameNewTheoremCapitalized}{#2} } \ExplSyntaxOff

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi} This is a test. \end{defi}

\begin{Defi} This is a test. \end{Defi}

\end{document}

Remark:

  • in pdflatex \tl_head will take the first byte of the name instead of the first character, so I don't know what happens if the first character is not a simple ASCII character.
  • If the first character is not a lowercase character newtheorem will raise error because the two names are identical.
  • Your macro definition has spurious spaces. Not so with \ExplSyntaxOn.
  • In this case the implementation of newtheorem happens to already expand the argument inside, so there's no need of expanding the argument before passing to it... nevertheless I'm not sure if this behavior the guaranteed... so I add \exp_args:Nx just in case.
user202729
  • 7,143
  • Thank you for your answer. Can you give a LaTeX solution? I've tried adding \usepackage{expl3} and compiling with LaTeX but it does not work. – Colas Jun 12 '22 at 18:43
  • @Colas expl3 is a LaTeX solution and part of the kernel for the last two years. One could help you better if you added more information than "does not work". – Skillmon Jun 12 '22 at 21:06
  • My distribution is too old I think. I have to put \usepackage{expl3} but still there is an error: Undefined control sequence. \nameNewTheoremCapitalized ->\str_uppercase:f. I'll try download a newer version of expl3. – Colas Jun 12 '22 at 21:30
  • 1
    @Colas don't only update to a newer version of expl3 (that won't work, I'm afraid). Just update to a newer TeX Live version. Alternatively, put the following after \ExplSyntaxOn: \cs_generate_variant:Nn \str_uppercase:n { f }. – Skillmon Jun 13 '22 at 09:33
1

You can use the TeX primitive \uppercase directly, but this is still not expandable, so we have to trick a bit. \createTheorem@a is used to get the first character, and calls \createTheorem@b after the first character was already upper-cased, and puts the name back together.

\documentclass{article}

\usepackage{amsmath}

\makeatletter \long\def\createTheorem@a#1#2\end {\uppercase{\createTheorem@b{#1}}{#2}} \newcommand\createTheorem@b[2]{\newtheorem{#1#2}} \newcommand{\createTheorem}[2] {% \newtheorem{#1}{#2}% \createTheorem@a#1\end{#2}% } \makeatother

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi} This is a test. \end{defi}

\begin{Defi} This is a test. \end{Defi}

\end{document}

Skillmon
  • 60,462
  • Thanks, it works fine. I would to do the same trick with a command \myCommand{} which takes one argument. What would be the syntax to create a command \myCommandWithCapital{}? Thanks – Colas Jun 12 '22 at 22:06
  • @Colas Not sure what you mean -- nevertheless if the question is sufficiently different consider asking a new question instead. (by the way you might want to read the TeXbook to learn some TeX programming and understand this answer.) – user202729 Jun 13 '22 at 00:32
  • 1
    @Colas, the solution is the same. Just use \newtheorem{#1}[WHATEVER]{#2} in \createTheorem and \newtheorem{#1#2}[WHATEVER] in \createTheorem@b. – Skillmon Jun 13 '22 at 09:41
1

I'm not sure what would the usage of this would be: having two environments defi and Defi that do exactly the same is useless and possibly confusing.

Anyway, you can use \text_titlecase:n (with a LaTeX released after March 2020).

\documentclass{article}
\usepackage{amsthm} % probably you wanted this one

\newcounter{counterForTheorem}

\ExplSyntaxOn \cs_new:Npn \uppercasefirst #1 { \str_uppercase:f { \tl_head:n { #1 } } \tl_tail:n { #1 } } \ExplSyntaxOff

\newcommand{\createTheorem}[2]{% \newtheorem{#1}[counterForTheorem]{#2}% \newtheorem{\uppercasefirst{#1}}[counterForTheorem]{#2}% }

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi} This is a test. \end{defi}

\begin{Defi} This is a test. \end{Defi}

\end{document}

Alternative implementation:

\documentclass{article}
\usepackage{amsthm} % probably you wanted this one

\newcounter{counterForTheorem}

\makeatletter \newcommand{\createTheorem}[2]{% \newtheorem{#1}[counterForTheorem]{#2}% \begingroup \edef\temp@a{@car#1@nil}% \edef\temp@b{@cdr#1@nil}% \begingroup\edef\x{\endgroup\uppercase{\def\noexpand\temp@a{\temp@a}}}\x \edef\temp@a{\temp@a\temp@b}% \expandafter\endgroup\expandafter\newtheorem\expandafter{\temp@a}[counterForTheorem]{#2}% } \makeatother

\createTheorem{defi}{Definition}

\begin{document}

\begin{defi} This is a test. \end{defi}

\begin{Defi} This is a test. \end{Defi}

\end{document}

egreg
  • 1,121,712