LaTeX3 Интерфейс для функций

Sep 03 2020

Недавно я разместил вопрос о написании макроса на простом TeX, который изменял бы элементы в указанном пользователем списке. Я небрежно упомянул о своей неприязни к интерфейсу TeX, поэтому кто-то переключил меня на LaTeX3, который, как и обещает руководство, должен быть больше похож на современный язык программирования. Я только начинаю программировать на TeX, так что мне пришлось нелегко понять руководство. Я предполагаю, что это потому, что руководство было написано для опытных пользователей TeX; однако, похоже, нет альтернативы для людей, только начинающих работать с LaTeX3 / TeX, поэтому у меня нет выбора, кроме как работать с тем, что у меня есть. Вот почему я публикую это. Руководство сбивает с толку, и я хотел бы прояснить эту путаницу, задав вам несколько простых вопросов о синтаксисе.

Я должен упомянуть, что человек, который рассказал мне о LaTeX3, также дал мне решение моей исходной публикации, используя свой интерфейс. Я смог использовать это решение вместе с руководством, чтобы начать выяснять некоторые основные факты о синтаксисе LaTeX3. Я собираюсь рассказать о том, что мне удалось выяснить, но честно предупреждаю, что некоторые из них основаны на моих собственных выводах, сделанных с помощью примера, предоставленного пользователем stackexchange, а не явных инструкций в руководстве, так что ждите ошибок. Я хочу, чтобы вы знали, я не запутываю дела, когда иногда использую свою терминологию. Просто сложно структурированно говорить о предмете, который вы не полностью понимаете.

Также я пишу это как отдельный пост, а не как комментарий, из-за его длины. Заранее спасибо.

-------------------------------------------------- -------------------------------------------------- -------------------

Определения функций .

Что мне удалось выяснить :

Новая функция определяется, среди прочего, с помощью следующего кода:

\cs_new_<restrictions>:Npn <function name> <function parameters> {<replacement code>}

Это \cs_new_<restrictions>команда LaTeX, Npn должен сообщить "синтаксическому анализатору" интерфейса, что он должен ожидать после \cs_new_<restrictions>: Npnчасти кода, в данном случае одного управляющего слова токена, то есть <function name>одного или нескольких параметров, то есть <function parameters>и токена list, т. е. {<code>}заменяющий функцию.

Итак, если я хочу определить новую функцию, которая принимает, скажем, 4 аргумента, я могу сделать это с помощью следующего кода

\cs_new_<restrictions>:Npn \myfunction #1 #2 #3 #4 {<code>}

Точно так же код функции с двумя аргументами может выглядеть примерно так

\cs_new_<restrictions>:Npn \myfunction #1 #2 {<code>}

Конечно, я предполагаю - и поправьте меня , если я ошибаюсь - пробелы не нужны, потому что анализатор уже было сказано , как разграничить «мета» аргументы ( <function name>, <parameters>, {<code>}) друг от друга с помощью "мета-подпись" Npn .

Теперь, если я хочу избавиться от #, я могу использовать следующую общую команду

\cs_new_<restrictions>:Nn <function name>:<function signature> {<code>}

Аналогичная сделка, за исключением того, что теперь синтаксический анализатор ожидает после этого что-то <function signature>вроде Nn, NnN, TnN или что-то еще <function name>.

Итак, снова функция с 4 аргументами может выглядеть так

\cs_new_<restrictions>:Nn \myfunction:NNNN {<code>}

и один с двумя такими аргументами

\cs_new_<restrictions>:Nn \myfunction:NN {<code>}

В библиотеке l3basics есть и другие команды для создания функций, но их общая структура кажется по существу такой же. Единственная разница в их функциональности. Так, например, использование \cs_set...вместо \cs_new...делает функцию локальной, а не глобальной. Я, вероятно, напишу следующий пост с просьбой предоставить более подробную информацию о том, что такое расширения e-type и x-type, но пока я думаю, что лучше всего придерживаться общей картины.

В любом случае, это так?

Хорошо, идем дальше.

Определения переменных .

Что мне удалось выяснить :

Итак, в LaTeX3 довольно много типов данных, но основные из них - это списки токенов , строки , целые числа , последовательности и списки, разделенные запятыми . Каждый из них использует свои собственные сокращения, но, как правило, при определении новой переменной вы объявляете тип и дополняете его ключевым словом, например new или const, в зависимости от того, инициализируете ли вы переменную.

Так, например, если я хочу объявить, но не инициализировать переменную списка токенов, я использую код:

\tl_new:N \mytokenList

а затем где-нибудь по строке я могу сохранить список токенов \mytokenListс кодом:

\tl_set:Nn \mytokenList {<tokens>}

Но, если я знаю, какие данные я хочу сохранить в переменной с самого начала, я могу вместо этого использовать эту команду (не применяется к последовательностям или целым числам )

\tl_const:Nn \mytokenList {<tokens>}

В сторону: я заметил, что даже переменные имеют «функциональные сигнатуры». Вероятно, упрощает определение режима синтаксического анализа.

