Tentando entender um trecho de código que encontrei

Tentando entender um trecho de código que encontrei

Neste tópico, encontrei um trecho de código que achei muito interessante e útil, mas não tenho ideia de como funciona:https://tex.stackexchange.com/a/584979/261033

Aqui está o código em questão, para referência:

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

Pode ser chamado como \matr{a,b;c,d}e gera uma pmatrix. Muito útil na minha opinião se você trabalha frequentemente com matrizes simples e está cansado de digitar repetidamente o comando longo e completo. Alguém também apontou que para fazê-lo funcionar com o pacote amsmath, você precisa substituir o \pmatrix{\matrL}arquivo \begin{pmatrix}\matrL\end{pmatrix}.

De qualquer forma, desejo fazer mais modificações neste comando, por exemplo, usar símbolos diferentes como separadores de linha/coluna, fazer a análise de entrada em colunas ou generalizá-la para todos os tipos de colchetes de matriz (para que você possa digitar algo como \matr{[)}{...}e isso irá gerar uma matriz com aquele conjunto específico de colchetes, semelhante a \left[\begin{matrix}...\end{matrix}\right)), mas ainda não sei como fazer nada disso.

Tentei aprender algo sobre esses comandos, mas rapidamente tive problemas. Parece que alguns deles, como \addto, são tão obscuros que não existe documentação para eles em lugar nenhum! O Google só conseguiu encontrar coisas como \addtocontentsou \g@addto@macro, nas quais não estou interessado, e também não consegui encontrar nenhum recurso TeX abrangente que as listasse, nem mesmohttps://www.latex-project.orgouhttps://texdoc.org/index.html.

Então, por favor, se alguém pudesse me ajudar com isso, talvez me indique alguma documentação existente para esses comandos, eu agradeceria muito. Agradeço antecipadamente.

Responder1

A \addtomacro anexa código a outra macro.

Se você tiver \def\foo{X}e fizer \addto\foo{Y}, o TeX fará

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

o que resulta em

\def\foo{XY}

depois que a \expandaftercorrente tiver feito seu trabalho. No entanto, vocênão podeuse \addtose você planeja usar o código em LaTeX, porque \addtoé um comando importante usado por babele você corre o risco de um desastre se redefini-lo. Basta usar outro nome.

O que faz \matr? Sim \def\matrL{}, o que inicializa um contêiner para o corpo da matriz. Em seguida, ele passa o argumento para \matrA, iniciando uma recursão.

A macro \matrAacabou de ler os seguintes tokens, um por um:

  • se o próximo token for ,(indicando o final de uma célula), então &será anexado a \matrL;
  • se o próximo token for ;(indicando o fim de uma linha), então \crserá anexado a \matrL;
  • se o próximo token for \end, o final do jogo é executado, ou seja, \pmatrix{\matrL}é executado e a recursão para;
  • em todos os outros casos, o token é apenas anexado a \matrL.

Você pode adaptar isso ao LaTeX e especificamente a um pmatrixambiente? Sim, facilmente.

Em primeiro lugar, escolha nomes diferentes para as macros internas, de preferência com @elas.

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

O mesmo código, com diferenças mínimas: em vez de \cracrescentamos \\e \begin{pmatrix}...\end{pmatrix}é usado.

Uma implementação diferente usando expl3, onde um argumento opcional especifica os delimitadores (padrão p, pode ser bvVBcom amsmathconvenções).

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

insira a descrição da imagem aqui

Se você também quiser alterar o separador de linhas e colunas, poderá usar um sistema de valores-chave.

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

insira a descrição da imagem aqui

Responder2

A \addtomacro mencionada no código é de macros OPmac projetadas originalmente para csplain, posteriormente OPmac para TeX simples, hoje em dia em OpTeX. O autor destes pacotes de macros não suporta LaTeX. Suas macros são principalmente para TeX simples e, como são baseadas principalmente em primitivas TeX, também são aplicáveis ​​em LaTeX. Mas às vezes existem alguns obstáculos, como o nome \addtocompartilhado com o mesmo nome em um pacote LaTeX. Como o autor não usa LaTeX ou seus pacotes (como o babel), isso não é problema para ele e para outros usuários simples do TeX.

Se você deseja modificar a macro para permitir definir o tipo de parêntese da matriz no parâmetro, então você pode enviar o tipo fornecido para a definição de \matrAdefinidodentroa \matrmacro. Então, você tem \defum \deftruque:

\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 comparação com outra resposta aqui, mostro como usar macros de valor-chave do 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

E se você quiser criar seu pacote com esta macro, então você deve usar um namespace separado ( tsskyxaqui). As sequências de controle neste namespace são prefixadas por .e outras sequências de controle usadas (primitivas e macros OpTeX) são prefixadas por _. Em seguida, sua macro é isolada do espaço de nomes de usuário (nomes sem prefixo) e de outros pacotes de macros com espaços de nomes 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

informação relacionada