estructura modular de lista de macros para iterarla

estructura modular de lista de macros para iterarla

Basado en elLa respuesta de Wipet., y con el mismo espíritu de aprendizaje, sobre el bucle iterativo "for", es interesante descubrir cómo el "bucle for" propuesto podría ser más modular. Quiero pasar, como argumento, la lista iterable propuesta en el ejemplo anterior.

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

El comportamiento del código es correcto para mi 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, es una lista implícita, con varias variables y operaciones aritméticas en cada componente. Entonces, la idea principal es pasar la lista como una macro, algo así como \newcommand{\list}{0 0 0;0 0 0;0 0 \linkLength;0 0 \jointLength;0 {\jointLength*0.5} {\linkLength + \jointRadio}}llamarla como \for\i in \list. No entiendo qué modificaciones serán necesarias para que la declaración alcance este comportamiento. (Me doy cuenta de que este comportamiento se puede lograr usando la declaración \foreach pero necesito entender cómo se puede hacer)

Cualquier idea será bien recibida.

Respuesta1

(La macro \listya está definida y en uso para el listentorno en LaTeX 2e.
Por lo tanto, en el siguiente ejemplo, la macro \MyListestá definida y utilizada en su lugar).

Puede, por ejemplo, convertir fácilmente el asunto en una cuestión de expandir la macro que contiene la lista y luego intercambiar argumentos.

Con el siguiente ejemplo, \expandafterse utiliza para expandir la macro \MyList(cuya expansión produce la lista que se va a iterar) cronológicamente antes de \PassFirstToSecondmover esa lista (anidada entre llaves) dentro de la disposición formada por el flujo de tokens detrás de la \for\i inconstrucción.

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

ingrese la descripción de la imagen aquí


También puede utilizar una macro como \romannumeral\Expandtimespara especificar el nivel de expansión que se necesita con el argumento que contiene la lista; \romannumeral\Expandtimesse explica en¿Cómo puedo saber el número de \expandaftermensajes de correo electrónico al agregar a una 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}

ingrese la descripción de la imagen aquí

Respuesta2

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

ingrese la descripción de la imagen aquí

Respuesta3

Aquí hay un código que estoy desarrollando por placer. Guarde el siguiente 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

Ahora tu documento puede 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}

Con la ayuda de xfppodemos incluso evaluar expresiones.

La formatclave configura una plantilla para cada elemento en la lista separada por comas dada como primer argumento obligatorio, aquí #1 #2 #3significa que el elemento consistirá en cosas como

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

El segundo argumento obligatorio es el código que utiliza los argumentos configurados en la plantilla. Hay abreviaturas single(predeterminadas si no se especifica nada) doubley triplesignifican

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

respectivamente.

ingrese la descripción de la imagen aquí

información relacionada