La macro\bordermatrixpermette di scrivere matrici “etichettate”, cioè nelle quali le righe e le colonne abbiano, esternamente alla matrice, simboli che spieghino la natura dei dati. Si tratta di una macro Plain, ma la sua definizione contiene parecchie idee interessanti.
\newdimen\p@renwd \setbox0=\hbox{\tenex B} \p@renwd=\wd0 \def\bordermatrix#1{\begingroup \m@th \setbox\z@\vbox{ \def\cr{\crcr\noalign{\kern2\p@\global\let\cr\endline}}% \ialign{$##$\hfil\kern2\p@\kern\p@renwd &\thinspace\hfil$##$\hfil &&\quad\hfil$##$\hfil\crcr \omit\strut\hfil\crcr\noalign{\kern-\baselineskip}% #1\crcr\omit\strut\cr}}% \setbox\tw@\vbox{\unvcopy\z@\global\setbox\@ne\lastbox}% \setbox\tw@\hbox{% \unhbox\@ne\unskip\global\setbox\@ne\lastbox}% \setbox\tw@\hbox{% $\kern\wd\@ne\kern-\p@renwd\left(\kern-\wd\@ne \global\setbox\@ne\vbox{\box\@ne\kern2\p@}% \vcenter{% \kern-\ht\@ne\unvbox\z@\kern-\baselineskip}\,\right)$}% \null\;\vbox{\kern\ht\@ne\box\tw@}\endgroup}
Le due righe che precedono la definizione di\bordermatrixintroducono un nuovo parametro dimensionale, che viene impostato come la larghezza del carat-tere ‘B’ nel font\tenex: si tratta semplicemente di una delle parentesi ‘grandi’. Infatti fra la prima e la seconda colonna del nostro allineamento dovremo inserire la parentesi che delimita la matrice.
L’inizio della definizione non ha nulla di problematico: si comincia un gruppo nel quale si dà il comando\m@thche azzera gli spazi supplementari che lo stile globale del documento potrebbe inserire prima e dopo una formula. A questo punto si compone una\vboxnel registro 0, dentro la quale si ridefinisce la primitiva\cr, vedremo poi perché.
In questa\vboxcostruiamo l’allineamento principale:\ialignè come\halign, ma azzera eventuali modifiche fatte a\tabskip. L’allineamento è costituito da un numero arbitrario di colonne:
• la prima colonna contiene una formula allineata a sinistra ($##$\hfil), se-guita da uno spazio di 2 pt e da un altro di ampiezza\p@renwde ancora da uno spazio sottile (\thinspace); il lettore attento noterà come il carattere# sia raddoppiato, dal momento che siamo in una definizione;
• la seconda colonna contiene una formula con allineamento al centro della cella (\hfil$##$\hfil);
• le colonne successive sono ripetizioni dello schema ‘spazio em’ e formula allineata al centro (\quad\hfil$##$\hfil).
Quando in un preambolo di tabella con\halignsi trova&&, ciò che segue fino a\cr viene ripetuto quante volte serve; qui si usa\crcrper terminare il preambolo di tabella, perché\crè stato ridefinito. La primitiva\crcrè quasi del tutto equivalente a\cr, ma non fa nulla se per caso segue\cr(con il suo significato originale).
Il comando\omitdice adesso a TEX di cominciare a costruire la tabella, ma omettendo lo schema impostato relativo alla prima colonna, nella quale viene solo
inserito un puntello (\strut) e la riga di tabella viene chiusa. Segue una spaziatura verticale negativa pari all’avanzamento di riga. Uno si domanda: perché? La rispo-sta è che questo permette di avere il controllo preciso su come comincia la\vbox, indipendentemente da ciò che sarà contenuto nella prima riga della nostra matrice bordata.
Lo stesso trucco si usa alla fine: infatti la definizione prosegue inserendo l’argo-mento del comando\bordermatrixe chiudendo l’ultima riga con\crcrin modo che, se l’utente della macro si dimentica di terminare la matrice con\cr, TEX non si trovi a mal partito. Però, prima di chiudere l’allineamento e la\vbox, viene ancora inserita una riga con\omit\strutcome prima. Questa riga “vuota” sarà annullata più tardi con una spaziatura negativa. Ma qui il trucco serve anche per un altro scopo: quando la\vboxè chiusa, l’ultima\hboxin essa sarà proprio l’unica colonna dell’allineamento, la cui ampiezza è esattamente quella delle etichette esterne, però a sua volta inscatolata in una\hboxampia quanto l’allineamento.
Ecco qui come usiamo questa informazione: si imposta il registro\box2come una\vboxnella quale prima liberiamo il contenuto del registro\box0e, per ultima cosa, impostiamo (globalmente) il registro\box1in modo che contenga l’ultima\box di cui è fatta\box0: lì dentro c’è una sola\hboxe con la riga successiva impostiamo di nuovo il registro\box2liberando il contenuto di\box1e ancora impostando (globalmente)\box1all’ultima\box(che è anche l’unica).
Il comando primitivo\lastboxsi può usare ovunque eccetto che in modo ver-ticale esterno, usualmente nella forma\setbox〈numero 〉=\lastbox. Se l’ultimo oggetto che si trova nella lista che TEX sta costruendo è una box, sarà rimossa dal-la lista e assegnata al registro\boxcon il numero indicato; naturalmente al posto di 〈numero 〉 si può usare un nome simbolico di registro definito con\newboxo \newsavebox(che sono più o meno equivalenti). Qui ‘lista’ non sta per ‘lista di to-ken’, ma per le liste di oggetti finali che TEX costruisce nel suo stomaco, non è il caso di addentrarci troppo nei dettagli.
Torniamo alla nostra macro. Ora l’ampiezza l0di\box1è quella della più larga etichetta esterna, aumentata di 2 pt e di p =\p@renwd, perché questa è l’ampiezza della prima colonna dell’allineamento. A questo punto costruiamo una nuova\hbox nel registro\box2; sarà una formula che però comincia con uno spazio orizzontale di l seguito da uno di −p, seguita da una parentesi alta quanto basta per contenere ciò che segue, usando\left. Dopo questa parentesi torniamo indietro di −l , in modo che la prima colonna dell’allineamento stia fuori dalla parentesi e poniamo nel registro\box1la stessa\box1seguita da uno spazio verticale di 2 pt. Ricordiamo che \box1, a questo punto, contiene solo un puntello, i 2 pt sono necessari per quanto diremo più tardi.
La formula prosegue con un\vcenterche comincia con una spaziatura verticale di −h, dove h è l’altezza del puntello, poi viene liberato il contenuto di\box0, cioè l’intero allineamento, seguito dalla spaziatura verticale che annulla, finalmente, quello prodotto dal puntello finale che abbiamo già usato un paio di volte. Terminato il\vcentermettiamo uno spazio fine e la parentesi di chiusura. Quanto è alta la parentesi? Se facciamo i conti, vediamo che la parentesi copre esattamente le righe dell’allineamento dalla seconda in poi, nell’ipotesi che ciò che sta nella prima riga non sia più alto del puntello.
Finora però non abbiamo prodotto nulla, perché tutto ciò che abbiamo costruito sta dentro registri\box. È il momento di usare i registri: un\nullper sicurezza, uno spazio medio per distanziare e poi una\vboxche comincia con uno spazio verticale alto come il puntello, in modo da annullare lo spazio negativo di prima (necessario
per regolare le parentesi), poi usiamo il registro\box2e chiudiamo il gruppo iniziato molto tempo fa. Ecco il risultato: il codice
\[\bordermatrix{% & X& Y& Z\cr A& 1& 2& 3\cr B& 4& 5& 6}\] produce la matrice etichettata
µ
X Y Z A 1 2 3
B 4 5 6 ¶
Rimane solo poco da vedere. Il misterioso
\def\cr{\crcr\noalign{\kern2\p@\global\let\cr\endline}}
non fa nulla di così misterioso, in realtà. Quando si scrive la prima riga dell’argomento di\bordermatrix, il\crsi espande come
\crcr\noalign{\kern2\p@\global\let\cr\endline}
e quindi la prima riga finisce per via di\crcr; poi viene inserito uno spazio verticale di 2 pt e\crriprende il suo significato usuale, perché il comando\endlineha il significato primitivo di\cr, come\endgrafquello primitivo di\par. E infatti, se si osserva bene, la righa delle etichette delle colonne è separata dalla matrice da uno spazio supplementare e di questi 2 pt abbiamo tenuto conto quando si è trattato di dimensionare le parentesi.
L’assunzione sull’altezza di queste etichette di colonne non sempre è valida: consideriamo per esempio
\[\def\X{{\displaystyle U\over\displaystyle V}} \bordermatrix{%
&\X& Y& Z\cr A& 1& 2& 3\cr B& 4& 5& 6}\]
(dove si è usata la sintassi Plain per le frazioni) e vediamo che succede:
à U V Y Z A 1 2 3 B 4 5 6 !
È evidente che i conti non tornano, se riguardiamo quanto è stato fatto per dimensio-nare le parentesi. Una macro che funzioni in tutti i casi dovrebbe avere due argomenti: la riga delle etichette, in modo da poterla misurare separatamente, e il resto della matrice.
La macro si può usare anche in LATEX e la definizione è del tutto simile, solo che invece di\p@renwdsi usa una dimensione fissa di 8,75 pt. Sarebbe un utile esercizio provare a trasformare la definizione della macro in quella di un ambiente dove, possibilmente, si adoperi\\come terminatore delle righe.