estrutura modular de lista de macros para iterá-la

estrutura modular de lista de macros para iterá-la

Com base noA resposta de Wipet, e com o mesmo espírito de aprendizagem, sobre o loop iterativo "for", é interessante descobrir como o "loop for" proposto poderia ser mais modular. Quero passar, como argumento, a lista iterável proposta no exemplo acima.

\documentclass[a4paper]{article}
\usepackage{pst-solides3d}

%%% FOR LOOP %%%
\makeatletter
\long\def\for#1in#2#3{\expandafter\def\csname b:\string#1\endcsname{#3}%
   \@forinA#1#2;}
\long\def\@forinA#1#2;{\ifx#2\else
   \def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother

%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}

\newcommand{\iterating}{
%%% point's structure  %%%
\for\i in {%
0 0 0;% N°0
0 0 0;% N°1 
0 0 \linkLength;% N°2 
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
{%  
  \i\par
   %... call to several macros
}%
}
\begin{document}

\iterating

\end{document}

O comportamento do código está correto para o meu propósito.

0 0 0
0 0 0
0 0 1.2
0 0 0.6
0 0.6*0.5 1.2+ 0.2

Esta lista, é uma lista implícita, com diversas variáveis ​​e operações aritméticas em cada componente. Então a ideia principal é passar a lista como uma macro, algo como \newcommand{\list}{0 0 0;0 0 0;0 0 \linkLength;0 0 \jointLength;0 {\jointLength*0.5} {\linkLength + \jointRadio}}e chamá-la de \for\i in \list. Não entendo quais modificações serão necessárias para que a declaração atinja esse comportamento. (sei que esse comportamento pode ser alcançado usando a instrução \foreach, mas preciso entender como isso pode ser feito)

Qualquer ideia será bem recebida.

Responder1

(A macro \listjá está definida e em uso para o list-environment no LaTeX 2e.
Portanto, no exemplo abaixo, a macro \MyListé definida e usada em seu lugar.)

Você pode, por exemplo, facilmente transformar o assunto em uma questão de expandir a macro que contém a lista e depois trocar argumentos.

Com o exemplo abaixo, \expandafteré usado para expandir a macro \MyList(cuja expansão produz a lista que deve ser iterada) cronologicamente antes de \PassFirstToSecondmover essa lista (aninhada entre colchetes) dentro do arranjo que é formado pelo token-stream atrás da \for\i in-construct.

\documentclass[a4paper]{article}
\usepackage{pst-solides3d}

%%% FOR LOOP %%%
\makeatletter
\long\def\for#1in#2#3{\expandafter\def\csname b:\string#1\endcsname{#3}%
   \@forinA#1#2;}
\long\def\@forinA#1#2;{\ifx#2\else
   \def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother

%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}

