\span
プリミティブに何度か遭遇しました。TeXプログラムで定義されているという印象を受けましたが、 でもありませんplain.tex
。それは正しいですか?そして、するそのコマンドは何を実行し、何のために使用するのでしょうか?
答え1
プリミティブは、\span
本文の前文に現れる場合\halign
と本文に現れる場合とで、2 つの非常に異なる意味を持ちます。
これがプリアンブル、つまり最初のトークンの前にある場合は\cr
、後続のトークンを「展開する」ことを意味します。これが本体にある場合は、現在のセルを終了し、後続のセルと結合します。この場合、通常は と組み合わせて使用されます\omit
。
最も簡単な例は
\halign{\hfil#\tabskip1em&#\hfil\cr
a&b\cr
c\span d\cr
}
2行目にはセルが1つだけあります。出力は次のようになります。
2 行目は前後の内容\tabskip
を含む 1 つのセルだけなので、「c」と「d」の間にはスペースがありませんが、TeX はセルの幅を決定する際にこれを考慮します。\hfil
\tabskip
しかし、通常は\omit
、あなたそしてヴ部品(あなた前にあるものを指します#
。ヴそれに続くものへ。
TeX が のプリアンブルを読み込むとき、\halign
が見つからない限りトークンを展開しません\tabskip
(適切なグルー仕様を見つけるためにトークンを展開するとき)。 を前に付けると、トークンの展開を強制できます\span
。
一例としてはamsmath.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%
}
これは、および関連で使用されるヘルパーマクロですalign
。プリアンブルはマクロ内で一度だけ定義されます。\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@
}
\align@
これにより、マクロに大量のコードを配置することで、の定義が大幅に簡素化されます。また、align
を変更することでの挙動を変更することもできます\align@preamble
(奇数列に暗黙的にプレフィックス {} を付けることは可能ですか?)。
LaTeX カーネルは、文字tabular
の組み合わせなど、その規則に従ってプリアンブルを構築する必要があるため、に対して異なる方法を使用しますlcrp
。
の2番目の用途は、\span
列を結合することです\halign
。Plain TeXでは、\multispan
\def\multispan#1{\omit \mscount#1\relax
\loop\ifnum\mscount>\@ne \sp@n\repeat}
\def\sp@n{\span\omit\advance\mscount\m@ne}
は、引数に指定された\omit
数(マイナス1)のペアを追加します。つまり、は、、、などと同じです。LaTeXのマクロも同じアイデアに基づいています。\span\omit
\multispan{1}
\omit
\multispan{2}
\omit\span\omit
\multicolumn
% 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}
まず最初に(Plain とまったく同じように定義されます)、 およびで使用されるものと\multispan{#1}
同じものを使用して「ローカル」アライメント プリアンブルを構築し、必須の引数を評価します。\@mkpream
tabular
array
なぜ Knuth は 2 つのまったく異なる意味に同じプリミティブを使用したのでしょうか。スペースを節約するためです。TeX はコンピュータのメモリ スペースが少ないときに書かれたもので、定義を節約することが重要でした。 は(または、もちろん )\span
でのみ出現できるため、問題にはなりません。\halign
\valign
最初の意味での の誤った使用法は、\span
TeXbookの演習20.16の解答に現れている。
以下のことはあまり真剣に受け止めるべきではありませんが、確かに効果があります。
{\setbox0=\vbox{\halign{#{\c\span\d}\cr \let\next=0\edef\next#1{\gdef\next{\b#1}}\next\cr}}} \let\a=\next
この演習では\a
、 を\b
(完全に展開) に続いて\c
(展開されていない) と\d
(一度だけ展開)を、\noexpand
と を使わずに定義する\the
。例えば、
\def\foo{xy\baz}
\def\baz{z}
\def\b{\foo\foo}
\def\c{--}
\def\d{\baz}
\a
置換テキストとして定義したいのは
xyzxyz\c\baz
部分は出力なしで\setbox0=\vbox{
単に使用するだけです。TeXはプリアンブルを と評価します。これは の1レベル展開を引き起こすためです。セルには以下が含まれます。\halign
\halign
#{\c\baz}\cr
\span
\d
\let\next=0\edef\next#1{\gdef\next{\b#1}}\next
規則によれば、#
プリアンブルの の代わりに が使用され、入力ストリームは
\let\next=0\edef\next#1{\gdef\next{\b#1}}\next{\c\baz}\cr
は\cr
セルを終了させるだけなので、関係ありません。 のため\let\next=0
、\next
は展開不可能になり、 が定義されるように\edef
なります。\next
\def\next#1{\gdef\next{<full expansion of \b>#1}}
そして\next{\c\baz}
忠実に実行する
\gdef\next{<full expansion of \b>\c\baz}
そして最後が\let\a=\next
すべてを終わらせます。
これは\span
、1つ拡大のステップ。
\noexpand
e-TeX(結局、と は使用しない\the
)での別の解決策は次のようになります。
\edef\a{\b\unexpanded\expandafter{\expandafter\c\d}}