Versões abstratas

Versões abstratas

Eu gostaria de definir um comando de 'construção de macro' do TeX (vamos chamá-lo de \buildmacro) que receba como argumento uma sequência de caracteres 'normais' (por exemplo, Title) e que satisfaça o seguinte:

  • o comando \buildmacro{Title}define o contador com o nome TitleXcountere o inicializa como 0.
  • ao emitir em algum ponto do arquivo o comando TeX \Title{<arg>}, isso terá o efeito de aumentar o contador TitleXcountere então colocar o valor <arg>em uma nova macro TeX com o nome \Title-<x>, onde <x>é o valor atual de TitleXcounter;

    aqui <arg>está um pedaço de código TeX (que pode conter texto, matemática, parágrafos de qualquer outro comando TeX).

Considere o seguinte exemplo mínimo:

\documentclass{article}
\usepackage{ifthen}


\def\buildmacro#1{...}% the definition of \buildmacro

\begin{document}

\buildmacro{Title}

% 'Read' several titles

\Title{The first title}
\Title{The second title}
\Title{The third title}

\newcount\tempcount
\tempcount=1\relax

% 'List' all the Titles
\whiledo{\the\tempcount<\numexpr \thetitleXcounter+1\relax}
        {%
         \textsc{\csname title-\the\tempcount\endcsname}\par
         \advance\tempcount by 1\relax
        }

\end{document}

'Brinquei' com \csnamee \endcsname, \expandafter, e as versões \def, mas sem 'sorte'.\gdef\long

Editado(para responder a alguns dos comentários):

O objetivo disso é ter um mecanismo simples para criar um conjunto de comandos indexados com o mesmo nome de root (semelhante a uma lista de comandos). Sempre se pode usar a \csname <...> \endcsnameconstrução para emitir os comandos.

Responder1

Pela descrição do fluxo necessário, isso parece bastante simples

