
Tengo la siguiente situación de bucle anidado:
\begingroup
\def\do##1{%
\begingroup
\def\do####1{%
\csletcs{somemacro@##1@####1}{someothermacro@##1@####1}}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
donde necesito que la \csletcs
definición exista fuera de los dos grupos peronoglobalmente. Hay un buen truco de Martin Scharrer en un comentario a esta pregunta:
¿Cómo obtengo un valor de un grupo?
pero no funciona en un bucle como este, ya que poner la \endgroup
s en el bucle interno realmente arruina las siguientes iteraciones del bucle. ¿Hay alguna forma (etoolbox está bien) de obtener las \csletcs
definiciones de los grupos sin romper más iteraciones de los bucles? Supongo que necesito los grupos; de lo contrario, los argumentos del bucle do no hacen referencia correctamente.
Para completar, aquí hay un intento de solución utilizando el truco de Martin Sharrer:
\begingroup
\def\do##1{%
\begingroup
\def\do####1{%
\edef\@z{\endgroup\endgroup\csletcs{somemacro@##1@####1}{someothermacro@##1@####1}}\@z}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
Esto funciona para la primera iteración anidada y el cs resultante se define correctamente fuera de los grupos. Desafortunadamente, los grupos se cierran y las siguientes iteraciones son un verdadero desastre.
Respuesta1
Su ejemplo está un poco incompleto (tuve que hacer algunos cambios para que se compilara), pero la esencia de la respuesta es simplemente recopilar sus definiciones en una lista de tokens (configurada globalmente) y luego expandir la lista después del segundo grupo ( provocando definiciones locales).
\documentclass{article}
\usepackage{etoolbox}
\begin{document}
\makeatletter
\def\somelista{x}
\def\somelistb{y}
\texttt{\meaning\somemacro@y@x}
\def\someothermacro@y@x{a}
\begingroup
\def\do#1{%
\begingroup
\def\do##1{%
\global\toks1=\expandafter{\the\toks1 \csletcs{somemacro@#1@##1}{someothermacro@#1@##1}}}%
\dolistloop\somelista
\endgroup}%
\dolistloop\somelistb
\endgroup
\the\toks1
\texttt{\meaning\somemacro@y@x}
\makeatother
\end{document}
Da: "macro indefinida:->a" como salida tipográfica.
Respuesta2
Puede usar cualquier controlador que desee para procesar una lista usando \forlistloop
en lugar de \dolistloop
; por lo que no es necesario redefinir \do
en un grupo para no alterar la definición del bucle externo: simplemente use dos controladores diferentes.
\documentclass{article}
\usepackage{etoolbox}
\newcommand\processlistb[1]{%
\def\temp{#1}%
\forlistloop\processlista\somelista
}
\newcommand\processlista[1]{%
\csletcs{somemacro@\temp @#1}{someothermacro@\temp @#1}%
\csshow{somemacro@\temp @#1}%
}
\listadd\somelista{a}
\listadd\somelista{b}
\listadd\somelista{c}
\listadd\somelistb{x}
\listadd\somelistb{y}
% Just to add some mock definitions
\csdef{someothermacro@x@a}{xa}
\csdef{someothermacro@x@b}{xb}
\csdef{someothermacro@x@c}{xc}
\csdef{someothermacro@y@a}{ya}
\csdef{someothermacro@y@b}{yb}
\csdef{someothermacro@y@c}{yc}
% Do the iterations
\forlistloop\processlistb\somelistb
\stop
La parte relevante del archivo de registro:
> \somemacro@x@a=macro:
->xa.
<recently read> \somemacro@x@a
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@x@b=macro:
->xb.
<recently read> \somemacro@x@b
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@x@c=macro:
->xc.
<recently read> \somemacro@x@c
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@a=macro:
->ya.
<recently read> \somemacro@y@a
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@b=macro:
->yb.
<recently read> \somemacro@y@b
l.29 \forlistloop\processlistb\somelistb
?
> \somemacro@y@c=macro:
->yc.
<recently read> \somemacro@y@c
l.29 \forlistloop\processlistb\somelistb
?