mdwmath.dtx: Introduce machinery for defining bracketty notation.
authorMark Wooding <mdw@distorted.org.uk>
Tue, 9 Aug 2022 17:18:02 +0000 (18:18 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Tue, 9 Aug 2022 17:22:13 +0000 (18:22 +0100)
mdwmath.dtx

index 2f93b1b..5635a0d 100644 (file)
@@ -27,7 +27,7 @@
 %<+package>                [2020/09/06 1.14.0 Nice mathematical things]
 % \end{meta-comment}
 %
-% \CheckSum{727}
+% \CheckSum{980}
 %% \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
 %
 % The old |\big| commands have been redefined in terms of |\bbigg|.
 %
+% \subsection{Defining bracketty notations}
+%
+% \DescribeMacro\defbrk
+% Many mathematical notations involve wrapping brackets of various kinds
+% around expressions.  \LaTeX\ doesn't provide much help in defining commands
+% for these notations, which is a shame because it's a good idea to keep the
+% markup semantic rather than visual.  I hereby present the |\defbrk|
+% command:
+% \begin{quote}
+% \syntax{"\\defbrk{"<command>"}["<louter>"]{"<lbrk>"}["<linner>"]"^^A
+%                              "["<rinner>"]{"<rbrk>"}["<router>"]"}
+% \end{quote}
+% The syntax looks intimidating, but it's quite easy really.  The \<command>
+% should be a command name, with a leading |\|.  The \<lbrk> and \<rbrk>
+% arguments, which are the only other mandatory arguments, are the brackets;
+% they should be something that can appear after |\left| and |\right|.  The
+% optional arguments are just extra stuff, commonly spacing, which can appear
+% around the brackets.
+%
+% The main command |\|\<foo> is invoked as
+% \syntax{"\\"<foo>"["<left>"]["<right>"]{"<filling>"}"}.  Slightly
+% unusually, the optional \<left> and \<right> arguments must be either both
+% missing or both provided.  They're the sizes to be applied to the brackets,
+% so they can be something like |\biggl| and |\biggr|, or |\left| and
+% |\right|; they default to empty, so you get the ordinary text-sized
+% brackets if you don't do anything special.  The \<filling> is just the
+% stuff to go in-between the brackets.
+%
+% You also get a number of extra commands:
+% \begin{itemize}
+% \item |\auto|\<foo> uses automatically-resizing brackets, as if you'd asked
+%   for |\left| and |\right|;
+% \item |\big|\<foo>, |\Big|\<foo>, |\bigg|\<foo>, and |\Bigg|\<foo> use the
+%   corresponding standard sizes of brackets; and
+% \item \syntax{"\\bbigg"<foo>"["$a$"]{"$n$"}"} uses the `bbigg' machinery
+%   described above for custom bracket sizes.
+% \end{itemize}
+%
+% \begin{figure}
+% \begin{demo}{Custom bracket notation}
+%\defbrk\set{\{}{\}}
+%\defbrk\floor{\lfloor}{\rfloor}
+%
+%Let $S = \set{1, 2, 3}$.
+%
+%Let
+%\[ \mu = \biggfloor{\frac{B^{2n}}{m}}
+%   \mpunct. \]
+%Show that $\bigfloor{\floor{a/b}/c} =
+%\floor{a/b c}$.
+% \end{demo}
+% \end{figure}
+%
+% But wait!  There's more!  Some notation comes in two pieces with a
+% separator in the middle.  For these, there's an even more complicated |*|
+% version of |\defbrk|:
+% \begin{quote}
+% \syntax{"\\defbrk*{"<command>"}["<louter>"]{"<lbrk>"}["<linner>"]"^^A
+%                               "["<mbefore>"]{"<mid>"}["<mafter>"]"^^A
+%                               "["<rinner>"]{"<rbrk>"}["<router>"]"}
+% \end{quote}
+% This defines \<command> as before, but now it takes two arguments, to be
+% surrounded by the \<lbrk> and \<rbrk> brackets and separated by \<mid>.
+%
+% \begin{figure}
+% \begin{demo}{More custom bracket notation}
+%\defbrk*\setcomp{\{}[\,]\vert[][\,]{\}}
+%
+%Consider the coset $x + H =
+%\setcomp{x + h}{h \in H}$.
+% \end{demo}
+% \end{figure}
+%
 % \subsection{The `QED' symbol}
 %
 % \DescribeMacro\qed
 % \end{macro}
 % \end{macro}
 %
+% \subsection{Bracketty notation}
+%
+% This is mostly an exercise in keeping track of data structures.  Which is a
+% problem, because \TeX\ isn't really very good at data structures.  Our main
+% trick is Church-encoded tuples; i.e., we represent a collection of things
+% as a higher-order function which applies a given projection to the tuple.
+%
+% \begin{macro}{\brk@delim}
+% \begin{macro}{\brk@plain}
+% \begin{macro}{\brk@size}
+% A delimiter keeps track of a before-string, a plain-text delimiter, a sized
+% delimiter, and an after-string.  Rather than just projecting components, we
+% we want to typeset the things, so we provide two macros for doing this: one
+% typesets the plain version (possibly with a prefix), and the other applies
+% a size to the sized delimiter.
+%    \begin{macrocode}
+\def\brk@delim#1#2#3#4#5{#5{#1}{#2}{#3}{#4}}
+\def\brk@plain#1#2#3#4#5{#2#1#3#5}
+\def\brk@size#1#2#3#4#5{#2#1#4#5}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\brk@bbigg}
+% Before we get really stuck in, here's a quick macro to collect a |\bbigg|
+% argument and pass it to its continuation.
+%    \begin{macrocode}
+\def\brk@bbigg#1{\@testopt{\brk@bbigg@{#1}}\z@}
+\def\brk@bbigg@#1[#2]#3{#1{#2}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\brk@lefttwo}
+% \begin{macro}{\brk@righttwo}
+% We now begin the two-delimiter machinery proper.  The macro |\defbrk| will
+% package up the delimiters in a macro.  The following two projections pick
+% out the left and right delimiters and apply them to their argument.
+%    \begin{macrocode}
+\def\brk@lefttwo#1#2#3{#2{#1}}
+\def\brk@righttwo#1#2#3{#3{#1}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\brk@plaintwo}
+% \begin{macro}{\brk@sizetwo}
+% The next stage is to typeset a full delimited expression, which is what we
+% do here.
+%    \begin{macrocode}
+\def\brk@plaintwo#1#2%
+  {#1{\brk@lefttwo{\brk@plain{}}}#2#1{\brk@righttwo{\brk@plain{}}}}
+\def\brk@sizetwo#1#2#3#4%
+  {#3{\brk@lefttwo{\brk@size{#1}}}#4#3{\brk@righttwo{\brk@size{#2}}}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\brk@maintwo}
+% \begin{macro}{\brk@bigtwo}
+% \begin{macro}{\brk@Bigtwo}
+% \begin{macro}{\brk@biggtwo}
+% \begin{macro}{\brk@Biggtwo}
+% \begin{macro}{\brk@bbiggtwo}
+% \begin{macro}{\brk@auto}
+% And finally, the top-level handlers for two-delimiter bracket-notation
+% macros.
+%    \begin{macrocode}
+\def\brk@maintwo#1{\@ifnextchar[{\brk@maintwo@size#1}{\brk@plaintwo#1}}
+\def\brk@maintwo@size#1[#2][#3]{\brk@sizetwo{#2}{#3}#1}
+\def\brk@bigtwo{\brk@sizetwo\bigl\bigr}
+\def\brk@Bigtwo{\brk@sizetwo\Bigl\Bigr}
+\def\brk@biggtwo{\brk@sizetwo\biggl\biggr}
+\def\brk@Biggtwo{\brk@sizetwo\Biggl\Biggr}
+\def\brk@bbiggtwo#1{\brk@bbigg{\brk@bbiggtwo@#1}}
+\def\brk@bbiggtwo@#1#2{\brk@sizetwo{\bbiggl#1{#2}}{\bbiggr#1{#2}}}
+\def\brk@auto{\brk@sizetwo\left\right}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\brk@leftthree}
+% \begin{macro}{\brk@midthree}
+% \begin{macro}{\brk@rightthree}
+% \begin{macro}{\brk@plainthree}
+% \begin{macro}{\brk@sizethree}
+% Next, the three-delimiter projections.
+%    \begin{macrocode}
+\def\brk@leftthree#1#2#3#4{#2{#1}}
+\def\brk@midthree#1#2#3#4{#3{#1}}
+\def\brk@rightthree#1#2#3#4{#4{#1}}
+\def\brk@plainthree#1#2#3{%
+  #1{\brk@leftthree{\brk@plain{}}}#2%
+  #1{\brk@midthree{\brk@plain\mathrel}}#3%
+  #1{\brk@rightthree{\brk@plain{}}}%
+}
+\def\brk@sizethree#1#2#3#4#5#6{%
+  #4{\brk@leftthree{\brk@size{#1}}}#5%
+  #4{\brk@midthree{\brk@size{#2}}}#6%
+  #4{\brk@rightthree{\brk@size{#3}}}%
+}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\brk@mainthree}
+% \begin{macro}{\brk@bigthree}
+% \begin{macro}{\brk@Bigthree}
+% \begin{macro}{\brk@biggthree}
+% \begin{macro}{\brk@Biggthree}
+% \begin{macro}{\brk@bbiggthree}
+% And finally, the top-level handlers for three-delimiter bracket-notation
+% macros.
+%    \begin{macrocode}
+\def\brk@mainthree#1{\@ifnextchar[{\brk@mainthree@size#1}{\brk@plainthree#1}}
+\def\brk@mainthree@size#1[#2][#3][#4]{\brk@sizethree{#2}{#3}{#4}#1}
+\def\brk@bigthree{\brk@sizethree\bigl\bigm\bigr}
+\def\brk@Bigthree{\brk@sizethree\Bigl\Bigm\Bigr}
+\def\brk@biggthree{\brk@sizethree\biggl\biggm\biggr}
+\def\brk@Biggthree{\brk@sizethree\Biggl\Biggm\Biggr}
+\def\brk@bbiggthree#1{\brk@bbigg{\brk@bbiggtree@#1}}
+\def\brk@bbiggthree@#1#2%
+  {\brk@sizethree{\bbiggl#1{#2}}{\bbiggm#1{#2}}{\bbiggr#1{#2}}}
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@csname}
+% A brief change of pace: \syntax{"\\@csname{"<cont>"}{"<command>"}"} calls
+% \<cont> with the name of the control sequence \<command>, suitable for
+% inlcuding as part of |\csname|\ldots|\endcsname|.  I use |\string|, and
+% then there's a dance to remove the backslash from the beginning and the
+% space from the end.
+%    \begin{macrocode}
+\def\@csname#1#2{\expandafter\@csname@\string#2 \relax#1}
+\begingroup \lccode`\|=`\\
+  \lowercase{\endgroup \def\@csname@|#1 \relax#2{#2{#1}}}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\defbrk}
+% There's nothing to do now but to define |\defbrk| itself.  This is mostly a
+% tedious exercise in collecting the arguments.
+%    \begin{macrocode}
+\def\defbrk@delim#1{\@testopt{\defbrk@delim@i{#1}}{}}
+\def\defbrk@delim@i#1[#2]#3{%
+  \def\@tempa{#3}%
+  \ifx\@tempa\@empty \expandafter\@firstoftwo
+  \else \expandafter\@secondoftwo \fi
+    {\@testopt{\defbrk@delim@ii{#1}{#2}{}{.}}{}}%
+    {\@testopt{\defbrk@delim@ii{#1}{#2}{#3}{#3}}{}}%
+}
+\def\defbrk@delim@ii#1#2#3#4[#5]{#1{\brk@delim{#2}{#3}{#4}{#5}}}
+\def\defbrk{\@ifstar\defbrk@three\defbrk@two}
+\def\defbrk@two#1{\defbrk@delim{\defbrk@two@i{#1}}}
+\def\defbrk@two@i#1#2{\defbrk@delim{\defbrk@two@ii{#1}{#2}}}
+\def\defbrk@two@ii{\@csname\defbrk@two@iii}
+\def\defbrk@two@iii#1#2#3{%
+  \@namedef{(#1)}##1{##1{#2}{#3}}%
+  \expandafter\defbrk@two@iv\csname(#1)\endcsname{#1}%
+}
+\def\defbrk@two@iv#1#2{%
+  \@namedef{#2}{\brk@maintwo#1}%
+  \@namedef{big#2}{\brk@bigtwo#1}%
+  \@namedef{Big#2}{\brk@Bigtwo#1}%
+  \@namedef{bigg#2}{\brk@biggtwo#1}%
+  \@namedef{Bigg#2}{\brk@Biggtwo#1}%
+  \@namedef{bbigg#2}{\brk@bbiggtwo#1}%
+  \@namedef{auto#2}{\brk@auto#1}%
+}
+\def\defbrk@three#1{\defbrk@delim{\defbrk@three@i{#1}}}
+\def\defbrk@three@i#1#2{\defbrk@delim{\defbrk@three@ii{#1}{#2}}}
+\def\defbrk@three@ii#1#2#3{\defbrk@delim{\defbrk@three@iii{#1}{#2}{#3}}}
+\def\defbrk@three@iii{\@csname\defbrk@three@iv}
+\def\defbrk@three@iv#1#2#3#4{%
+  \@namedef{(#1)}##1{##1{#2}{#3}{#4}}%
+  \expandafter\defbrk@three@v\csname(#1)\endcsname{#1}%
+}
+\def\defbrk@three@v#1#2{%
+  \@namedef{#2}{\brk@mainthree#1}%
+  \@namedef{big#2}{\brk@bigthree#1}%
+  \@namedef{Big#2}{\brk@Bigthree#1}%
+  \@namedef{bigg#2}{\brk@biggthree#1}%
+  \@namedef{Bigg#2}{\brk@Biggthree#1}%
+  \@namedef{bbigg#2}{\brk@bbiggthree#1}%
+}
+%    \end{macrocode}
+% \end{macro}
+%
 % \subsection{The `QED' symbol}
 %
 % \begin{macro}{\qed}