4

The following file gets ! TeX capacity exceeded, sorry [input stack size=5000]. If I remove the call to \tl_gput_right:Nn then it compiles successfully.

\documentclass{article}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{mathtools}
\usepackage{xparse} % loads expl3
%See interface3.pdf

\ExplSyntaxOn

\NewDocumentCommand{\uqual}{mm}
 {
   \int_compare:nTF { \tl_count:n { #1 } > 1 }
     {
       Extended \ parm \ #1 \
       \bool_gset_true:N \g_tmpa_bool
       \tl_gclear:N \g_tmpa_tl
       \tl_map_inline:nn{#1}
       {
         mapping \ ##1 \
         \if_bool:N \g_tmpa_bool
           {
             first \ item \ ##1 \
             \bool_gset_false:N \g_tmpa_bool
              \tl_gset_eq:NN \g_tmpa_tl ##1
           } \else: {
             next \ item \ ##1
             \tl_gput_right:Nn \g_tmpa_tl {xx ##1}
           } \fi:
       }
       test \ tokenlist=\g_tmpa_tl \
       \expandafter
         \left ( {\forall}_{ \g_tmpa_tl} \right ) #2
     }
     {
        single \ parm \ #1 \
       \expandafter
         \left ( {\forall}_{#1} \right ) #2
     }
 }

\ExplSyntaxOff

\begin{document}

$\uqual{{X}}{P(X.Y)}$

$\uqual{{X}{Y}}{P(X,Y)}$

\end{document}
4
  • you're using \ a lot – you probably want to use ~ instead. Sep 15, 2016 at 1:16
  • In Math mode ~ doesn't produce a space.
    – shmuel
    Sep 15, 2016 at 16:23
  • Didn't notice we were in math mode – it looks like your outputting text as well – shouldn't that be wrapped in \text or are those just debug statements? Sep 15, 2016 at 23:14
  • (At which point I like to use \msg_term:n) Sep 15, 2016 at 23:15

2 Answers 2

4

There is an error where you do \tl_gset_eq:NN \g_tmpa_tl ##1, because ##1 will generally not start with a control sequence variable and, even if it does, the result is not what you'd like to be.

Remember that N denotes an argument that should consist of a single token; in particular, \tl_gset_eq:NN makes the token list variable given as first argument globally equal to the token list variable given as second argument (no coercion, in case you're asking).

A braced argument is denoted in the function name with n. What you really want is

\tl_gset:Nn \g_tmpa_tl { ##1 }

(globally set \g_tmpa_tl to the given argument).

However, there are other parts to tidy up. For instance, you're using global settings and variables where you don't need to. Also,

\if_bool:N <boolean>
  <true text>
\else:
  <false text>
\fi:

is not the recommended coding; in any case, the true and false texts should not be braced (which is probably your reason for using global assignments); it's better to do

\bool_if:NTF <boolean>
 {
  <true text>
 }
 {
  <false text>
 }

The problem with _ is easily solved; since in expl3 syntax it is part of macro names, when you want to denote a math subscript, use \c_math_subscript_token.

However, there are easier ways to accomplish your task (which I guess is listing the variables in the first argument separated by commas):

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse} % loads expl3

\ExplSyntaxOn

\seq_new:N \l_shmuel_uqual_seq

\NewDocumentCommand{\uqual}{mm}
 {
  \seq_set_split:Nnn \l_shmuel_uqual_seq { } { #1 }
  ( \forall \c_math_subscript_token { \seq_use:Nn \l_shmuel_uqual_seq { , } } ) #2
 }

\ExplSyntaxOff

\begin{document}

$\uqual{X}{P(X.Y)}$

$\uqual{XY}{P(X,Y)}$

\end{document}

This means: split the first argument “at nothing” (which is the same division as done by \tl_map_inline:nn) into a sequence; then deliver the sequence with items separated by commas.

enter image description here

If you want to stack the variables given in the first argument, then change the macros like below:

\documentclass{article}
\usepackage{amsmath}
\usepackage{xparse} % loads expl3

\ExplSyntaxOn

\seq_new:N \l_shmuel_uqual_seq

\NewDocumentCommand{\uqual}{mm}
 {
  \seq_set_split:Nnn \l_shmuel_uqual_seq { } { #1 }
  ( 
  \forall \c_math_subscript_token
   {
    \substack{  \seq_use:Nn \l_shmuel_uqual_seq { \\ } } 
   }
  ) #2
 }

\ExplSyntaxOff

\begin{document}

$\uqual{X}{P(X.Y)}$

$\uqual{XY}{P(X,Y)}$

\end{document}

enter image description here

8
  • Sorry, I had a typo. It's the \tl_gput_right:Nn that is crashing and burning; I've edited the question to correct that. What I really want to do is to separate the items with \\, but that currently has other issues. I originally used a local Boolean, but it lost settings between iteration of the loop.
    – shmuel
    Sep 15, 2016 at 16:41
  • @shmuel As the code stands, the error is still present. Anyway, you can't directly use \\ to get stacked subscripts
    – egreg
    Sep 15, 2016 at 17:27
  • @shmuel I updated the solution
    – egreg
    Sep 15, 2016 at 20:30
  • @egreg Rather than \c_math_subscript_token better define \math_subscript:n { .. } or \math_sb:n { .. } or just use \sb, in my opinion.
    – Manuel
    Sep 15, 2016 at 20:47
  • Could you tell me where \c_math_subscript_token is defined/documented?
    – cfr
    Sep 16, 2016 at 22:31
4
\tl_gset_eq:NN 

expects two arguments of type N and not one of type N and one of type n.

What you want here is simply

\tl_gset:Nn \g_tmpa_tl {##1}

which works fine.

EDIT

The code works fine for me if I simply substitute the replacement above for the line I mentioned. This is not to say that other changes are not needed for the intended functionality (whatever that is) or that it might not be wise to do certain things differently, but it certainly does not fail to compile.

That is,

\documentclass{article}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{mathtools}
\usepackage{xparse} % loads expl3
%See interface3.pdf

\ExplSyntaxOn

\NewDocumentCommand{\uqual}{mm}
 {
   \int_compare:nTF { \tl_count:n { #1 } > 1 }
     {
       Extended \ parm \ #1 \
       \bool_gset_true:N \g_tmpa_bool
       \tl_gclear:N \g_tmpa_tl
       \tl_map_inline:nn{#1}
       {
         mapping \ ##1 \
         \if_bool:N \g_tmpa_bool
           {
             first \ item \ ##1 \
             \bool_gset_false:N \g_tmpa_bool
              \tl_gset:Nn \g_tmpa_tl {##1}
           } \else: {
             next \ item \ ##1
             \tl_gput_right:Nn \g_tmpa_tl {xx ##1}
           } \fi:
       }
       test \ tokenlist=\g_tmpa_tl \
       \expandafter
         \left ( {\forall}_{ \g_tmpa_tl} \right ) #2
     }
     {
        single \ parm \ #1 \
       \expandafter
         \left ( {\forall}_{#1} \right ) #2
     }
 }

\ExplSyntaxOff

\begin{document}

$\uqual{{X}}{P(X.Y)}$

$\uqual{{X}{Y}}{P(X,Y)}$

\end{document}

compiles without error. I don't know if the output is what you want, but it certainly produces a PDF.

output

4
  • Sorry, I had a typo. It's the \tl_gput_right:Nn that is crashing and burning.
    – shmuel
    Sep 15, 2016 at 16:28
  • @shmuel When I made this change in your code, it compiled, so I don't know why it would still crash for you. Is your TeX up to date?
    – cfr
    Sep 15, 2016 at 17:37
  • I'm using MiKTeX 2.9, which should have recent copies of everything; This is pdfTeX, Version 3.14159265-2.6-1.40.17 (MiKTeX 2.9) (preloaded format=pdflatex 2016.7.31) 16 SEP 2016 09:09. Are there any diagnostics that would help? Could you show the code that compiled correctly? N.B. \tl_gset_eq:NN \g_tmpa_tl ##1 works just fine; It seems to recognize that #1 is a name. Whether it is guarantied to work in future releases I don't know.
    – shmuel
    Sep 16, 2016 at 20:30
  • @shmuel Please see edit. I literally just replace that line from your code with the substitute line from my answer and it worked. As I said - and as egreg explained in detail - your use of \tl_gset_eq:NN is incorrect.
    – cfr
    Sep 16, 2016 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.