Пытаюсь понять фрагмент кода, который я нашел

Пытаюсь понять фрагмент кода, который я нашел

В этой теме я нашел фрагмент кода, который показался мне действительно интересным и полезным, но я понятия не имею, как он работает:https://tex.stackexchange.com/a/584979/261033

Вот код, о котором идет речь, для справки:

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

Его можно вызвать как \matr{a,b;c,d}и он сгенерирует pmatrix. Очень полезно, на мой взгляд, если вы часто работаете с простыми матрицами и устали от многократного ввода полной длинной команды. Кто-то также указал, что для того, чтобы это работало с пакетом amsmath, нужно заменить \pmatrix{\matrL}на \begin{pmatrix}\matrL\end{pmatrix}.

В любом случае, я хочу внести дополнительные изменения в эту команду, например, использовать различные символы в качестве разделителей строк/столбцов, сделать разбор входных данных по столбцам или обобщить ее для всех типов скобок матриц (чтобы вы могли ввести что-то вроде , \matr{[)}{...}и она сгенерирует матрицу с этим определенным набором закрывающих скобок, например \left[\begin{matrix}...\end{matrix}\right)), но я пока не знаю, как это сделать.

Я пытался узнать что-нибудь об этих командах, но быстро столкнулся с проблемами. Кажется, некоторые из них, такие как \addto, настолько неясны, что для них нигде нет документации! Google смог найти только такие вещи, как \addtocontentsили \g@addto@macro, которые мне не интересны, и я также не смог найти ни одного исчерпывающего ресурса TeX, который бы их перечислил, дажеhttps://www.latex-project.orgилиhttps://texdoc.org/index.html.

Так что, пожалуйста, если кто-нибудь может мне помочь с этим, возможно, укажет мне на какую-то существующую документацию по этим командам, я был бы очень признателен. Заранее спасибо.

решение1

Макрос \addtoдобавляет код к другому макросу.

Если у вас есть \def\foo{X}и вы делаете \addto\foo{Y}, TeX сделает это

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

что приводит к

\def\foo{XY}

после того, как \expandafterцепь выполнила свою работу. Однако, выне мочьиспользуйте \addto, если вы планируете использовать код в LaTeX, потому что \addtoэто важная команда, используемая babelи вы рискуете попасть в беду, если переопределите ее. Просто используйте другое имя.

Что делает \matr? Он делает \def\matrL{}, который инициализирует контейнер для тела матрицы. Затем он передает аргумент в \matrA, начиная рекурсию.

Макрос \matrAпросто прочитал следующие токены один за другим:

  • если следующий токен ,(обозначающий конец ячейки), то &добавляется к \matrL;
  • если следующий токен ;(обозначающий конец строки), то \crдобавляется к \matrL;
  • если следующий токен — \end, то запускается финальная игра, а именно \pmatrix{\matrL}выполняется , и рекурсия останавливается;
  • во всех остальных случаях токен просто добавляется к \matrL.

Можно ли адаптировать это к LaTeX и конкретно к pmatrixсреде? Да, легко.

Прежде всего, выберите разные имена для внутренних макросов, желательно с использованием @в них.

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

Тот же код, с минимальными отличиями: вместо \crмы добавляем \\и \begin{pmatrix}...\end{pmatrix}используется.

Другая реализация с использованием expl3, где необязательный аргумент указывает разделители (по умолчанию p, может быть bvVBс amsmathсоглашениями).

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

введите описание изображения здесь

Если вы также хотите изменить разделитель строк и столбцов, вы можете использовать систему «ключ-значение».

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

введите описание изображения здесь

решение2

Макрос \addto, упомянутый в коде, взят из макросов OPmac, изначально разработанных для csplain, позже OPmac для простого TeX, в настоящее время в OpTeX. Автор этих макропакетов не поддерживает LaTeX. Его макросы в первую очередь предназначены для простого TeX, и поскольку они в основном основаны на примитивах TeX, они применимы и в LaTeX. Но иногда возникают небольшие препятствия, такие как имя, \addtoсовпадающее с тем же именем в пакете LaTeX. Поскольку автор не использует LaTeX или его пакеты (например, babel), то это не проблема для него и для других пользователей простого TeX.

Если вы хотите изменить макрос, чтобы включить установку типа скобок матрицы в параметре, то вы можете отправить заданный тип в определение \matrAdefinedвнутримакрос \matr. Итак, у вас есть \defтрюк \def:

\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

РедактироватьДля сравнения с другим ответом здесь я покажу, как использовать макросы «ключ-значение» из 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

И если вы хотите создать свой пакет с этим макросом, то вам следует использовать отдельное пространство имен ( tsskyxздесь). Управляющие последовательности в этом пространстве имен имеют префикс ., а другие используемые управляющие последовательности (примитивы и макросы OpTeX) имеют префикс _. Тогда ваш макрос будет изолирован от пространства имен пользователя (имена без префиксов) и от других пакетов макросов с другим пространством имен.

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

Связанный контент