Это примерно так же, как и я, прежде чем мне нужно будет указать, к какому типу данных я обращаюсь, потому что каждый имеет свои собственные связанные операции.

-------------------------------------------------- -------------------------------------------------- -------------------

Вот что у меня есть до сих пор. Буду признателен за любые отзывы. Самостоятельно этому научиться нелегко! Особенно с минимальным знанием TeX, так что прошу прощения, если некоторые из вас смотрят на это и думают «хорошо, очевидно». В любом случае, еще раз спасибо.

Ответы

2 egreg Sep 03 2020 at 17:30

Есть два основных способа определения функций:

\cs_new<restrictions>:Npn

\cs_new<restrictions>:Nn

где может быть _protected, _noparили _protected_nopar.

Оба способа проверяют, что следующий за Nаргументом -аргументом (то есть одиночный токен) является управляющей последовательностью (или активным символом), которая в настоящее время не определена, и глобально определяют управляющую последовательность.

Какая разница? Первое семейство требует после определения последовательности управления «текст параметра» перед {ограничивающим «текстом замены» функции.

«Текст параметра» может быть любой последовательностью знаков , включая #1, #2и так далее до #9. Однако, чтобы оценить всю мощь этой свободы, вам нужно ознакомиться с главой 20 TeXbook и концепцией «ограниченного аргумента».

Однако давайте будем простыми. Два следующих фрагмента кода полностью эквивалентны:

\cs_new:Npn \harry_foo:nn #1 #2 { -#1-#2- }
\cs_new:Nn \harry_foo:nn { -#1-#2- }

потому что в этом случае последний автоматически предоставит текст параметра #1#2на основе сигнатуры определяемой функции :nn.

Подпись должна состоять из (возможно , пустой) последовательности nи Nсимволов.

Обратите внимание, что пробелы игнорируются, когда \ExplSyntaxOnон активен, поэтому

\cs_new:Npn \harry_foo:nn #1 #2 { -#1-#2- }
\cs_new:Npn \harry_foo:nn #1#2 { -#1-#2- }
\cs_new:Npn \harry_foo:nn #1#2{ -#1-#2- }

все эквивалентны. Там может быть место даже после #, но я бы не рекомендовал его.

Правила синтаксиса TeX указывают, что когда он ожидает «текст параметра» (в основном, при выполнении \defили аналогичных назначениях и после сохранения имени определяемого макроса) все до первого {является частью текста параметра. Невозможно предугадать, что такое текст параметра, отсюда и специальный pспецификатор аргумента, который просто означает «все до {».

Только простой текст параметра, такой как #1, #1#2и т. Д., Может быть автоматически сгенерирован, что происходит при использовании второго семейства \cs_new<restrictions>:Nn.

Где ты не прав? Предполагая, что вы можете использовать Tв качестве спецификатора в подписи. Спецификаторы аргумента Tили Fдобавляются при \prg_new_conditional<restrictions>:Nnnвыполнении.

Также ваш анализ текста параметра неверен, как показано ранее.

А как насчет \cs_set<restrictions>:Npnи :Nn? Применяется все, как указано выше, с той разницей, что определяемая функция не проверяется на предмет определения или нет, и ее значение будет автоматически перезаписано, но область объявления совпадает с текущей группой. Обычно \cs_set...используется для временных функций, которые необходимо адаптировать к контексту, чтобы их значение не было фиксированным.


В обозначения для переменных рекомендует , что их имя начинается с l, gили c. Фактически, переменные, используемые в expl3коде, должны соответствовать соглашению; можно использовать «нормальные» имена, например, \myTokenListдля переменных типа tl(возможно, также clist), которые будут использоваться в документе.

Переменные, начинающиеся с, lвсегда должны обрабатываться локально ( \tl_set:Nnскажем), а переменные, начинающиеся с, gвсегда должны обрабатываться глобально ( \tl_gset:Nnскажем).

Переменные, начинающиеся с символа, cявляются константами и никогда не должны использоваться после присвоения значения, а должны использоваться только.

Можно определить константы с помощью

\tl_const:Nn \c_harry_foo_tl {<tokens>}
\str_const:Nn \c_harry_foo_str {<tokens>}
\clist_const:Nn \c_harry_foo_clist {<comma list>}
\seq_const_from_clist:Nn \c_harry_foo_seq {<comma list>}
\prop_const_from_keyval:Nn \c_harry_foo_prop {<key-value list>}
\int_const:Nn \c_harry_foo_int {<integer expression>}
\fp_const:Nn \c_harry_foo_int {<fp expression>}
\bool_const:Nn \c_harry_foo_bool {<boolean expression>}
\dim_const:Nn \c_harry_foo_dim {<dimen expression>}
\skip_const:Nn \c_harry_foo_dim {<skip expression>}
\muskip_const:Nn \c_harry_foo_dim {<muskip expression>}
\intarray_const_from_clist:Nn \c_harry_foo_intarray {<comma list>}
\regex_const:Nn \c_harry_foo_regex {<regex>}
\cc_tab_const:Nn \c_harry_foo_cctab {<code>}