5

Sorry for the very open question title, but I can't really figure out what is wrong exactly. I wanted to save a little time when writing semantic types, which are usually subscript but are often recursive, leading to types within types, like this:

D<e,<s,t>>

The easiest solution seemed to me to use a boolean which checks whether I am within Type Brackets (<>) already; if so, \type would not use \textsubscript, if not, \type would set the boolean to true and use \textsubscript; the last command in \type would set the boolean to false if it had been false when the command was called. This is a minimal example:

\documentclass{article}
\usepackage{etoolbox}

\newbool{intype}
\newcommand{\type}[1]{\ifbool{intype}{$\langle$#1$\rangle$}{\setbool{intype}{true}\textsubscript{$\langle$#1$\rangle$}}\setbool{intype}{false}}

\begin{document}
D\type{\type{$\tau$,\type{$s,t$}},\type{$\tau$,\type{$s$,$t$}}}
\end{document}

The expected output is D<<τ,<s,t>>,<τ,<s,t>>.

The output I get is D<<τ,<s,t>>,<τ,<s,t>>.

This is really confusing - If my solution doesn't work, why isn't the <s,t> bit in the first pair of brackets lower than the τ?

Sorry for that long line of code btw, as far as I can tell, adding spaces or line breaks produces unwanted spaces in the output.

A Feldman
  • 3,930
sgf
  • 561

2 Answers2

7

You are setting it false too soon, but you can just use the grouping to set it back automatically:

enter image description here

\documentclass{article}
\usepackage{etoolbox}

\newbool{intype}
\newcommand{\type}[1]{%
  \ifbool{intype}%
  {$\langle$#1$\rangle$}%
  {\textsubscript{\setbool{intype}{true}$\langle$#1$\rangle$}}%
  }

\begin{document}
D\type{\type{$\tau$,\type{$s,t$}},\type{$\tau$,\type{$s$,$t$}}}
\end{document}
David Carlisle
  • 757,742
  • Not ownly does that work, but you managed to split up the macro without creating any spaces. Is that on account of the %s? Also, *why* does it work? I don't see you ever setting the boolean back to false. And I thought I was setting it to false right at the end of the macro, so how can it have been too early? (This is not meant to critizise your answer, it is exactly what I needed, so feel free to ignore these questions.) – sgf Jul 08 '16 at 12:15
  • yes an end of line is a space but if you comment it out, it isn't there:-) setbool is a local setting so the value reverts to what it was at the end of the subscript just like the font {\bfseries xxx} yyy reverting back from bold at the } you don't need to explicitly set it back. In your code you had the setting to false after the ifbool test so you were always setting it to false even if it was true at the start of the macro. so it would also have worked to have moved one the } here }}\setbool to the end, but using grouping is more the tex way. – David Carlisle Jul 08 '16 at 12:19
  • I checked that thrice :( Now I see it, there's a } too many after the langlerangle. Thank you! – sgf Jul 08 '16 at 12:25
5

The boolean is set to false in the wrong place.

Here's a different implementation, based on grouping, that avoids code repetition. Since \textsubscript typesets its argument in a group, the “outer” definition of \type will be restored as soon as the subscript has been typeset.

\documentclass{article}

\newcommand{\type}[1]{%
  \textsubscript{\let\type\innertype\innertype{#1}}%
}
\newcommand{\innertype}[1]{$\langle$#1$\rangle$}

\begin{document}
D\type{\type{$\tau$,\type{$s,t$}},\type{$\tau$,\type{$s$,$t$}}}
\end{document}

image

egreg
  • 1,121,712
  • This is pretty sweet. I always thought the \let command was particularly useless. I seem to have been particularly wrong. – sgf Jul 09 '16 at 20:28
  • @thisismynamenow It takes some time (and coding) to appreciate the power of \let. – egreg Jul 09 '16 at 20:33