Intentando comprender un fragmento de código que encontré

Intentando comprender un fragmento de código que encontré

En este hilo encontré un fragmento de código que me pareció realmente interesante y útil, pero no tengo idea de cómo funciona:https://tex.stackexchange.com/a/584979/261033

Aquí está el código en cuestión, como referencia:

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\matr#1{\def\matrL{}\matrA#1\end}
\def\matrA#1{\ifx\end#1\pmatrix{\matrL}\else 
   \ifx,#1\addto\matrL{&}\else
   \ifx;#1\addto\matrL{\cr}\else
   \addto\matrL{#1}\fi\fi
   \expandafter\matrA\fi
}

Se puede llamar como \matr{a,b;c,d}y genera una pmatriz. En mi opinión, es muy útil si trabajas a menudo con matrices simples y estás cansado de escribir repetidamente el comando largo completo. Alguien también señaló que para que funcione con el paquete amsmath, es necesario reemplazarlo \pmatrix{\matrL}por \begin{pmatrix}\matrL\end{pmatrix}.

De todos modos, deseo hacer más modificaciones a este comando, por ejemplo, usar diferentes símbolos como separadores de fila/columna, realizar el análisis de entrada por columnas o generalizarlo para todos los tipos de corchetes de matriz (por lo que podría escribir algo como \matr{[)}{...}y generará una matriz con ese conjunto específico de corchetes, similar a \left[\begin{matrix}...\end{matrix}\right)), pero no sé cómo hacer nada de eso todavía.

Intenté aprender algo sobre estos comandos, pero rápidamente encontré problemas. Parece que algunos de ellos, como \addto, son tan oscuros que no existe documentación sobre ellos en ninguna parte. Google sólo pudo encontrar cosas como \addtocontentso \g@addto@macro, que no me interesan, y tampoco pude encontrar ningún recurso TeX completo que las enumerara, ni siquierahttps://www.latex-project.orgohttps://texdoc.org/index.html.

Entonces, por favor, si alguien pudiera ayudarme con esto, tal vez indicarme alguna documentación existente para estos comandos, se lo agradecería mucho. Gracias de antemano.

Respuesta1

La \addtomacro agrega código a otra macro.

Si lo tienes \def\foo{X}y lo haces \addto\foo{Y}, TeX servirá.

\expandafter\def\expandafter\foo\expandafter{\foo Y}

lo que resulta en

\def\foo{XY}

después de que la \expandaftercadena haya hecho su trabajo. Sin embargo, tuno poderÚselo \addtosi planea usar el código en LaTeX, porque \addtoes un comando importante utilizado babely corre el riesgo de sufrir un desastre si lo redefine. Sólo usa otro nombre.

¿Que es lo que \matrhace? Lo hace \def\matrL{}, lo que inicializa un contenedor para el cuerpo de la matriz. Luego pasa el argumento a \matrA, iniciando una recursividad.

La macro \matrAsimplemente lee los siguientes tokens uno por uno:

  • si el siguiente token es ,(que indica el final de una celda), entonces &se agrega a \matrL;
  • si el siguiente token es ;(que indica el final de una fila), entonces \crse agrega a \matrL;
  • si el siguiente token es \end, se ejecuta el final del juego, es decir, \pmatrix{\matrL}se ejecuta y se detiene la recursividad;
  • en todos los demás casos, el token simplemente se agrega a \matrL.

¿Puedes adaptar esto a LaTeX y específicamente a un pmatrixentorno? Sí, fácilmente.

En primer lugar, elija diferentes nombres para las macros internas, preferiblemente dentro @de ellas.

\documentclass{article}
\usepackage{amsmath}

\makeatletter
\newcommand{\matr}[1]{\def\tsskyx@matrL{}\tsskyx@matrA#1\end}

\def\tsskyx@addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}

\def\tsskyx@matrA#1{%
  \ifx\end#1%
    \begin{pmatrix}\tsskyx@matrL\end{pmatrix}%
  \else 
    \ifx,#1%
      \tsskyx@addto\tsskyx@matrL{&}%
    \else
      \ifx;#1%
        \tsskyx@addto\tsskyx@matrL{\\}%
      \else
        \tsskyx@addto\tsskyx@matrL{#1}%
      \fi
    \fi
    \expandafter\tsskyx@matrA
  \fi
}
\makeatother

