Interfaccia LaTeX3 per le funzioni
Recentemente ho pubblicato una domanda sulla scrittura di una macro in TeX semplice che modificherebbe gli elementi in un elenco specificato dall'utente. Ho accennato con disinvoltura alla mia antipatia per l'interfaccia di TeX, quindi qualcuno mi ha trasformato in LaTeX3, che dovrebbe essere, come promette il manuale, più simile a un moderno linguaggio di programmazione. Sto appena iniziando a programmare in TeX, quindi è stata una dura battaglia cercare di capire il manuale. Presumo sia perché il manuale è stato scritto per utenti esperti di TeX; tuttavia, non sembra esserci un'alternativa là fuori per le persone che hanno appena iniziato con LaTeX3 / TeX, quindi non ho altra scelta che lavorare con quello che ho. Ecco perché sto postando questo. Il manuale crea confusione e vorrei chiarire un po 'di quella confusione ponendovi alcune semplici domande sulla sintassi.
Dovrei menzionare, la persona che mi ha parlato di LaTeX3, mi ha anche dato una soluzione al mio post originale usando la sua interfaccia. Sono stato in grado di utilizzare questa soluzione insieme al manuale per iniziare a elaborare alcuni fatti di base sulla sintassi LaTeX3. Parlerò di ciò che sono riuscito a capire, ma un giusto avvertimento, alcune delle quali si basano sulle mie inferenze - disegnate con l'aiuto dell'esempio fornito dall'utente di stackexchange - non istruzioni esplicite nel manuale, quindi aspettati errori. Vorrei che tu sapessi che non sto offuscando le cose quando a volte uso la mia terminologia. È solo difficile parlare di un argomento che non capisci completamente in modo strutturato.
Inoltre sto scrivendo questo come un post separato, non un commento, a causa della sua lunghezza. Grazie in anticipo.
-------------------------------------------------- -------------------------------------------------- -------------------
Definizioni di funzione .
Quello che sono riuscito a capire finora :
Una nuova funzione viene definita, tra l'altro, con il seguente codice:
\cs_new_<restrictions>:Npn <function name> <function parameters> {<replacement code>}
Il \cs_new_<restrictions>è un comando LaTeX, la NPN è lì per dire "parser" dell'interfaccia che cosa deve aspettarsi dopo la \cs_new_<restrictions>: Npnparte del codice, in questo caso, una sola parola di token di controllo, vale a dire <function name>, uno o più parametri, vale a dire <function parameters>, e un gettone list, cioè {<code>}che sostituisce la funzione.
Quindi, se voglio definire una nuova funzione che richiede, diciamo, 4 argomenti, potrei farlo con il seguente codice
\cs_new_<restrictions>:Npn \myfunction #1 #2 #3 #4 {<code>}
Allo stesso modo il codice per una funzione con 2 argomenti potrebbe assomigliare a questo
\cs_new_<restrictions>:Npn \myfunction #1 #2 {<code>}
Naturalmente, sto assumendo - e mi corregga se sbaglio - gli spazi non sono necessari, perché il parser è già stato detto come per delineare gli argomenti "meta" ( <function name>, <parameters>, {<code>}) l'una dall'altra, con l'aiuto di la "meta firma" Npn .
Ora, se voglio farla finita con gli # posso usare il seguente comando generico
\cs_new_<restrictions>:Nn <function name>:<function signature> {<code>}
Accordo simile, tranne che ora il parser si aspetta un <function signature>come Nn, NnN, TnN o qualcosa del genere dopo <function name>.
Quindi, di nuovo, una funzione con 4 argomenti potrebbe assomigliare a questa
\cs_new_<restrictions>:Nn \myfunction:NNNN {<code>}
e uno con 2 argomenti come questo
\cs_new_<restrictions>:Nn \myfunction:NN {<code>}
Ci sono altri comandi nella libreria l3basics per creare funzioni, ma la loro struttura generale sembra essere essenzialmente la stessa. L'unica differenza è nella loro funzionalità. Quindi, ad esempio, usare \cs_set...invece di \cs_new...rende la funzione locale anziché globale. Probabilmente scriverò un post di follow-up chiedendo maggiori dettagli su cosa sono le espansioni e-type e x-type, ma per ora penso che sia meglio attenersi al quadro generale.
Comunque, è vero finora?
Va bene, andiamo avanti.
Definizioni variabili .
Quello che sono riuscito a capire finora :
Quindi ci sono alcuni tipi di dati in LaTeX3, ma i principali sono elenchi di token , stringhe , numeri interi , sequenze ed elenchi separati da virgole . Ognuno di loro usa le proprie abbreviazioni, ma in generale, quando si definisce una nuova variabile, si dichiara il tipo e lo si fa seguire con una parola chiave come new o const a seconda che si stia inizializzando la variabile.
Quindi, ad esempio, se voglio dichiarare, ma non inizializzare, una variabile dell'elenco di token, utilizzo il codice:
\tl_new:N \mytokenList
e poi da qualche parte lungo la linea, posso memorizzare un elenco di token \mytokenListcon il codice:
\tl_set:Nn \mytokenList {<tokens>}
Ma, se so quali dati voglio memorizzare nella variabile dall'inizio, posso invece usare questo comando (non si applica a sequenze o numeri interi )
\tl_const:Nn \mytokenList {<tokens>}
A parte: ho notato che anche le variabili hanno "firme di funzione". Probabilmente semplifica la definizione di un regime di analisi.
È il più generale possibile, prima di dover specificare a quale tipo di dati mi riferisco, perché ognuno ha le proprie operazioni associate.
-------------------------------------------------- -------------------------------------------------- -------------------
Questo è quello che ho finora. Apprezzerei qualsiasi feedback. Questa roba non è facile da imparare da solo! Soprattutto con una conoscenza minima di TeX, quindi mi scuso se alcuni di voi lo guardano e pensano "ovviamente bene". Comunque, grazie ancora.
Risposte
Esistono due modi principali per definire le funzioni:
\cs_new<restrictions>:Npn
\cs_new<restrictions>:Nn
dove può essere _protected, _noparo _protected_nopar.
Entrambi i modi controllano che l' Nargomento (cioè un singolo token) che segue sia una sequenza di controllo (o carattere attivo) che è attualmente indefinito e definisce globalmente la sequenza di controllo.
Qual è la differenza? Che la prima famiglia richiede, dopo la definizione della sequenza di controllo, un “testo parametro” prima della {delimitazione del “testo sostitutivo” della funzione.
Il "testo del parametro" può essere qualsiasi sequenza di token inclusi #1, #2e così via fino a #9. Tuttavia, per apprezzare la piena potenza di questa libertà, è necessario conoscere il capitolo 20 del TeXbook e il concetto di "argomento delimitato".
Manteniamolo semplice, però. Le due parti di codice seguenti sono completamente equivalenti:
\cs_new:Npn \harry_foo:nn #1 #2 { -#1-#2- }
\cs_new:Nn \harry_foo:nn { -#1-#2- }
perché quest'ultimo fornirà automaticamente il testo del parametro in #1#2base alla firma della funzione da definire, in questo caso :nn.
La firma dovrebbe essere composta da una sequenza (possibilmente vuota) di ne Ncaratteri.
Nota che gli spazi vengono ignorati quando \ExplSyntaxOnè attivo, quindi
\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- }
sono tutti equivalenti. Potrebbe esserci uno spazio anche dopo #, ma non lo consiglierei.
Le regole di sintassi di TeX specificano che quando si aspetta un “testo di parametro” (in pratica, quando si eseguono \defo simili assegnazioni e dopo aver memorizzato il nome della macro da definire) tutto fino al primo {fa parte del testo del parametro. Non c'è modo di prevedere quale sia il testo del parametro, da qui lo specificatore di pargomento speciale che significa semplicemente "tutto fino a {".
Solo un testo di parametro semplice come #1, #1#2e così via può essere generato automaticamente, cosa che viene eseguita quando si utilizza la seconda famiglia \cs_new<restrictions>:Nn.
Dove sbagli? Presumendo che tu possa usare Tcome specificatore nella firma. Gli specificatori di argomento To Fvengono aggiunti quando \prg_new_conditional<restrictions>:Nnnviene eseguito.
Anche la tua analisi del testo del parametro è sbagliata, come mostrato prima.
Che mi dici di \cs_set<restrictions>:Npne :Nn? Vale tutto quanto sopra, con la differenza che la funzione da definire non viene controllata per essere definita o meno e il suo significato verrà silenziosamente sovrascritto, ma lo scopo della dichiarazione coincide con il gruppo corrente. In genere, \cs_set...viene utilizzato per funzioni temporanee che devono adattarsi al contesto in modo che il loro significato non sia fisso.
Le convenzioni di denominazione per le variabili consigliano che il loro nome inizi con l, go c. In realtà, le variabili usate nel expl3codice dovrebbero essere conformi alla convenzione; è possibile utilizzare nomi “normali” come \myTokenListper le variabili di tipo tl(forse anche clist) che devono essere usate nel documento.
Le variabili che iniziano con ldovrebbero sempre essere applicate localmente ( \tl_set:Nn, diciamo), mentre le variabili che iniziano con gdovrebbero sempre essere agite globalmente ( \tl_gset:Nn, diciamo).
Le variabili che iniziano con csono costanti e non dovrebbero mai essere applicate dopo aver ricevuto un valore, ma solo usate.
Si possono definire costanti con
\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>}