2

I use an environment "exo" defined by

\usepackage{amsmath}
\newtheorem{exo}{Exercice}

I would like to optionally include some exercises later in the document, using the following:

\makeatletter
\newcounter{nbexosfac}
\setcounter{nbexosfac}{0}
\newcommand{\exofacultatif}[2][]{
  \stepcounter{nbexosfac}
  \edef\tmp{\string\thenbexosfac}
  \expandafter\def\csname exosfacopt\tmp\endcsname{#1}
  \expandafter\def\csname exosfaccorps\tmp\endcsname{#2}
}
\newcounter{myaux}
\newcommand{\restitueexos}{
  \ifnum\thenbexosfac>0%
    \begin{center} Exercices supplémentaires \end{center}
    \setcounter{myaux}{0}
    \@whilenum\value{myaux}<\value{nbexosfac}\do{
      \stepcounter{myaux}
      \edef\tmp{\string\themyaux}
      \begin{exo}[\csname exosfacopt\tmp\endcsname]
        \csname exosfaccorps\tmp\endcsname
      \end{exo}
    }
    \setcounter{nbexosfac}{0}
  \fi
}
\makeatother

However it does not work as intended in the document:

\begin{document}

\begin{exo} Texte 1 \end{exo}

\exofacultatif{Texte 2}

\begin{exo}[essai 3] Texte 3 \end{exo}

\exofacultatif[essai 4]{Texte 4}

\restitueexos

\end{document}

The stored data is not retrieved, but it adds an superfluous "()": \exofacultatif{} is not equivalent to \begin{exo}[] \end{exo}.

Any idea ?

Edit: I removed the superfluous \def\withexosfac{} and \ifdefined\withexosfac.

Edit 2: The solution by egreg is better. However I found a solution that seems to work, even if I am not sure why:

\makeatletter
\newcounter{nbexosfac}
\setcounter{nbexosfac}{0}
\newcommand{\exofacultatif}[2][]{
  \stepcounter{nbexosfac}
  \expandafter\def\csname exosfacopt\string{\thenbexosfac}\endcsname{#1}
  \expandafter\def\csname exosfaccorps\string{\thenbexosfac}\endcsname{#2}
}
\newcounter{myaux}
\newcommand{\restitueexosfac}{
  \ifnum\thenbexosfac>0%
    (...)
    \setcounter{myaux}{0}
    \@whilenum\value{myaux}<\value{nbexosfac}\do{
      \stepcounter{myaux}
      \edef\tmp{\csname exosfacopt\string{\themyaux}\endcsname}
      \ifx\tmp\empty
        \begin{exo}
      \else
        \begin{exo}[\tmp]
      \fi
        \csname exosfaccorps\string{\themyaux}\endcsname
      \end{exo}
    }
    \setcounter{nbexosfac}{0}
  \fi
}
\makeatother

Edit 3: So, on the basis of the code by egreg, I wrote

\documentclass{article}

\usepackage{amsmath} \usepackage{hyperref} \newtheorem{exo}{Exercise}

\ExplSyntaxOn \seq_new:N \exof_seq

\NewDocumentEnvironment{exo*}{+b} { \seq_gput_right:Nn \exof_seq { \begin{exo} #1 \end{exo} } }{}

\newcommand{\restitueexosfac}{ \seq_if_empty:NF \exof_seq {% \section*{Exercices~complémentaires}% } \seq_use:Nn \exof_seq {} \seq_clear:N \exof_seq } \ExplSyntaxOff

\begin{document}

\section{Titre 1}

\begin{exo} Texte 1 \end{exo}

\begin{exo} Texte 2 \end{exo}

\section*{Autre titre}

\begin{exo}[essai 3] Texte 3 \end{exo}

\begin{exo}[essai 4] Texte 4 \end{exo}

\restitueexosfac

\section{Titre 2}

\begin{exo} Texte 5 \end{exo}

\restitueexosfac

\end{document}

Edit 4: The following is not relevant any more.

However, you can see that the space is lost in the \section* command inside \restitueexosfac. Is there a reason it is lost here and not in the \section*{Autre titre} command elsewhere? I can use ~ or \ but I would prefer to change \restitueexosfac so that it is not necessary. Any idea?

  • I tried to adapt from https://tex.stackexchange.com/questions/215563/storing-an-array-of-strings-in-a-command – dominique Sep 04 '22 at 10:15
  • @Ulrich \documentclass{article}. Sorry. I also see that a complete document is compiled in the page by tex.stackexchange.com. – dominique Sep 04 '22 at 13:17
  • about Edit 2: it worked, then not... So I now use the solution by egreg. – dominique Sep 04 '22 at 14:37
  • 1
    In expl3 syntax (\ExplSyntaxOn) spaces are not tokenized as space tokens but ignored in any case. If you want a space token in expl3-syntax, write ~. Outside expl3-syntax that denotes a non-breaking space. Inside expl3-syntax that denotes a normal breaking space/is tokenized as space-token/explicit character token of category 10(space) and character code 32.So, while in expl3-syntax do \section*{Exercices~complémentaires}%. – Ulrich Diez Sep 04 '22 at 17:32
  • @Ulrich : Thanks. I think I have now the final answer – dominique Sep 04 '22 at 17:48

3 Answers3

3

I suggest to store the facultative exercises in a sequence that you can eventually deliver.

\documentclass{article}
\usepackage{amsmath}
\usepackage{amsthm}

\newtheorem{exo}{Exercice}

\ExplSyntaxOn

\seq_new:N \g_dominique_exof_seq

\NewDocumentEnvironment{exo*}{+b} { \seq_gput_right:Nn \g_dominique_exof_seq { \begin{exo} #1 \end{exo} } } {}

\NewDocumentCommand{\restituteexos}{} { \section*{Exercices~supplémentaires} \seq_use:Nn \g_dominique_exof_seq {} }

\ExplSyntaxOff

\begin{document}

\begin{exo} Texte 1 \end{exo}

\begin{exo} Texte 2 \end{exo}

\begin{exo}[essai 3] Texte 3 \end{exo}

\begin{exo}[essai 4] Texte 4 \end{exo}

\restituteexos

\end{document}

With the +b argument type you can input exo* like exo and it would be easy to transform one type into the other.

enter image description here

egreg
  • 1,121,712
  • Thanks. It is a more general solution. I did not know the syntax \seq_new:N \g_dominique_exof_seq for lists. – dominique Sep 04 '22 at 13:04
2

The code provided by egreg is definitely preferable because it opens up many more possibilities.

In the following - only to show the problems with the code of the initial posting - a variant in which as little as possible was changed compared to the code of the initial posting:

\documentclass{article}

\usepackage{amsmath} \newtheorem{exo}{Exercice}

\makeatletter \newcounter{nbexosfac} \setcounter{nbexosfac}{0} \begingroup \def\passtodefinitions#1{% \endgroup \newcommand*\mynovaluemarker{#1}% \newcommand{\exofacultatif}[2][#1]% }% \catcode`-=3 % \expandafter\passtodefinitions\expandafter{\expandafter-\detokenize{NoValue-}}{%% @bsphack \stepcounter{nbexosfac}%% %% \edef\tmp{\string\thenbexosfac}%% <- This does not make sense! Don't do this! Don't stringify the token \themyaux !!! \begingroup\toks@{#1}\edef\tmp{\the\toks@}\expandafter\endgroup\ifx\tmp\mynovaluemarker\else \expandafter@ifdefinable\csname exosfacopt\number\value{nbexosfac}\endcsname{% \global@namedef{exosfacopt\number\value{nbexosfac}}{#1}%% }% \fi \expandafter@ifdefinable\csname exosfaccorps\number\value{nbexosfac}\endcsname{% \global@namedef{exosfaccorps\number\value{nbexosfac}}{#2}%% }% @esphack } \newcounter{myaux} \newcommand{\restitueexos}{%% \ifnum\thenbexosfac>0 %%<- leave this space - it terminates the number-quantity !!! \begin{center}Exercices supplémentaires\end{center}%% \setcounter{myaux}{0}%% @whilenum\value{myaux}<\value{nbexosfac}\do{%% \stepcounter{myaux}%% %% \edef\tmp{\string\themyaux}%% <- This does not make sense! Don't do this! Don't stringify the token \themyaux !!! @ifundefined{exosfaccorps\number\value{myaux}}{}{% @ifundefined{exosfacopt\number\value{myaux}}{% \begin{exo}%% }{% \begin{exo}[@nameuse{exosfacopt\number\value{myaux}}]%% }% @nameuse{exosfaccorps\number\value{myaux}}%% \end{exo}%% }% }%% \setcounter{nbexosfac}{0}%% \fi } \makeatother

\begin{document}

\begin{exo} Texte 1 \end{exo}

\exofacultatif{Texte 2}

\begin{exo}[essai 3] Texte 3 \end{exo}

\exofacultatif[essai 4]{Texte 4}

\restitueexos

\end{document}

enter image description here

Ulrich Diez
  • 28,770
  • Thanks. I had found a less effective solution with \edef\tmp{\csname exosfacopt\string{\themyaux}\endcsname} and \ifx\tmp\empty. – dominique Sep 04 '22 at 13:02
  • 1
    @dominique If you wish to check whether an optional argument was provided at all, consider using \NewDocumentCommand and \IfNoValueTF instead of \newcommand. With recent LaTeX releases these things are in the LaTeX 2e kernel. With not so recent LaTeX releases these things are in the package xparse. – Ulrich Diez Sep 04 '22 at 13:09
0

Instead of counters and macros the \addtocontents-\@starttoc-mechanism might be an option. Using this mechanism you can place supplementary exercises into the document wherever you like, not just after all other exercises.

\documentclass{article}

\usepackage{amsmath} \newtheorem{exo}{Exercice} \usepackage{hyperref}

\makeatletter \newcounter{nbexosfac} \newcommand\PassFirstToSecond[2]{#2{#1}} \NewDocumentCommand{\exofacultatif}{om}{%% \Hy@SaveLastskip \IfNoValueTF{#1}{% \addtocontents{exo}{\ExoDelayed{#2}\protected@file@percent}% }{% \addtocontents{exo}{\ExoDelayed[{#1}]{#2}\protected@file@percent}% }% \Hy@RestoreLastskip } \NewDocumentCommand{\ExoDelayed}{om}{%% \IfNoValueTF{#1}{\begin{exo}}{\begin{exo}[{#1}]}#2\end{exo}% }%% \newcommand\restitueexos{% \section{Exercices supplémentaires}% \begingroup \providecommand\lastExo{0}% \expandafter\PassFirstToSecond\expandafter{\number\value{exo}}{% \setcounter{exo}{\lastExo}% @starttoc{exo}% \setcounter{exo}% }% \endgroup }% \AtEndDocument{% \protected@write@auxout{}{\string\gdef\string\lastExo{\number\value{exo}}}% } \makeatother

\begin{document}

\restitueexos

\bigskip\hrule\bigskip

\begin{exo} Texte 1 \end{exo}

\exofacultatif{Texte 2}%

\begin{exo}[essai 3] Texte 3 \end{exo}

\exofacultatif[essai 4]{Texte 4}%

\end{document}

enter image description here

Yet another option might be using the package "datatool" for maintaining two database of supplementary exercises:

One database is used for adding data to it. It is created during the LaTeX-run. At the end of the LaTeX-run it is written to .csv-file or the like.
The other database is used for obtaining data during the LaTeX-run. It is created at the begin of the LaTeX-run by reading the .csv-file if that exists.
You can process the database used for obtaining data during the LaTeX-run within the document as often as you like, sorting out entries as you like. This might be useful for having supplementary exercises per section or chapter or the like.

Ulrich Diez
  • 28,770
  • It is really interesting, I learn a lot. However I planned to use \restitueexos several times, more like a FIFO queue : I add exercises to my queue with \exofacultatif, I empty my queue with \restitueexos. It does not seem compatible. – dominique Sep 04 '22 at 15:19