% \iffalse meta-comment % % Copyright (C) 2005 by Kevin W. Hamlen % ------------------------------------- % % This file may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either % version 1.3a of this license or (at your option) any later % version. The latest version of this license is in: % % http://www.latex-project.org/lppl.txt % % and version 1.3a or later is part of all distributions of % LaTeX version 2004/10/01 or later. % % \fi % % \iffalse %<*driver> \ProvidesFile{trfrac.dtx} % %\NeedsTeXFormat{LaTeX2e} %\ProvidesPackage{trfrac} %<*package> [2006/05/01 v2.0 Tree Fraction Package] % % %<*driver> \documentclass{ltxdoc} \usepackage{amsmath} \usepackage{hyperref} \usepackage{trfrac} \newcount\seclevel% \newcommand{\getseclevel}{% \global\seclevel=3\relax% \ifnum\arabic{subsection}=0\global\seclevel=2\relax\fi% } {\catcode`/=0 \catcode`\\=11 /gdef/DescMacro#1{% /getseclevel% /pdfbookmark[/the/seclevel]{\\#1}{macdef-#1}% /expandafter/DescribeMacro/expandafter{/csname #1/endcsname}% /hyperdef{macro}{#1}{}/kern0pt% } } \newcommand{\DescEnv}[1]{% \getseclevel% \pdfbookmark[\the\seclevel]{#1}{envdef-#1}% \DescribeEnv{#1}% \hyperdef{env}{#1}{}\kern0pt% } \newcommand{\mac}[1]{{\tt\hyperlink{macro.#1}{\char92 #1}}} \newcommand{\env}[1]{{\tt\hyperlink{env.#1}{#1}}} \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{trfrac.dtx} \end{document} % % \fi % % \CheckSum{443} % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % \changes{v1.0}{2005/09/05}{Initial version} % \changes{v2.0}{2006/05/01}{Renamed to TrFrac package} % % \GetFileInfo{trfrac.dtx} % % \title{The \textsf{trfrac} package\thanks{This document corresponds to % \textsf{trfrac}~\fileversion, dated~\filedate.}} % \author{Kevin W.~Hamlen} % % \maketitle % % \begin{abstract} % The |trfrac| package provides convenient mechanisms for typesetting % derivation trees in \LaTeX. % Derivation trees look like nested fractions; thus, the primary contribution % of this software is a macro |\trfrac| that functions much like \LaTeX's % |\frac| for fractions, but with a number of important differences that make % it better suited to derivation trees. % \end{abstract} % % \section{Introduction} % % Typing rules and typing derivations in formal typing systems are usually % written like fractions in which the numerator consists of one or more % premise judgments or derivations, and the denominator consists of a % single conclusion judgment. % For example, the typing rule for application in the simply-typed lambda % calculus is typically written % \[ \trfrac[\small(\emph{app})] % {\Gamma \vdash e_1:\tau\rightarrow\tau' \qquad % \Gamma \vdash e_2:\tau} % {\Gamma \vdash e_1 e_2 : \tau'} \] % where $\Gamma \vdash e_1:\tau\rightarrow\tau'$ and $\Gamma \vdash e_2:\tau$ % are the two premise judgments of the rule, and % $\Gamma \vdash e_1 e_2 : \tau'$ is the conclusion judgment. % % Simple rules like the above are easy to typeset with \LaTeX's built-in % |\frac| macro, or with fraction macros like |\dfrac| provided by the % |amslatex| package; but when derivations consist of a tree of nested rules, % |\frac| and |\dfrac| often prove inadequate because they yield spacing % and alignment that is unsuited to derivation trees. % For example, consider the derivation % \[ \trfrac[\small(\emph{app})] % {\Gamma \vdash e_1:\tau\rightarrow\tau' \qquad % \trfrac[\small(\emph{app})] % {\Gamma \vdash e_2:\tau''\rightarrow\tau \qquad % \Gamma \vdash e_3:\tau''} % {\Gamma \vdash e_2 e_3:\tau}} % {\Gamma \vdash e_1 (e_2 e_3):\tau'} \] % which contains a nested subderivation of one of its premise judgments. % This was easily typeset using the |\trfrac| macro provided by % the |trfrac| package. % The complete \LaTeX\ code is as follows: % \begin{verbatim} % \[ \trfrac[\small(\emph{app})] % {\Gamma \vdash e_1:\tau\rightarrow\tau' \qquad % \trfrac[\small(\emph{app})] % {\Gamma \vdash e_2:\tau''\rightarrow\tau \qquad % \Gamma \vdash e_3:\tau''} % {\Gamma \vdash e_2 e_3:\tau}} % {\Gamma \vdash e_1 (e_2 e_3):\tau'} \] % \end{verbatim} % In contrast, if one writes analogous code using |\dfrac| instead of % |\trfrac|, the result is % \[ \dfrac{\Gamma \vdash e_1:\tau\rightarrow\tau' \qquad % \dfrac{\Gamma \vdash e_2:\tau''\rightarrow\tau \qquad % \Gamma \vdash e_3:\tau''} % {\Gamma \vdash e_2 e_3:\tau}\text{\small(\emph{app})}} % {\Gamma \vdash e_1 (e_2 e_3):\tau'}\text{\small(\emph{app})} \] % which is unsuitable for two reasons: % First, the leftmost premise is floating up above the fraction bar when % it should be sitting on the bar. % Second, the bottom fraction bar is longer than it should be; it has been % unnecessarily extended rightward to span the entire ``numerator'' of the % ``fraction''. % This can become problematic when derivations are large and horizontal % space is at a premium. % % In addition to providing |\trfrac| as an alternative to fraction macros, % the |trfrac| package also provides two environments that can be helpful % for squeezing numerous and/or lengthy premise judgments into a smaller % amount of horizontal space. % Derivations can sometimes contain long judgments that must be wrapped, or % numerous premise judgments that must be placed above one another for lack % of space. % The |trfrac| package provides math environments |trgather| and |tralign| % for stacking sets of judgments vertically within a derivation tree. % The |trgather| environment horizontally centers each judgment in the stack, % whereas the |tralign| environment aligns each judgment at a specified point. % For example, the derivation % \[ \trfrac[\small(\emph{case})] % {\begin{trgather} % \Gamma \vdash e:\tau_1+\tau_2 \\ % \Gamma[x_1\mapsto\tau_1] \vdash e_1:\tau \qquad % \Gamma[x_2\mapsto\tau_2] \vdash e_2:\tau % \end{trgather}} % {\begin{tralign} % \Gamma \vdash \mathbf{case}~e~\mathbf{of}~ % &\mathit{in}_1(x_1)\Rightarrow e_1 \\ % \mid\,&\mathit{in}_2(x_2)\Rightarrow e_2 : \tau % \end{tralign}} \] % can be produced with % \begin{verbatim} % \[ \trfrac[\small(\emph{case})] % {\begin{trgather} % \Gamma \vdash e:\tau_1+\tau_2 \\ % \Gamma[x_1\mapsto\tau_1] \vdash e_1:\tau \qquad % \Gamma[x_2\mapsto\tau_2] \vdash e_2:\tau % \end{trgather}} % {\begin{tralign} % \Gamma \vdash \mathbf{case}~e~\mathbf{of}~ % &\mathit{in}_1(x_1)\Rightarrow e_1 \\ % \mid\,&\mathit{in}_2(x_2)\Rightarrow e_2 : \tau % \end{tralign}} \] % \end{verbatim} % % The |split| and |aligned| environments provided by the |amsmath| package % provide facilities for vertically stacking sub-equations in similar ways, % but like |\dfrac|, these often prove inadequate for derivation trees % because they vertically center the material they typeset, causing any % adjacent material to float above the fraction bar. % % \section{Usage} % % To start using the macros and environments provided by the |trfrac| package, % place the line % % \medskip{\narrower|\usepackage{trfrac}|}\medskip % % \noindent % somewhere near the top of your \TeX\ file. % % \DescMacro{trfrac} % Subsequently, within any math environment you can use % % \medskip{\narrower % |\trfrac[|\meta{name}|]{|\meta{premises}|}{|\meta{consequent}|}| % }\medskip % % \noindent % to typeset a derivation rule, where % \meta{name} is optional material processed in horizontal text mode % that is to sit to the right of the fraction bar, % \meta{premises} is math material that is to sit above the fraction bar, and % \meta{consequent} is math material that is to sit below the fraction bar. % The \meta{consequent} and \meta{name} may not contain additional |\trfrac| % macros, but the \meta{premises} may. % % The outermost |\trfrac| in a derivation will be vertically centered on its % fraction bar, but inner |\trfrac|'s in a derivation will have baselines at % the bottom of their consequents. % This makes it possible to typeset something like % \[ {\cal D} = % \trfrac[\small(\emph{app})] % {\Gamma \vdash e_1:\tau\rightarrow\tau' \qquad % \trfrac[\small(\emph{app})] % {\Gamma \vdash e_2:\tau''\rightarrow\tau \qquad % \Gamma \vdash e_3:\tau''} % {\Gamma \vdash e_2 e_3:\tau}} % {\Gamma \vdash e_1 (e_2 e_3):\tau'} \] % in which the material ``${\cal D} =$'' should be vertically centered with % respect to the bottom fraction bar, but the left premise should not be % centered with respect to the right subderivation's fraction bar. % % \DescEnv{trgather} % The environment % % \medskip{\narrower\parindent=0pt % |\begin{trgather}|\par % \hskip1em \meta{eqn$_1$} |\\[|\meta{len$_1$}|]|\par % \hskip1em \meta{eqn$_2$} |\\[|\meta{len$_2$}|]|\par % \hskip2em $\vdots$\par % \hskip1em \meta{eqn$_n$} |\\[|\meta{len$_n$}|]|\par % |\end{trgather}|\par % }\medskip % % \noindent % can be used in math mode to stack a set of equations, each of which is to % be centered horizontally over one another. % Here, \meta{eqn$_i$} is material processed in math mode and % \meta{len$_i$} is an optional length that modifies the vertical spacing % between the current equation and the next. % The baseline of the resulting stack of equations will be the baseline of % the bottom equation in the stack. % % \DescEnv{tralign} % The environment % % \medskip{\narrower\parindent=0pt % |\begin{tralign}|\par % \hskip1em \meta{left$_1$}|&|\meta{right$_1$} |\\[|\meta{len$_1$}|]|\par % \hskip1em \meta{left$_2$}|&|\meta{right$_2$} |\\[|\meta{len$_2$}|]|\par % \hskip2em $\vdots$\par % \hskip1em \meta{left$_n$}|&|\meta{right$_n$} |\\[|\meta{len$_n$}|]|\par % |\end{tralign}|\par % }\medskip % % \noindent % can be used in math mode to stack a set of equations, each of which is to % be aligned horizontally by the position of the |&| in the equation. % Here, \meta{left$_i$} and \meta{right$_i$} is the math material to be % placed to the left and right, respectively, of the vertical center axis of % the resulting stack of equations; % and \meta{len$_i$} is an optional length that modifies the vertical % spacing between the current equation and the next. % The baseline of the resulting stack of equations will be the baseline of % the bottom equation in the stack. % % \StopEventually{\PrintIndex} % % \section{Implementation} % % The following is a verbatim listing of the |trfrac| package implementation % with comments explaining how it works. % % \begin{macro}{\TRF@adjust} % The following dimen register will hold half the total vertical length % (height plus depth) of a box passed to |\TRF@squeeze|. % \begin{macrocode} \newdimen\TRF@adjust % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@squeeze} % Take a box and output it so that it is vertically centered across the % baseline, it consumes no horizontal space (like |\rlap|), and it consumes % no vertical space. % This is used for adding equation numbers to derivations. % \begin{macrocode} \newcommand\TRF@squeeze[1]{% \TRF@adjust0.5\ht#1% \advance\TRF@adjust0.5\dp#1% \vbox to\z@{% \kern-\TRF@adjust% \hb@xt@\z@{\box#1\hss}% \kern-\TRF@adjust% }% } % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@startp} % \begin{macro}{\TRF@endp} % When processing a numerator, the |\TRF@trfrac| code must be able to determine % if (a)~the current derivation is the first thing being added to the current % horizontal list, and if (b)~the current horizontal list ends in a derivation. % To accomplish this, two penalties of ``magic'' values are added to % horizontal lists: |\TRF@startp| is added at the beginning of a horizontal % list comprising a numerator, and |\TRF@endp| is added just after every % derivation. % Then |\lastpenalty| can be used to inquire whether the current horizontal % list ends in either ``magic'' value. % (Since derivations encased within numerators cannot undergo line-breaking, % these extra penalties will have no effect on \LaTeX's processing of the % actual output.) % \begin{macrocode} \newcount\TRF@startp\TRF@startp31415926 \newcount\TRF@endp\TRF@endp27182818 % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TRF@lastpenalty} % In accordance with the above, the result of |\lastpenalty| will be saved in % the following register before the current horizontal list is modified. % \begin{macrocode} \newcount\TRF@lastpenalty % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@level} % The outermost derivation behaves slightly differently than subderivations % within a derivation tree. % (Its baseline is its fraction bar instead of its denominator's baseline, % and it should not include the spurious |\TRF@endp| penalty, since % line-breaking might occur.) % The |\TRF@level| counter therefore tracks the current nesting level of % derivations. % \begin{macrocode} \newcount\TRF@level\TRF@level0 % \end{macrocode} % \end{macro} % % \begin{macro}{\ifTRF@derivok} % Subderivations are not permitted to appear within denominators or within % rule names. % The |\ifTRF@derivok| conditional is set to |false| when processing such % material. % \begin{macrocode} \newif\ifTRF@derivok\TRF@derivoktrue % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@lhang} % \begin{macro}{\TRF@rhang} % After processing a horizontal list that might contain one or more % derivations, |\TRF@lhang| will hold the horizontal distance by which the % leftmost derivation's numerator overhangs its fraction bar to the left % (or |0pt| if the leftmost list item is not a derivation), % and |\TRF@rhang| will hold the amount by which the rightmost derivation's % numerator overhangs its fraction bar to the right % (or |0pt| if the rightmost list item is not a derivation). % \begin{macrocode} \newdimen\TRF@lhang\TRF@lhang\z@ \newdimen\TRF@rhang\TRF@rhang\z@ % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TRF@xtrarhang} % While creating a derivation tree, |\TRF@xtrarhang| holds the amount by which % the current derivation rule's name extends beyond the |\TRF@rhang| of its % numerator. % \begin{macrocode} \newdimen\TRF@xtrarhang % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@lsave} % Because derivations are recursive structures, the various count and dimen % registers used in their construction must conform to some delicate scoping % rules. % Most are local, |\TRF@rhang| is global, but |\TRF@lhang| must be treated as % either local or global depending on where the derivation appears. % To accomplish this, we use |\TRF@lsave| as a local variable that saves the % current global |\TRF@lhang| value on entrance to the derivation code. % Upon exit, this value is either restored or not depending on whether % |\TRF@lhang| is being treated as local or global for this particular % derivation. % \begin{macrocode} \newdimen\TRF@lsave % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@linewd} % The following dimen register holds the width of the current derivation's % fraction bar. % \begin{macrocode} \newdimen\TRF@linewd % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@totalwd} % The following dimen register holds the overall width of the current % derivation. % That is, it is the sum of |\TRF@lhang|, |\TRF@linewd|, |\TRF@rhang|, and % |\TRF@xtrarhang|. % \begin{macrocode} \newdimen\TRF@totalwd % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@numwd} % \begin{macro}{\TRF@denomwd} % The following dimen registers hold the width of the current derivation's % numerator and denominator. % \begin{macrocode} \newdimen\TRF@numwd \newdimen\TRF@denomwd % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TRF@numbox} % \begin{macro}{\TRF@denombox} % \begin{macro}{\TRF@eqbox} % While constructing a derivation, the following three boxes hold the % derivation's numerator, denominator, and rule name, respectively. % \begin{macrocode} \newbox\TRF@numbox \newbox\TRF@denombox \newbox\TRF@eqbox % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\TRF@abovebar} % \begin{macro}{\TRF@belowbar} % The following two dimensions hold the computed distances of the numerator % above the barline and the denominator below the barline, respectively. % \begin{macrocode} \newdimen\TRF@abovebar \newdimen\TRF@belowbar % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\TRF@trfrac} % Here is the real meat of the code. % The following macro produces a single derivation rule in a derivation tree. % Its arguments are % (1)~the rule name (processed in horizontal mode), % (2)~the numerator (processed in math mode), and % (3)~the denominator (processed in math mode). % \begin{macrocode} \newcommand\TRF@trfrac[3]{\begingroup% \TRF@lastpenalty\the\lastpenalty% \TRF@lsave\TRF@lhang% \setbox\TRF@eqbox\hbox{\TRF@derivokfalse#1}% \ifdim\wd\TRF@eqbox>\z@% \setbox\TRF@eqbox\hbox{\kern\p@\unhbox\TRF@eqbox}% \fi% \TRF@lhang\z@% \advance\TRF@level\@ne% \setbox\TRF@numbox\hbox{\m@th$% \strut% \penalty\TRF@startp% #2% \ifnum\the\lastpenalty=\TRF@endp\else% \global\TRF@rhang\z@% \fi% $}% \advance\TRF@level\m@ne% \setbox\TRF@denombox\hbox{\m@th$% \strut% \TRF@derivokfalse% #3% $}% \TRF@numwd\wd\TRF@numbox% \TRF@denomwd\wd\TRF@denombox% \ifdim\TRF@numwd>\z@\else% \setbox\TRF@numbox\hbox{\vbox to0.5ex{\vfil}}% \fi% \ifdim\wd\TRF@numbox>\TRF@denomwd% \TRF@totalwd\wd\TRF@numbox% \else% \TRF@totalwd\TRF@denomwd% \fi% \TRF@linewd\wd\TRF@numbox% \advance\TRF@linewd-\TRF@lhang% \advance\TRF@linewd-\TRF@rhang% \ifdim\TRF@denomwd>\TRF@linewd% \advance\TRF@linewd-\TRF@denomwd% \advance\TRF@lhang0.5\TRF@linewd% \global\advance\TRF@rhang0.5\TRF@linewd% \ifdim\TRF@lhang<\z@\TRF@lhang\z@\fi% \ifdim\TRF@rhang<\z@\global\TRF@rhang\z@\fi% \TRF@linewd\TRF@denomwd% \fi% \ifdim\wd\TRF@eqbox>\TRF@rhang% \TRF@xtrarhang\wd\TRF@eqbox% \advance\TRF@xtrarhang-\TRF@rhang% \else% \TRF@xtrarhang\z@% \fi% \advance\TRF@totalwd\TRF@xtrarhang% \TRF@abovebar\fontdimen8\textfont\tw@% \advance\TRF@abovebar-\fontdimen22\textfont\tw@% \advance\TRF@abovebar-0.5\fontdimen8\textfont\thr@@% \advance\TRF@abovebar-\dp\TRF@numbox% \ifdim\TRF@abovebar<3\fontdimen8\textfont\thr@@% \TRF@abovebar3\fontdimen8\textfont\thr@@% \fi% \TRF@belowbar\fontdimen11\textfont\tw@% \advance\TRF@belowbar\fontdimen22\textfont\tw@% \advance\TRF@belowbar-0.5\fontdimen8\textfont\thr@@% \advance\TRF@belowbar-\ht\TRF@denombox% \ifdim\TRF@belowbar<3\fontdimen8\textfont\thr@@% \TRF@belowbar3\fontdimen8\textfont\thr@@% \fi% \mathinner{% \ifnum\TRF@level=0 % \raise\fontdimen22\textfont\tw@\vtop% \else% \vbox% \fi% {% \offinterlineskip% \hbox{\vbox{% \hb@xt@\TRF@totalwd{% \hfil% \unhbox\TRF@numbox% \hfil% \kern\TRF@xtrarhang% }% \kern\TRF@abovebar% \hb@xt@\TRF@totalwd{% \kern\TRF@lhang% \vrule\@width\TRF@linewd% \@height0.5\fontdimen8\textfont\thr@@% \@depth0.5\fontdimen8\textfont\thr@@% \TRF@squeeze{\TRF@eqbox}% \kern\TRF@rhang% \kern\TRF@xtrarhang% }% }}% \kern\TRF@belowbar% \hb@xt@\TRF@totalwd{% \kern\TRF@lhang% \hfil% \box\TRF@denombox% \hfil% \kern\TRF@rhang% \kern\TRF@xtrarhang% }% }% }% \ifnum\TRF@level>0 % \penalty\TRF@endp% \fi% \global\advance\TRF@rhang\TRF@xtrarhang% \ifdim\TRF@denomwd<\TRF@linewd% \advance\TRF@denomwd-\TRF@linewd% \advance\TRF@lhang-0.5\TRF@denomwd% \global\advance\TRF@rhang-0.5\TRF@denomwd% \fi% \ifnum\TRF@lastpenalty=\TRF@startp% \global\TRF@lhang\TRF@lhang% \else% \global\TRF@lhang\TRF@lsave% \fi% \endgroup} % \end{macrocode} % \end{macro} % % \begin{macro}{\trfrac} % The following is the entrypoint to the derivation code. % The |\trfrac| macro takes one optional argument which, if present, is the % name of the rule (processed in horizontal mode), % followed by two mandatory arguments---the rule's numerator and denominator. % Derivations can only appear in math mode, and cannot appear within the % denominator of another derivation or within its rule name. % \begin{macrocode} \newcommand\trfrac[3][]{% \ifTRF@derivok% \ifmmode% \TRF@trfrac{#1}{#2}{#3}% \else% \PackageError{trfrac}{\protect\trfrac\space% only allowed in math mode}% {I encountered a \protect\trfrac\space% macro without first encountering a begin-math token.}% \fi% \else% \PackageError{trfrac}{\protect\trfrac\space% not allowed in the consequent of another \protect\trfrac}% {\protect\trfrac\space can only appear in the premise (numerator% ) of another \protect\trfrac, not in the consequent (denominator% ) of a \protect\trfrac.}% \fi% } % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@next} % The |\TRF@next| token is here reserved so that it can be used in conjunction % with |\futurelet| (when processing optional arguments). % \begin{macrocode} \newcommand\TRF@next{} % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@sep} % In a |trgather| or |tralign| environment, the |\\| macro is used to delimit % lines. % It is temporarily set equal to |\TRF@sep| (below), which is just like |\cr| % in an |\halign| except that it takes an optional length argument that % has the effect of inserting a vertical space between the lines. % \begin{macrocode} \newcommand\TRF@sep{\futurelet\TRF@next\TRF@@sep} % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@@sep} % The following processes the optional argument to |\TRF@sep|. % \begin{macrocode} \newcommand\TRF@@sep{% \ifx[\TRF@next% \let\TRF@next\TRF@separg% \else% \let\TRF@next\TRF@sepnoarg% \fi% \TRF@next% } % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@separg} % The following is the code for a |\TRF@sep| that has been provided the % optional argument. % \begin{macrocode} \newcommand\TRF@separg{} \def\TRF@separg[#1]{\cr\noalign{\kern#1}} % \end{macrocode} % \end{macro} % % \begin{macro}{\TRF@sepnoarg} % The following is the code for a |\TRF@sep| that has not been provided the % optional argument. % You might think that it would have been simpler to use |\let| instead of % |\newcommand| in the line below, or even to just use |\cr| within some of % the code above instead of defining this new macro at all, % but |\cr| is a strange beast; it can only be expanded onto the token % stream when we're sure of everything that is to follow it. % \begin{macrocode} \newcommand\TRF@sepnoarg{\cr} % \end{macrocode} % \end{macro} % % \begin{environment}{trgather} % A |trgather| environment is just like |amsmath|'s |gather| environment except % that its baseline is at the bottom instead of in the middle. % Also, it can appear nested within other math environments, whereas |gather| % can only be used at the outermost level. % \begin{macrocode} \newenvironment{trgather}{% \vbox\bgroup% \let\\\TRF@sep% \ialign\bgroup\hfil{\m@th$##$}\hfil\cr% }{% \crcr\egroup\egroup% } % \end{macrocode} % \end{environment} % % \begin{environment}{tralign} % A |tralign| environment is like |amsmath|'s |aligned| environment except that % its baseline is at the bottom instead of in the middle, and it's restricted % to two columns (for simplicity). % \begin{macrocode} \newenvironment{tralign}{% \vbox\bgroup% \let\\\TRF@sep% \ialign\bgroup\hfil{\m@th$##\null$}&{\m@th$\null##$}\hfil\cr% }{% \crcr\egroup\egroup% } % \end{macrocode} % \end{environment} % % \Finale \endinput