
Estoy intentando escribir un paquete, similar al paquete de ejercicios, para poder preparar conjuntos de problemas para mis alumnos. Deseo retrasar la publicación de los problemas y/o soluciones hasta que se haya alcanzado un lugar adecuado en el documento. Tengo algo que funciona pero es un poco torpe. Por ejemplo, esto funciona bastante bien:
\usepackage{environ}
\NewEnviron{testb}{\global\expandafter\let\csname bar\endcsname\BODY}
Lo uso \csname
porque los nombres se generan dinámicamente. Esto no funciona tan bien si el comando no es \BODY
. Por ejemplo, si lo hago \let\bar{\BODY}
, el látex tiene un aneurisma (se une \bar
solo a {).
Existe una forma alternativa de hacer esto, que es:
\NewEnviron{testc}{\global\expandafter\edef\csname foo\endcsname{\BODY}}
Este tipo de obras. Lo siguiente funciona:
\begin{testc}hi\end{testc}
, pero esto le da a LaTeX un aneurisma: \begin{testc}\bf hi\end{testc}
. (El mensaje de error es \incomplete
). Intenté depurarlo yo mismo pero me enredo irremediablemente en paquetes que no entiendo. Si lo hace en \tiny
lugar de, \bf
obtendrá el mensaje de error de LaTeX tremendamente diferente:! TeX capacity exceeded, sorry [input stack size=5000].
¿Cómo puedo guardarlo para más adelante, no solo \BODY
, sino también para alguna combinación sofisticada de \BODY
y otras cosas, y al mismo tiempo tenerlo sólido para lo que hay entre el principio y el final?
Editar: ok, varias soluciones a continuación
Respuesta1
Con \unexpanded
podrás evitar preocuparte \protected@xdef
.
\documentclass{article}
\usepackage{environ}
\NewEnviron{exercise}{%
\xdef\savedexercises{%
\unexpanded\expandafter{\savedexercises}%
\noexpand\begin{printedexercise}%
\unexpanded\expandafter{\BODY}%
\noexpand\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\savedexercises
\gdef\savedexercises{}%
}
\newcommand{\savedexercises}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Lo usé \newtheorem
solo para el ejemplo.
Con xparse
lanzamiento el 2019-03-05 o posterior:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentEnvironment{exercise}{+b}
{
\tl_gput_right:Nn \g_loisel_exercises_tl
{
\begin{printedexercise}
#1
\end{printedexercise}
}
}{}
\NewDocumentCommand{\printexercises}{}
{
\tl_use:N \g_loisel_exercises_tl
\tl_gclear:N \g_loisel_exercises_tl
}
\tl_new:N \g_loisel_exercises_tl
\ExplSyntaxOff
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Respuesta2
Si desea BODY
guardarlo, agregue cosas dinámicamente; probablemente sea mejor usar dos macros:
\documentclass{article}
\usepackage{environ}
\NewEnviron{testb}{%
\global\expandafter\let\csname bar\endcsname\BODY
\expandafter\xdef\csname barplus\endcsname{%
\expandafter\noexpand\csname bar\endcsname
\noexpand\bf Hi
}%
}
\begin{document}
\begin{testb}
\bfseries
Hi
\end{testb}
\show\barplus
\end{document}
Si quieres evitar el uso, \BODY
puedes usarxparse
\documentclass{article}
\usepackage{xparse}
\NewDocumentEnvironment{testb}{+b}{\expandafter\gdef\csname bar\endcsname{#1}}{}
\begin{document}
\begin{testb}
\bfseries
Hi
\end{testb}
\show\bar
\end{document}
Respuesta3
Un truco para activar la expansión es usar \romannumeral
:
Cuando debido a \romannumeral
(La)TeX reúne una secuencia de dígitos seguidos por un espacio como el número que tiene que convertir, los tokens expandibles se expanden.
Cuando al final se reúne un número que no es positivo, como resultado de la conversión (La)TeX no entregará ningún token.
Por lo tanto, uno puede usar muy bien (¿ab?) \romannumeral
para desencadenar una gran cantidad de trabajo de expansión y cambiar argumentos, siempre y cuando se asegure de que al final \romannumeral
no encontrará un número positivo.
He aquí una variante dela respuesta de egregque hace con \romannumeral
y \exchange
en lugar de \xdef
y \unexpanded
.
\documentclass{article}
\usepackage{environ}
\newcommand\exchange[2]{#2#1}
\NewEnviron{exercise}{%
\expandafter\gdef\expandafter\savedexercises\expandafter{%
\romannumeral0\expandafter\exchange\expandafter{\BODY}{%
\exchange{ }{\expandafter}\savedexercises
\begin{printedexercise}%
}%
\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\savedexercises
\gdef\savedexercises{}%
}
\newcommand{\savedexercises}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Si desea envolver el nombre de la macro que se va a definir en \csname
.. \endcsname
, es decir, si desea utilizarlo \csname savedexercises\endcsname
en lugar de \savedexercises
, puede aprovechar el hecho de que (La)TeX expande los tokens expandibles mientras reúne \csname
el nombre de un token de secuencia de control y buscando la coincidencia \endcsname
:
\documentclass{article}
\usepackage{environ}
\newcommand\exchange[2]{#2#1}
\NewEnviron{exercise}{%
\expandafter\gdef\csname savedexercises\expandafter\endcsname\expandafter{%
\romannumeral0\expandafter\exchange\expandafter{\BODY}{%
\exchange{ }{\expandafter\expandafter\expandafter}\csname savedexercises\endcsname
\begin{printedexercise}%
}%
\end{printedexercise}%
}%
}
\newcommand{\printexercises}{%
\csname savedexercises\endcsname
\expandafter\gdef\csname savedexercises\endcsname{}%
}
\expandafter\newcommand\expandafter{\csname savedexercises\endcsname}{}
\newtheorem{printedexercise}{Exercise}
\begin{document}
Here we talk about addition and show that $1+1=2$.
\begin{exercise}
Compute $1+2$
\end{exercise}
Here we talk about integrals.
\begin{exercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{exercise}
Now we can print the exercises.
\printexercises
\end{document}
Tenga en cuenta que con los enfoques presentados hasta ahora no puede utilizarlos \printexercises
para que los ejercicios se realicen en lugares arbitrarios. Puede hacer que los ejercicios se realicen sólo en lugares del documento que en la fuente corresponden a lugares detrás de los entornos de ejercicio.
Quizás un entorno que lea su contenido bajo el régimen verbatim-catcode-régime para escribirlo sin expandir en un archivo .aux de manera que desde el archivo .aux se vuelva a leer bajo el régimen verbatim-catcode también para definir una macro donde \scantokens
se aplicará y, por lo tanto, algún tipo de reimplementación del \label
- \ref
-mecanismo o del \tableofcontents
-mecanismo para material textual podría hacer posible hacer ejercicios imprimibles en todo el documento.
Implementar un mecanismo de este tipo podría ser un gran desafío. Pero antes de tomar eso en consideración, se necesita información exacta sobre el uso previsto y la "interfaz de usuario" deseada, es decir, qué cosas adicionales desea poder especificar, de qué manera, etc.
Respuesta4
Otra variante, usando filecontentsdef v1.4
, admite verbatim
contenido (si es necesario).
\documentclass{article}
\usepackage{filecontentsdef,pgffor}
\setlength{\parindent}{0pt}
\pagestyle{empty}
\newtheorem{exercise}{Exercise}
% savedexercise
\newcounter{exeNr}
\newenvironment{savedexercise}
{\stepcounter{exeNr}%
\begingroup
\filecontentsdefmacro{exercise-\the\value{exeNr}}}%
{\endfilecontentsdefmacro\endgroup}
\newcommand{\printexercise}[1]{\filecontentsexec{exercise-\the\numexpr#1\relax}}
\newcommand{\printsrcexercise}[1]{\filecontentsprint{exercise-\the\numexpr#1\relax}}
\begin{document}
\section{Talk about math}
Here we talk about addition and show that $1+1=2$.
\begin{savedexercise}
Compute $1+2$
\end{savedexercise}
Here we talk about integrals.
\begin{savedexercise}
Compute the following integrals:
\begin{itemize}
\item $\displaystyle\int_0^x e^{-t^2}\,dt$
\item $\displaystyle\int_1^x \frac{e^t}{t}\,dt$, for $t>0$.
\end{itemize}
\end{savedexercise}
\section{The exercises}
Now we can print the exercises.
\foreach \i in {1,...,2} {
\begin{exercise}
\printexercise{\i}
\end{exercise}
}
\section{The src exercises}
Now we can print the src of exercises.
\foreach \i in {1,...,2} {
\printsrcexercise{\i}
}
\section{Back to first exercises}
Remember the first exercise
\setcounter{exercise}{0}
\begin{exercise}
\printexercise{1}
\end{exercise}
\end{document}