\begin{document}

\[
\matr{a,b;c,d}
\]

\end{document}

Se utiliza el mismo código, con diferencias mínimas: en lugar de \cragregamos \\y .\begin{pmatrix}...\end{pmatrix}

Una implementación diferente usando expl3, donde un argumento opcional especifica los delimitadores (el valor predeterminado ppuede ser bvVBcon amsmathconvenciones).

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\matr}{O{p}m}
 {
  \tsskyx_matr:nn { #1 } { #2 }
 }

\seq_new:N \l__tsskyx_matr_body_seq

\cs_new_protected:Nn \tsskyx_matr:nn
 {
  % build the matrix
  \begin{#1matrix}
  % split the argument at ;
  \seq_set_split:Nnn \l__tsskyx_matr_body_seq { ; } { #2 }
  % map the items, that are comma separated lists
  \seq_map_function:NN \l__tsskyx_matr_body_seq \__tsskyx_matr_row:N
  \end{#1matrix}
 }

\cs_new_protected:Nn \__tsskyx_matr_row:N
 {
  \clist_use:nn { #1 } { & } \\
 }

\ExplSyntaxOff

\begin{document}

\[
\matr{a,b;c,d}
\qquad
\matr[b]{a,b;c,d}
\]

\end{document}

ingrese la descripción de la imagen aquí

Si también desea cambiar el separador de filas y columnas, puede utilizar un sistema clave-valor.

\documentclass{article}
\usepackage{amsmath}

\ExplSyntaxOn

\NewDocumentCommand{\matr}{O{}m}
 {
  \group_begin:
  \keys_set:nn { tsskyx/matr } { #1 }
  \tsskyx_matr:n { #2 }
  \group_end:
 }

\seq_new:N \l__tsskyx_matr_body_seq
\seq_new:N \l__tsskyx_matr_row_seq

\keys_define:nn { tsskyx/matr }
 {
  row-sep .tl_set:N  = \l__tsskyx_matr_rowsep_tl,
  col-sep .tl_set:N  = \l__tsskyx_matr_colsep_tl,
  delim   .tl_set:N  = \l__tsskyx_matr_delim_tl,
  row-sep .initial:n = { ; },
  col-sep .initial:n = { , },
  delim   .initial:n = { p },
 }

\cs_new_protected:Nn \tsskyx_matr:n
 {
  % build the matrix
  \begin{\l__tsskyx_matr_delim_tl matrix}
  % split the argument at ;
  \seq_set_split:NVn \l__tsskyx_matr_body_seq \l__tsskyx_matr_rowsep_tl { #1 }
  % map the items, that are comma separated lists
  \seq_map_function:NN \l__tsskyx_matr_body_seq \__tsskyx_matr_row:N
  \end{\l__tsskyx_matr_delim_tl matrix}
 }

\cs_new_protected:Nn \__tsskyx_matr_row:N
 {
  \seq_set_split:NVn \l__tsskyx_matr_row_seq \l__tsskyx_matr_colsep_tl { #1 }
  \seq_use:Nn \l__tsskyx_matr_row_seq { & } \\
 }

\ExplSyntaxOff

\begin{document}

\begin{gather*}
\matr{a,b;c,d}
\\
\matr[delim=b]{a,b;c,d}
\\
\matr[row-sep=\\,col-sep=&,delim=V]{a & b \\ c & d}
\\
\matr[row-sep=;,col-sep=:]{a:b;c:d}
\end{gather*}

\end{document}

ingrese la descripción de la imagen aquí

Respuesta2

La \addtomacro mencionada en el código es de macros OPmac diseñadas originalmente para csplain, luego OPmac para TeX simple, hoy en día en OpTeX. El autor de estos paquetes de macros no es compatible con LaTeX. Sus macros son principalmente para TeX simple y, debido a que se basan principalmente en primitivas de TeX, también son aplicables en LaTeX. Pero a veces hay pequeños obstáculos, como el nombre \addtocompartido con el mismo nombre en un paquete LaTeX. Debido a que el autor no usa LaTeX ni sus paquetes (como babel), no es ningún problema para él ni para otros usuarios simples de TeX.

Si desea modificar la macro para permitir establecer el tipo de paréntesis de la matriz en el parámetro, puede enviar el tipo dado a la definición de\matrA definidoadentrola \matrmacro. Entonces, tienes \defun \deftruco:

\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\matr#1#2#3{\def\matrL{}%
   \def\matrA##1{\ifx\end##1\left#1\matrix{\matrL}\right#2\else 
      \ifx,##1\addto\matrL{&}\else
      \ifx;##1\addto\matrL{\cr}\else
      \addto\matrL{##1}\fi\fi
      \expandafter\matrA\fi
   }
   \matrA#3\end
}

Test and usage:
$$
  \matr[]{a,b;c,d}
$$

\bye

EditarPara comparar con otra respuesta aquí, muestro cómo usar macros clave-valor de OpTeX:

\def\matrdefaults{%
   delims=(),   % delimiters of the matrix
   row-sep={;}, % row separator used in parameter
   col-sep={,}, % column separator used in parameter
}
\optdef\matr [] #1{{%
   \readkv\matrdefaults \readkv{\the\opt}%
   \ea\matrX \expanded{\kv{delims}\kv{row-sep}\kv{col-sep}}#1\end
}}
\def\matrX#1#2#3#4{\def\matrL{}%
   \def\matrA##1{\ifx\end##1\left#1\matrix{\matrL}\right#2\else 
      \ifx#4##1\addto\matrL{&}\else
      \ifx#3##1\addto\matrL{\cr}\else
      \addto\matrL{##1}\fi\fi
      \ea\matrA\fi
   }
   \matrA
}

$$
  \displaylines{
     \matr {a,b;c,d} \cr
     \matr [delims={[]}] {a,b;c,d} \cr
     \matr [row-sep={\cr}, col-sep={&}, delims={\|\|}] {a&b\cr c&d} \cr
     \matr [row-sep=;,col-sep=:]{a:b;c:d}
}
$$

\bye

Y si desea crear su paquete con esta macro, debe usar un espacio de nombre separado ( tsskyxaquí). Las secuencias de control en este espacio de nombres tienen el prefijo .y otras secuencias de control utilizadas (primitivas y macros OpTeX) tienen el prefijo _. Luego, su macro se aísla del espacio de nombres de usuario (nombres sin prefijo) y de otros paquetes de macros con espacios de nombres diferentes.

\_namespace{tsskyx}
\_def\.matrdefaults{%
   delims=(),   % delimiters of the matrix
   row-sep={;}, % row separator used in parameter
   col-sep={,}, % column separator used in parameter
}
\_optdef\.matr [] #1{{%
   \_kvdict{tsskyx}%
   \_readkv\.matrdefaults \_readkv{\_the\_opt}%
   \_ea\.matrX \_expanded{\_kv{delims}\_kv{row-sep}\_kv{col-sep}}#1\_end
}}
\_def\.matrX#1#2#3#4{\_def\.matrL{}%
   \_def\.matrA##1{\_ifx\_end##1\_left#1\_matrix{\.matrL}\_right#2\_else 
      \_ifx#4##1\_addto\.matrL{&}\_else
      \_ifx#3##1\_addto\.matrL{\_cr}\_else
      \_addto\.matrL{##1}\_fi\_fi
      \_ea\.matrA\_fi
   }
   \.matrA
}
\_nspublic \matr ;
\_endnamespace

$$
  \displaylines{
     \matr {a,b;c,d} \cr
     \matr [delims={[]}] {a,b;c,d} \cr
     \matr [row-sep={\cr}, col-sep={&}, delims={\|\|}] {a&b\cr c&d} \cr
     \matr [row-sep=;,col-sep=:]{a:b;c:d}
}
$$

\bye

información relacionada