Obtendo definições \let de dentro de um grupo, dentro de um loop

Obtendo definições \let de dentro de um grupo, dentro de um loop

Eu tenho a seguinte situação de loop aninhado:

\begingroup
  \def\do##1{%
    \begingroup
      \def\do####1{%
         \csletcs{somemacro@##1@####1}{someothermacro@##1@####1}}%
      \dolistloop\somelista
    \endgroup}%
  \dolistloop\somelistb
\endgroup

onde preciso que a \csletcsdefinição exista fora dos dois grupos, masnãoglobalmente. Há um belo truque de Martin Scharrer em um comentário a esta pergunta:

Como obtenho um valor de um grupo?

mas não funciona em um loop como esse, pois colocar \endgroups no loop interno realmente atrapalha as próximas iterações do loop. Existe alguma maneira (o etoolbox está ok) de \csletcsretirar as definições dos grupos sem interromper outras iterações dos loops? Presumo que preciso dos grupos, caso contrário os argumentos do loop não fazem referência corretamente.

Apenas para completar, aqui está uma tentativa de solução usando o truque 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

Isso funciona para a primeira iteração aninhada e o cs resultante é definido corretamente fora dos grupos. Infelizmente, os grupos são fechados e as próximas iterações são uma verdadeira bagunça.

Responder1

Seu exemplo está um pouco incompleto (tive que fazer algumas alterações para compilar), mas a essência da resposta é apenas coletar suas definições em uma lista de tokens (definida globalmente) e expandir a lista após o segundo grupo ( causando definições locais).

\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}

Fornece: "macro indefinida:->a" como saída da composição.

Responder2

Você pode usar qualquer manipulador que desejar para processar uma lista em \forlistloopvez de \dolistloop; então você não precisa redefinir \doem um grupo para não atrapalhar a definição do loop externo: basta usar dois manipuladores 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

A parte relevante do arquivo de log:

> \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

?

informação relacionada