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}
  • you're using \ a lot – you probably want to use ~ instead. – Sean Allred Sep 15 '16 at 1:16
  • In Math mode ~ doesn't produce a space. – shmuel Sep 15 '16 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? – Sean Allred Sep 15 '16 at 23:14
  • (At which point I like to use \msg_term:n) – Sean Allred Sep 15 '16 at 23:15
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

  • 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 '16 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 '16 at 17:27
  • @shmuel I updated the solution – egreg Sep 15 '16 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 '16 at 20:47
  • Could you tell me where \c_math_subscript_token is defined/documented? – cfr Sep 16 '16 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

  • Sorry, I had a typo. It's the \tl_gput_right:Nn that is crashing and burning. – shmuel Sep 15 '16 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 '16 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 '16 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 '16 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.