\newcommand\buildmacro[1]{%
  % Create a new counter named after the argument
  \newcounter{#1Xcounter}%
  % Create a new command named after the argument,
  % itself taking one argument
  \expandafter\newcommand\csname #1\endcsname[1]{%
    % Step the counter
    \stepcounter(#1Xcounter)%
    % Store the argument
    \expandafter\newcommand\csname #1-\arabic{#1Xcounter}\endcsname
      {##1}%
  }%
}

Como uma versão simples também foi solicitada

\long\def\buildmacro#1{%
  \csname newcount\expandafter\endcsname\csname #1Xcounter\endcsname
  \long\expandafter\def\csname #1\endcsname##1{%
    \global\expandafter\advance\csname #1Xcounter\endcsname by 1
    \expandafter\def\csname #1-\expandafter\number\csname #1Xcounter\endcsname
      \endcsname
      {##1}%
  }%
}

Responder2

Como mencionei em um comentário, nem um hífen nem um numeral podem ser usados ​​ao construir nomes de macro, a menos que você sempre escreva o equivalente \csname ... \endcsnameou garanta que os catcodes sejam alterados ao usá-los.

Portanto, é necessário modificar a interface do usuário daquela sugerida.

A ideia básica parece ser criar uma série de listas indexadas de argumentos que podem ser recuperadas fornecendo o nome da lista e o índice do item dentro dessa lista.

Isso poderia ser implementado usando listas separadas por vírgulas. Aqui está uma sugestão de interface que utiliza apenas expl3sintaxe considerada estável pelos desenvolvedores:

\buildmacro{<list identifier>}
\addmacro{<list identifier>}{<item to be added>}
\fetchmacro{<list identifier>}{<index of item to be fetched>}
\listmacro{<list identifier>}

O primeiro configura as coisas inicializando uma nova lista. O segundo adiciona um item a uma lista. O terceiro busca um item de uma lista. A quarta lista todos os itens de uma lista sequencialmente.

Prova de conceito (embora dificilmente original):

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\cs_new_protected_nopar:Nn \digitalink_buildmacro:n
{
  \clist_new:c { g_digitalink_#1_clist }
}
\NewDocumentCommand \buildmacro { m }
{
  \digitalink_buildmacro:n { #1 }
}
\NewDocumentCommand \addmacro { m +m }
{
  \clist_gput_right:cn { g_digitalink_#1_clist }
  {
    #2
  }
}
\NewDocumentCommand \fetchmacro { m m }
{
  \clist_item:cn { g_digitalink_#1_clist } { #2 }
}
\NewDocumentCommand \listmacro { m }
{
  \clist_use:cn { g_digitalink_#1_clist } { \par }
}
\ExplSyntaxOff
\begin{document}
\buildmacro{dititle}
\addmacro{dititle}{Here's some text.}
\addmacro{dititle}{Here's some more.}
\fetchmacro{dititle}{1}
\fetchmacro{dititle}{2}
\fetchmacro{dititle}{1}

List:

\listmacro{dititle}
\end{document}

prova de conceito

Responder3

A \@namedefe \@nameuseversão, falsificando nomes de 'macro' que não seriam possíveis sem a alteração do código de gato.

A alocação \newcounterdentro de macros pode causar problemas com registros de contadores.

\documentclass{article}

\makeatletter
\newcommand{\buildmacro}[1]{%
  \newcounter{#1Xcounter}%
    \expandafter\newcommand\csname #1\endcsname[1]{%
      \stepcounter{#1Xcounter}%
      \@namedef{#1-\number\value{#1Xcounter}}{##1}%
  }
}

\newcommand{\displaymacrocontent}[2]{%
  \@nameuse{#1-#2}%
}
\makeatother



\begin{document}

\buildmacro{Title}
\Title{The first title}
\Title{The second title}
\Title{The third title}

\newcount\tmpcntr

\loop\unless\ifnum\tmpcntr > 4
\advance\tmpcntr by 1
\displaymacrocontent{Title}{\number\tmpcntr}

\repeat



\end{document}

insira a descrição da imagem aqui

Responder4

O efeito que você está mostrando no seu pseudocódigo é obtido muito mais facilmente com uma macro de lista, que permite fazer um loop sem precisar saber quantos objetos estão nele e sem pisar nos contadores.

\documentclass{article}

\makeatletter
\newcommand{\Titlecontainer}{\@empty}% initialize
\newcommand{\Title}[1]{%
  \expandafter\def\expandafter\Titlecontainer\expandafter{%
    \Titlecontainer\LISTSEP{#1}%
  }%
}
\makeatother

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\begingroup % keep the change to \LISTSEP local
\def\LISTSEP#1{\textsc{#1}\par}
\Titlecontainer
\endgroup

\end{document}

insira a descrição da imagem aqui

Uma versão “abstrata”:

\documentclass{article}

\makeatletter
\newcommand{\Titlecontainer}{\@empty}% initialize
\newcommand{\Title}[1]{%
  \expandafter\def\expandafter\Titlecontainer\expandafter{%
    \Titlecontainer\LISTSEP{#1}%
  }%
}
\newcommand{\listmap}[2]{% #1 is the list name, #2 the code
  \begingroup\def\LISTSEP##1{#2}#1\endgroup
}
\makeatother

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\listmap{\Titlecontainer}{\textsc{#1}\par}

\end{document}

Ainda mais fácil com expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\Title}{m}
 {
  \seq_put_right:Nn \digitalink_titles_seq { #1 }
 }
\NewDocumentCommand{\ProcessTitles}{+m}
 {
  \seq_map_inline:Nn \digitalink_titles_seq { #1 }
 }
\seq_new:N \digitalink_titles_seq
\ExplSyntaxOff

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

\ProcessTitles{\textsc{#1}\par}

\newcounter{titlecount}
\ProcessTitles{\stepcounter{titlecount}\arabic{titlecount} -- #1\par}

\end{document}

insira a descrição da imagem aqui


Versões abstratas

Método clássico

\documentclass{article}

\makeatletter
\newcommand{\definelist}[1]{%
  \@namedef{#1}##1{%
    \expandafter\def\csname #1@container\expandafter\expandafter\expandafter\endcsname
    \expandafter\expandafter\expandafter{%
      \csname #1@container\endcsname\LISTSEP{##1}%
    }%
  }%
  \@namedef{#1@container}{\@empty}% initialize
}
\newcommand{\maplist}[2]{%
  \begingroup
  \def\LISTSEP##1{#2}%
  \@nameuse{#1@container}%
  \endgroup
}
\makeatother

\definelist{Title}

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\maplist{Title}{\textsc{#1}\par}

\newcounter{tempcount}
\maplist{Title}{\stepcounter{tempcount}\arabic{tempcount} -- #1\par}

\end{document}

Comexpl3

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\definelist}{m}
 {
  \seq_new:c { l_digitalink_list_#1_seq }
  \cs_new_protected:cpn { #1 } ##1
   {
    \seq_put_right:cn { l_digitalink_list_#1_seq } { ##1 }
   }
 }
\NewDocumentCommand{\maplist}{m +m}
 {
  \seq_map_inline:cn { l_digitalink_list_#1_seq } { #2 }
 }
\ExplSyntaxOff

\definelist{Title}

\begin{document}

\Title{The first title}
\Title{The second title}
\Title{The third title}

% 'List' all the Titles
\maplist{Title}{\textsc{#1}\par}

\newcounter{tempcount}
\maplist{Title}{\stepcounter{tempcount}\arabic{tempcount} -- #1\par}

\end{document}

informação relacionada