¿Qué es el comando \span?

¿Qué es el comando \span?

Me he topado con lo \spanprimitivo un par de veces. Me dio la impresión de que está definido en el programa TeX, ni siquiera enplain.tex . ¿Está bien? Y quéhaceque comando hace y para que sirve?

Respuesta1

El primitivo \spantiene dos significados muy diferentes si aparece en el preámbulo \haligno en el cuerpo.

Si está en el preámbulo, es decir, antes del primero, \crsignifica "expandir" el siguiente token; si aparece en el cuerpo finaliza la celda actual, pero la fusiona con la siguiente. En este caso suele ir en combinación con \omit.

El ejemplo más simple es

\halign{\hfil#\tabskip1em&#\hfil\cr
  a&b\cr
  c\span d\cr
}

donde la segunda fila tendrá solo una celda. La salida será

ingrese la descripción de la imagen aquí

sin \tabskipespacio entre “c” y “d”, porque la segunda fila es solo una celda con \hfilantes y después del contenido, pero TeX tendrá en \tabskipcuenta para determinar el ancho de la celda.

Sin embargo, normalmente también se añade \omitpara eliminar eltuyvpartes (tuse refiere a lo que viene antes #,va lo que sigue).

Cuando TeX lee un preámbulo, \halignno expande los tokens a menos que los encuentre \tabskip(cuando expande los tokens para encontrar la especificación de pegamento adecuada). La expansión de un token se puede forzar precediéndolo con \span.

Un ejemplo está enamsmath.sty

\def\align@#1#2{%
    \inalign@true \intertext@ \Let@ \chardef\dspbrk@context\z@
    \ifingather@\else\displ@y@\fi
    \let\math@cr@@@\math@cr@@@align
    \ifxxat@\else \let\tag\tag@in@align \fi
    \let\label\label@in@display
    #1% set st@r
    \ifst@rred\else \global\@eqnswtrue \fi
    \measure@{#2}%
    \global\row@\z@
    \tabskip\eqnshift@
    \halign\bgroup
        \span\align@preamble\crcr
        #2%
}

Esta es una macro auxiliar utilizada para aligny amigos; el preámbulo se define de una vez por todas en la macro\align@preamble

\def\align@preamble{%
   &\hfil
    \strut@
    \setboxz@h{\@lign$\m@th\displaystyle{##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \tabskip\z@skip
   &\setboxz@h{\@lign$\m@th\displaystyle{{}##}$}%
    \ifmeasuring@\savefieldlength@\fi
    \set@field
    \hfil
    \tabskip\alignsep@
}

Esto simplifica enormemente la definición de \align@, al colocar una gran cantidad de código en una macro. También permite cambiar el comportamiento alignmodificando \align@preamble(ver¿Es posible hacer que las columnas impares tengan implícitamente un prefijo {}?).

El kernel de LaTeX utiliza un método diferente para tabular, porque necesita construir el preámbulo de acuerdo con sus reglas, es decir, una combinación de lcrpcaracteres, etc.

El segundo uso de \spanes para fusionar columnas en un archivo \halign. En Plain TeX encontramos\multispan

\def\multispan#1{\omit \mscount#1\relax
  \loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}

que hace \omity suma tantos \span\omitpares como se indica en el argumento (menos uno); so \multispan{1}es equivalente a \omit, \multispan{2}to \omit\span\omity así sucesivamente. La \multicolumnmacro de LaTeX se basa en la misma idea.

% latex.ltx, line 5053:
\long\def\multicolumn#1#2#3{\multispan{#1}\begingroup
  \@mkpream{#2}%
  \def\@sharp{#3}\set@typeset@protect
  \let\@startpbox\@@startpbox\let\@endpbox\@@endpbox
  \@arstrut \@preamble\hbox{}\endgroup\ignorespaces}

Primero lo hace \multispan{#1}(definido exactamente como en Plain) y luego procede a construir un preámbulo de alineación "local" utilizando el mismo \@mkpreamutilizado por tabulary arraypara evaluar su argumento obligatorio.

¿Por qué Knuth utilizó el mismo primitivo para dos significados muy diferentes? Para ahorrar espacio; TeX se escribió cuando el espacio en la memoria de la computadora era bajo y era importante guardar una definición. Como \spansólo puede aparecer en \halign(o \valign, por supuesto), no es un problema.

Un uso tortuoso de \spanen el primer significado aparece en la solución del ejercicio 20.16 del TeXbook.

Lo siguiente no debe tomarse demasiado en serio, pero funciona:

{\setbox0=\vbox{\halign{#{\c\span\d}\cr
       \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}}
 \let\a=\next

El ejercicio consiste en definir \aque sea equivalente a \b(completamente expandido) seguido de \c(no expandido) y de \d(expandido solo una vez) sin usar \noexpandy \the. Por ejemplo, si tenemos

\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}

queremos definir \atener como texto de reemplazo

xyzxyz\c\baz

La \setbox0=\vbox{pieza es solo para usar \halignsin ningún resultado. Ahora TeX evalúa el \halignpreámbulo como #{\c\baz}\cr, porque \spanprovoca una expansión de un nivel de \d. La única celda contiene

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next

que, de acuerdo con las reglas, se usa en lugar de #en el preámbulo, de modo que el flujo de entrada se convierte en

\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr

Simplemente \crtermina la celda, por lo que no es relevante. Debido a que \let\next=0se \nextvuelve inexpandible, por lo que \edefprovoca \nextque se defina como si hubiera sido

\def\next#1{\gdef\next{<full expansion of \b>#1}}

y así \next{\c\baz}ejecutará obedientemente

\gdef\next{<full expansion of \b>\c\baz}

y el final \let\a=\nextacaba con todo.

Esto explica bien que \spansolounopaso de expansión.


Una solución diferente con e-TeX (no usa \noexpandy \the, después de todo), sería

\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}

información relacionada