\newcommand{\iterating}{%%%%%%%%%%%%%
%%% point's structure  %%%
\for\i in {%
0 0 0;% N°0
0 0 0;% N°1 
0 0 \linkLength;% N°2 
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
{%  
  \i\par
   %... call to several macros
}%
}


\newcommand\PassFirstToSecond[2]{#2{#1}}

\newcommand\MyList{%
  0 0 0;% N°0
  0 0 0;% N°1 
  0 0 \linkLength;% N°2 
  0 0 \jointLength;% N°3
  0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}%



\begin{document}

\noindent\verb|\iterating| yields:

\iterating

\bigskip

\noindent\verb|\expandafter\PassFirstToSecond\expandafter{\MyList}{\for\i in }{\i\par}| yields:

\expandafter\PassFirstToSecond\expandafter{\MyList}{\for\i in }{\i\par}%

\bigskip

\noindent You can also do another kind of \verb|\expandafter|-orgy:

\bigskip

\noindent\verb|\expandafter\for\expandafter\i\expandafter i\expandafter n\expandafter{\MyList}{\i\par}| yields:

\expandafter\for\expandafter\i\expandafter i\expandafter n\expandafter{\MyList}{\i\par}%

\end{document}

insira a descrição da imagem aqui


Você também pode usar uma macro \romannumeral\Expandtimespara especificar o nível de expansão necessário com o argumento que contém a lista - \romannumeral\Expandtimesé explicado emComo posso saber o número de \expandafters ao anexar a uma macro csname?:

\documentclass[a4paper]{article}
\usepackage{pst-solides3d}

%%% FOR LOOP %%%
\makeatletter
%
\newcommand\exchange[2]{#2#1}%
% A check is needed for finding out if an argument is catcode-11-"d" while there are only 
% the possibilities that the argument is either a single catcode-11-"d"
% or a single catcode-12-"m":
\def\innerdfork#1d#2#3dd{#2}%
\def\dfork#1{\innerdfork#1{\@firstoftwo}d{\@secondoftwo}dd}%
% By means of \romannumeral create as many catcode-12-characters m as expansion-steps are to take place.
% Then by means of recursion for each of these m double the amount of `\expandafter`-tokens and
% add one `\expandafter`-token within \innerExp's first argument.
\def\Expandtimes#1{0\expandafter\innerExp\expandafter{\expandafter}\romannumeral\number\number#1 000d}
\def\innerExp#1#2{\dfork{#2}{#1 }{\innerExp{#1#1\expandafter}}}


\long\def\for#1in #2-level-expansion of #3#4{%
  \expandafter\def\csname b:\string#1\endcsname{#4}%
  \expandafter\exchange\expandafter{\romannumeral\Expandtimes{#2}#3;}{\@forinA#1}%
}
\long\def\@forinA#1#2;{\ifx#2\else
   \def#1{#2}\csname b:\string#1\endcsname \expandafter\@forinA\expandafter#1\fi}
%%%%%%%%%%%%%%%%%%
\makeatother

%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}

\newcommand\MyList{%
  0 0 0;%
  0 0 0;%
  0 0 \linkLength;%
  0 0 \jointLength;%
  0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}%

\newcommand\MyOuterListContainer{\MyInnerListContainer}
\newcommand\MyInnerListContainer{\MyList}


\begin{document}

\begingroup
\topsep=0ex \partopsep=0ex
\begin{verbatim}
\for\i in 0-level-expansion of {%
  0 0 0;%
  0 0 0;%
  0 0 \linkLength;%
  0 0 \jointLength;%
  0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}{\i\par}%
\end{verbatim}%
\smallskip
\endgroup

\noindent yields:

\for\i in 0-level-expansion of {%
  0 0 0;%
  0 0 0;%
  0 0 \linkLength;%
  0 0 \jointLength;%
  0 {\jointLength*0.5} {\linkLength + \jointRadio};%
}{\i\par}%

\bigskip

\noindent\verb|\for\i in 1-level-expansion of {\MyList}{\i\par}| yields:

\for\i in 1-level-expansion of {\MyList}{\i\par}

\bigskip

\noindent\verb|\for\i in 3-level-expansion of {\MyOuterListContainer}{\i\par}| yields:

\for\i in 3-level-expansion of {\MyOuterListContainer}{\i\par}

\end{document}

insira a descrição da imagem aqui

Responder2

\documentclass[a4paper]{article}
\usepackage[T1]{fontenc}
\usepackage{pst-solides3d}
%% Variables%%
\pgfmathparse{1.2}\edef\linkLength{\pgfmathresult}
\pgfmathparse{0.2}\edef\jointRadio{\pgfmathresult}
\pgfmathparse{0.6}\edef\jointLength{\pgfmathresult}
\newcommand\itlist{
0 0 0;% N°0
0 0 0;% N°1 
0 0 \linkLength;% N°2 
0 0 \jointLength;% N°3
0 {\jointLength*0.5} {\linkLength + \jointRadio};% N°4
}
\usepackage{listofitems}
\begin{document}
\setsepchar{;/ }
\ignoreemptyitems
\readlist*\mylist{\itlist}
Iterate by row:
\foreachitem\x\in\mylist[]{\par%
  \fbox{\x}
}

Third item on 5th row (the actual tokens):\\
\detokenize\expandafter\expandafter\expandafter{\mylist[5,3]}\\
which expands to \mylist[5,3]

1st, 3rd items on 3rd row, in a box is \fbox{\mylist[3,2],\mylist[3,3]}

Now to iterate on each item:
\foreachitem\x\in\mylist{\par%
  \foreachitem\y\in\mylist[\xcnt]{%
    \fbox{\y}
}}
\end{document}

insira a descrição da imagem aqui

Responder3

Aqui está um código que estou desenvolvendo para lazer. Salve o seguinte código comoextforeach-code.tex

% extforeach-code.tex

\ExplSyntaxOn
\providecommand\fpeval{\fp_eval:n}

\NewDocumentCommand{\nforeach}{ m +m }
 {
  \tl_clear:N \l__manual_nforeach_type_tl
  \keys_set:nn { manual/nforeach }
   {
    type=integers,start = 1, step = 1, end = 0,
   }
  \keys_set:nn { manual/nforeach } { #1 }
  \__manual_nforeach_exec:n { #2 }
 }

\int_new:N \g__manual_foreach_map_int
\int_new:N \g__manual_fp_map_int
\tl_new:N \l__manual_nforeach_type_tl

\keys_define:nn { manual/nforeach }
 {
  type .choice:,
  type .value_required:n = true,
  type/integers .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { integers },
  type/fp       .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { fp },
  type/alph     .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { alph },
  type/Alph     .code:n = \tl_set:Nn \l__manual_nforeach_type_tl { Alph },
  start .tl_set:N = \l__manual_nforeach_start_tl,
  step  .tl_set:N = \l__manual_nforeach_step_tl,
  end   .tl_set:N = \l__manual_nforeach_end_tl,
 }

\cs_new_protected:Nn \__manual_nforeach_exec:n
 {
  \int_gincr:N \g__manual_foreach_map_int
  \str_case:Vn \l__manual_nforeach_type_tl
   {
    {integers}{\__manual_nforeach_exec_integers:n { #1 }}
    {fp}      {\__manual_nforeach_exec_fp:n { #1 }}
    {alph}    {\__manual_nforeach_exec_alph:Nn \int_to_alph:n { #1 }}
    {Alph}    {\__manual_nforeach_exec_alph:Nn \int_to_Alph:n { #1 }}
   }
  \int_gdecr:N \g__manual_foreach_map_int
 }
\cs_generate_variant:Nn \str_case:nn { V }

\cs_new_protected:Nn \__manual_nforeach_exec_integers:n
 {
  \int_step_inline:nnnn
   { \l__manual_nforeach_start_tl }
   { \l__manual_nforeach_step_tl }
   { \l__manual_nforeach_end_tl }
   { #1 }
 }
\cs_new_protected:Nn \__manual_nforeach_exec_alph:Nn
 {
  \cs_set:cn { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n } { #2 }
  \cs_generate_variant:cn
   { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :n }
   { f }
  \int_step_inline:nnnn
   { \int_from_alph:f { \l__manual_nforeach_start_tl } }
   { \l__manual_nforeach_step_tl }
   { \int_from_alph:f { \l__manual_nforeach_end_tl } }
   {
    \use:c { __manual_nforeach_alph_ \int_use:N \g__manual_foreach_map_int :f }
     { #1 { ##1 } }
   }
 }
\cs_generate_variant:Nn \cs_generate_variant:Nn { c }
\cs_generate_variant:Nn \int_from_alph:n { f }

\cs_new_protected:Nn \__manual_nforeach_exec_fp:n
 {
  \fp_step_inline:nnnn
   { \l__manual_nforeach_start_tl }
   { \l__manual_nforeach_step_tl }
   { \l__manual_nforeach_end_tl }
   { #1 }
 }

\NewDocumentCommand{\lforeach}{ s O{} m +m }
 {
  \IfBooleanTF{#1}
   {
    \manual_lforeach:non { #2 } { #3 } { #4 }
   }
   {
    \manual_lforeach:nnn { #2 } { #3 } { #4 }
   }
 }

\cs_new_protected:Nn \manual_lforeach:nnn
 {
  \keys_set:nn { manual/lforeach } { single }
  \keys_set:nn { manual/lforeach } { #1 }
  \clist_set:Nn \l__manual_lforeach_list_clist { #2 }
  \int_gincr:N \g__manual_foreach_map_int
  \__manual_lforeach_define:n { #3 }
  \clist_map_inline:Nn \l__manual_lforeach_list_clist
   {
    \use:c { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w } ##1 \q_stop
   }
  \int_gdecr:N \g__manual_foreach_map_int
 }
\cs_generate_variant:Nn \manual_lforeach:nnn { no }

\cs_new_protected:Nn \__manual_lforeach_define:n
 {
  \exp_last_unbraced:NcV
   \cs_set:Npn
   { __manual_lforeach_ \int_use:N \g__manual_foreach_map_int _action:w }
   \l__manual_lforeach_format_tl
   \q_stop
   {#1}
 }

\keys_define:nn { manual/lforeach }
 {
  format .tl_set:N = \l__manual_lforeach_format_tl,
  single .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1 },
  double .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2 },
  triple .code:n = \tl_set:Nn \l__manual_lforeach_format_tl { ##1/##2/##3 },
 }
\ExplSyntaxOff

Agora seu documento pode ser

\documentclass{article}
\usepackage{xparse,xfp}

\input{extforeach-code.tex}

\newcommand\linkLength{1.2}
\newcommand\jointRadio{0.2}
\newcommand\jointLength{0.6}

\newcounter{lines}

\begin{document}

\lforeach[format=#1 #2 #3]{
  0 0 0, % N°0
  0 0 0, % N°1
  0 0 \linkLength, % N°2
  0 0 \jointLength, % N°3
  0 {\jointLength*0.5} {\linkLength + \jointRadio}, % N°4
}
{%
 \stepcounter{lines}Line \thelines\ is \fpeval{#1}~\fpeval{#2}~\fpeval{#3}\par 
}

\end{document}

Com a ajuda de xfppodemos até avaliar expressões.

A formatchave configura um modelo para cada item na lista separada por vírgulas dada como primeiro argumento obrigatório, aqui #1 #2 #3significa que o item consistirá em coisas como

<subitem><space><subitem><space><subitem>

O segundo argumento obrigatório é o código que utiliza os argumentos configurados no modelo. Existem abreviações single(padrão se nada for especificado) doublee tripleque significam

format=#1
format=#1/#2
format=#1/#2/#3

respectivamente.

insira a descrição da imagem aqui

informação relacionada