2

TLDR; How can I define a "double" environment like in theorems/proofs (with an optional proof)?

I'm defining a small library that is supposed to behave more or less like theorems/proof environments (I'm using xparse to parse the inputs if it matters). For now, my code is used that way:

\theoremProofEnd[my keys options]{thm}[mytitle]{My theorem}{My optional proof}

(when I don't have proof, I remove the last curly brackets)

But I'd like to make it closer to the usual way people define theorems and proof so that users are not changed too much. So I'd like to be able to use it like:

\begin{proofAtEnd}[my keys options]{thm}[mytitle]
  My theorem
\end{proofAtEnd}
\begin{proof} %% <- This environment is optional
  My optinal proof
\end{proof}

But I can't find how to do that... Any idea?

MWE: enter image description here

\documentclass{article}

\usepackage{xparse}
\usepackage{mathtools}
\usepackage{amssymb, amsthm, amsmath, thm-restate}
\usepackage{thmtools} %%

\newtheorem{thm}{Theorem}[section]


\NewDocumentCommand\theoremProofEnd{O{}mO{}+m+g}{
  The options are ``#1''.
  \begin{restatable}[#3]{#2}{mymacro}
    #4
  \end{restatable}
  \IfNoValueTF{#5}{}{
    \begin{proof}[Custom proof]
      #5
    \end{proof}
  }
}

\begin{document}

\section{My minilib}
% Current syntax
\theoremProofEnd[options A, options B]{thm}[My optional title]{My theorem}{My proof}

\theoremProofEnd[options C]{thm}{My theorem without proof and title}

%% Wanted syntax:
% \begin{proofAtEnd}[options A, options B]{thm}[My optional title]
%   My theorem
% \end{proofAtEnd}
% \begin{proof}
%   My proof
% \end{proof}
% 
% \begin{proofAtEnd}[options C]{thm}
%   My theorem without proof and title
% \end{proofAtEnd}

\end{document}
  • Maybe I'm missing something here but can't you just use your restatable and proof environments as desired already? – schtandard May 2 '19 at 10:49
  • @schtandard Well in practice the code is more complicated than a simple restatable, takes options, like the name of the section that should include the proof, the content of the text to put in the link... See tex.stackexchange.com/questions/484183/… for example. Now, I'd like to see if it's possible to use two environments instead of one command in order to look like the original syntax of theorems/proofs. – tobiasBora May 2 '19 at 11:52
  • 1
    I guess I just don't see the point of what you are asking. While it should be possible in principle, I would deem it extremely bad practice to have syntax that looks like environments not be environments. If you want to pass some information from proofAtEnd to proof (while keeping them distinct), just make it available outside of proofAtEnd. If you want to have one construct handling both, make the syntax reflect that. You could e.g. have one environment in which you can use an optional command to indicate that everything after belongs to the proof. Or just nest two environments. – schtandard May 2 '19 at 12:12
  • @schtandard the method where you define a macro in the first environment and get it from the proof could work, but it won't work it the second environment is facultative. And for the nesting of environments I don't see how to use them, would you have an example? – tobiasBora May 3 '19 at 11:22
1
+50

Since this is getting a bit extensive for the comments, here's an answer.


Firstly, let me stress that only clear syntax is good syntax. Syntax that looks like one thing but does something else entirely is just confusing. One of the strengths of (good) LaTeX is that syntax always reflects meaning; \emph emphasizes text (no matter what this means typographically), \begin starts an environment, \end ends it.

Thus, while possible in theory, I would strongly discourage building a syntax that looks like two separate environments where the second environment is really an optional argument. Instead, there are some alternatives you could choose from. (I will from now on call the first environment head and the second one tail.)

  1. You could really make the environments separate. If you want to pass some information from head to tail, make it available outside of head. This has the disadvantage of "leaking" macros and you have little control over where after head the user puts tail. It will however allow you to use the syntax you desire.

  2. You could use the second environment inside the first. This makes sense semantically (tail is an optional part of head) and makes designing the environments rather easy, too (you can make tail and the information needed by it unavailable outside of head naturally by the grouping provided by \begin and end).

  3. You could design a macro for use inside of head that marks everything up to \end{head} as part of tail. This is basically the same as the previous option with a slightly different syntax.

I would favor option 2 since it is the most straight forward.


Here's an example of all three options. I didn't dive deep into your link, but it seemed you wanted to store something for later output, so my head just typesets something and my tail collects its content with references to the corresponding head, which is then printed by \printtails.

All of the definitions could of course be improved depending on the use case, but I think the concept becomes clear here.

\documentclass{article}

\usepackage{etoolbox}
\usepackage{calc}
\usepackage{collect}
\usepackage{hyperref}

\makeatletter
    \newcounter{head}
    \newcounter{tail}
    \def\@printtails{}
    \def\printtails{\@printtails\def\@printtails{}}
    \newenvironment{headA}[2]{%
        \par\vskip 1em\noindent%
        \refstepcounter{head}%
        \protected@edef\@currentlabelname{#2}%
        \label{#1}%
        % make information public
        \xdef\@lasthead@label{#1}%
        \xdef\@lasthead@title{#1}%
        \centering
        {\Large\bfseries Head~\thehead : #2\par}%
    }{%
        \par\vskip 1em%
    }
    \newenvironment{headB}[2]{%
        \par\vskip 1em\noindent%
        \refstepcounter{head}%
        \protected@edef\@currentlabelname{#2}%
        \label{#1}%
        % make {tail} available
        \def\tailB{\@tailB{#1}{#2}}%
        \let\endtailB\end@tailB
        \centering
        {\Large\bfseries Head~\thehead : #2\par}%
    }{%
        \par\vskip 1em%
    }
    \newenvironment{headC}[2]{%
        \par\vskip 1em\noindent%
        \refstepcounter{head}%
        \protected@edef\@currentlabelname{#2}%
        \label{#1}%
        % reset the \end{tail} hook
        \let\@maybeendtail\relax
        % make {tail} available
        \def\tailC{%
            \let\@maybeendtail\end@tailB
            \@tailB{#1}{#2}%
        }%
        \centering
        {\Large\bfseries Head~\thehead : #2\par}%
    }{%
        % use the \end{tail} hook
        \@maybeendtail
        \par\vskip 1em%
    }
    \newenvironment{@printtail}[2]{%
        \par\vskip 1em\noindent
        \setcounter{tail}{\expandafter\expandafter\expandafter\@firstoffive\csname r@#1\endcsname-1}%
        \refstepcounter{tail}%
        \protected@edef\@currentlabelname{The Tail of Head~\ref*{#1} ({\slshape\nameref*{#1}})}%
        \label{tailof:#1}%
        \begin{tabular}{|p{\textwidth-2\tabcolsep}|}%
        {\bfseries The Tail of Head~\ref{#1} ({\slshape\nameref{#1}})\quad}%
    }{%
        \end{tabular}%
        \par\vskip 1em%
    }
    \newenvironment{tailA}{%
        \xappto\@printtails{%
            \noexpand\begin{@printtail}{\@lasthead@label}{\@lasthead@title}%
                \expandafter\noexpand\csname @tailcontent@\@lasthead@label\endcsname
            \noexpand\end{@printtail}%
        }%
        \collectinmacro\@temp@tailcontent{}{}%
    }{%
        \endcollectinmacro
        \expandafter\expandafter\expandafter
        \gdef
        \expandafter\expandafter
        \csname @tailcontent@\@lasthead@label\endcsname
        \expandafter
        {\@temp@tailcontent}%
    }
    \newenvironment{@tailB}[2]{%
        \xappto\@printtails{%
            \noexpand\begin{@printtail}{#1}{#2}%
                \expandafter\noexpand\csname @tailcontent@#1\endcsname
            \noexpand\end{@printtail}%
        }%
        \def\@temp@headlabel{#1}%
        \collectinmacro\@temp@tailcontent{}{}%
    }{%
        \endcollectinmacro
        \expandafter\expandafter\expandafter
        \gdef
        \expandafter\expandafter
        \csname @tailcontent@\@temp@headlabel\endcsname
        \expandafter
        {\@temp@tailcontent}%
    }
\makeatother

\begin{document}

Have a look at tail~\ref{tailof:head:lorem} with the title \nameref{tailof:head:lorem}.
Or maybe consider tail~\ref{tailof:head:die} with the title \nameref{tailof:head:die}.

\begin{headA}{head:wine}{Better Than Grapes}
    In vino veritas.
\end{headA}

\begin{headA}{head:lorem}{This Is a Test}
    Lorem ipsum dolor sit amet.
\end{headA}
\begin{tailA}
    Well, it looks like Latin, but it doesn't actually mean anything, does it?
    Anyhow, people won't care if we just use it as filler.
\end{tailA}

\begin{headB}{head:something-else}{Something Else}
    Haec non sunt verba.
    \begin{tailB}
        Okay, then.
    \end{tailB}
\end{headB}

\begin{headC}{head:die}{Roll the die}
    Alea iacta est.
    \tailC
    Yes, I'm running out of sentences.
\end{headC}

\printtails

\end{document}

example output

  • Thanks a lot for this very detailed answer! I'll still spend some time to understand how you do everything, but it's very interesting. I think the first option will be the one I will chose because it seems more powerful and close to my needs. Thanks! – tobiasBora May 6 '19 at 9:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.