[Tex/LaTex] latex3 complaining about Undefined control sequence. But it is defined!

expl3latex3

I've tried pairing this down, but each time I do that I'm either correcting my mistake or something. So here's a slightly unwieldy MWE.

In a nutshell, what I'm trying to do is….

I'm writing a quiz that has multiple version. I've got some clunky LaTeX code that already handles versioning, but I decided I could probably get cleaner looking document code if I tried writing something using LaTeX3.

Each quiz has a version attached to it. I'm writing a \choice macro that's given a ; separated list of possible output which will change based upon the version of the quiz.

For example if I write \choice{x;y;z;w} then on version A of the quiz \choice will provide x, on version B of the quiz \choice will provide y, etc.

I'm not anywhere near getting this up and running. I'm actually not interested in someone telling me how to achieve my ultimate goal: I think I'll learn a fair amount if I try it on my own. Also, I know I'm not following notational conventions quite correctly, but it's giving me a headache trying to balance notation (which I still find difficult to read) and mastering syntax (which I find slightly obscure, but beginning to get the hang of).

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
%-@-(1)---------------------------------------------------------------------
%% --- VERSIONING --- %%
%% store what the possible version are
\tl_new:N  \g__version_types
\tl_set:Nn \g__version_types { a;b;c;d }
\tl_show:N \g__version_types
%% make a sequence of the possible versions
\seq_new:N \g__all_possible_versions_seq
\seq_gset_split:Nnn \g__all_possible_versions_seq { ; } {\g__version_types}
\seq_show:N \g__all_possible_versions_seq
%% allow the user to define what the versions are
\NewDocumentCommand{\defineversions}{ O{;} m }{
    \tl_set:Nn \g__version_types { #2 }
    \seq_set_split:Nnn \g__all_possible_versions_seq { #1 } \g__version_types
}
%-@-(2)---------------------------------------------------------------------
%% --- GETTING/SETTING VERSIONS ---%%
\tl_new:N   \g__tl_current_doc_version 

\cs_new:Npn \mv_set_version:n #1 
    {
        \tl_set:Nn \g__tl_current_doc_version { #1 }
    }

\cs_new:Npn \mv_get_version 
    {
        \tl_use:N \g__tl_current_doc_version
    }

\newcommand{\setversion}[1]{\mv_set_version:n {#1}}
\newcommand{\getversion}{ \mv_get_version }

\cs_new:Npn \mv_test_version:n #1 {
    \str_if_eq:VnTF \g__tl_current_doc_version { #1 } { HELLO } { BYE}
}
\newcommand{\testversion}[1]{\mv_test_version:n {#1}}

%-@-(3)---------------------------------------------------------------------
%% --- CREATING THE USER INTERFACE --- %%
%% I'm going to destructive examine the sequence, so make 
%% a copy of it and work with copy
\seq_new:N     \g__copy_all_possible_versions_seq
\seq_set_eq:NN \g__copy_all_possible_versions_seq \g__all_possible_versions_seq
\tl_new:N      \g__current_possible_version_tl
%% Information that the user passes to us
\seq_new:N \g__user_defined_choice_seq
\tl_new:N  \g__current_possible_choice_tl

%% This "cs" assumes that the user choices have been translated
%% into a sequence
\cs_new:Npn \__test_current_choice_against_version:n #1 { 
    \seq_pop_left:NN \g__user_defined_choice_seq        
                     \g__current_possible_choice_tl

    \seq_pop_left:NN \g__copy_all_possible_versions_seq 
                     \g__current_possible_version_tl

    \tl_use:N        \g__current_possible_choice_tl --
    \tl_use:N        \g__current_possible_version_tl \par

    \str_if_eq:VVTF  \g__current_possible_choice_tl 
                     \g__current_possible_version_tl
                     { \tl_use:N \g__current_possible_choice_tl  }
                     { #1 }
}

\cs_new:Npn \mv_make_choice:n #1 {
    \__test_current_choice_against_version:n
        { \__test_current_choice_against_version:n 
            { \__test_current_choice_against_version:n 
                { FAIL }}}
}

\NewDocumentCommand{\choices}{ O{;} m }{
    \texttt{#2}\par
    \seq_gset_split:Nnn \g__user_defined_choice_seq  {#1}  {#2}
    \mv_make_choice:n {#1}
}

\ExplSyntaxOff
\begin{document}

Hello:  I'm setting the version \setversion{b}

I'm getting the version \textbf{\getversion}!

Choosing \choices{x;y;z;w}
\end{document}

I'm getting an error about an empty sequence. I've tried showing the sequence, and tokens used to create it, but nothing seems to be right.

Best Answer

I've tried to correct it, but I don't know if it does exactly what you want:

\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
%-@-(1)---------------------------------------------------------------------
%% --- VERSIONING --- %%
%% store what the possible version are
\tl_new:N  \g__version_types_tl
\tl_set:Nn \g__version_types_tl { a;b;c;d }
%% make a sequence of the possible versions
\seq_new:N \g__all_possible_versions_seq
\seq_new:N \g__copy_all_possible_versions_seq
\cs_generate_variant:Nn \seq_gset_split:Nnn { NnV }
\seq_gset_split:NnV \g__all_possible_versions_seq { ; } \g__version_types_tl
\seq_gset_eq:NN \g__copy_all_possible_versions_seq \g__all_possible_versions_seq
%% allow the user to define what the versions are
\NewDocumentCommand{\defineversions}{ O{;} m }
 {
  \tl_gset:Nn \g__version_types_tl { #2 }
  \seq_gset_split:NnV \g__all_possible_versions_seq { #1 } \g__version_types_tl
  \seq_gset_eq:NN \g__copy_all_possible_versions_seq \g__all_possible_versions_seq
 }

%-@-(2)---------------------------------------------------------------------
%% --- GETTING/SETTING VERSIONS ---%%

\tl_new:N   \g__current_doc_version_tl

\cs_new_protected:Npn \mv_set_version:n #1 
 {
  \tl_set:Nn \g__current_doc_version_tl { #1 }
 }

\cs_new:Npn \mv_get_version:
 {
  \tl_use:N \g__current_doc_version_tl
 }

\NewDocumentCommand{\setversion}{m}
 {
  \mv_set_version:n {#1}
 }
\NewDocumentCommand{\getversion} {}
 {
  \mv_get_version:
 }

\cs_new:Npn \mv_test_version:n #1
 {
  \tl_if_eq:VnTF \g__tl_current_doc_version { #1 } { HELLO } { BYE}
 }
\NewDocumentCommand{\testversion}{m}
 {
  \mv_test_version:n {#1}
 }

%-@-(3)---------------------------------------------------------------------
%% --- CREATING THE USER INTERFACE --- %%
%% I'm going to destructively examine the sequence, so make 
%% a copy of it and work with copy
\tl_new:N  \g__current_possible_version_tl
%% Information that the user passes to us
\seq_new:N \g__user_defined_choice_seq
\tl_new:N  \g__current_possible_choice_tl

%% This "cs" assumes that the user choices have been translated
%% into a sequence
\cs_new_protected:Npn \__test_current_choice_against_version: 
 {
  %I'm working 
  \seq_gpop_left:NN \g__user_defined_choice_seq        
                    \g__current_possible_choice_tl

  \seq_gpop_left:NN \g__copy_all_possible_versions_seq 
                    \g__current_possible_version_tl

  \tl_if_eq:NNTF    \g__current_possible_choice_tl 
                    \g__current_possible_version_tl
                    { \tl_use:N \g__current_possible_choice_tl  }
                    { FAIL }
 }

\cs_new:Npn \mv_make_choice:n #1
 {
  \__test_current_choice_against_version:
 }

\NewDocumentCommand{\choices}{ O{;} m }
 {
  \texttt{#2}\par
  \seq_gset_split:Nnn \g__user_defined_choice_seq  {#1}  {#2}
  \mv_make_choice:n {#1}
 }

\ExplSyntaxOff
\begin{document}

Hello:  I'm setting the version \setversion{b}

I'm getting the version \textbf{\getversion}!

Choosing \choices{x;y;z;w}
\end{document}

I fixed the names and some programming glitches. For instance you're comparing token lists with \str_if_eq:... but \tl_if_eq:... should be used. In particular \tl_if_eq:NNTF and not \str_if_eq:VVTF which does more work for nothing. It's quite obscure why you define \mv_make_choice:n with an argument that you don't use. Just use \__test_current_choice_against_version: as the final instruction in \choices.

Other points.

  1. When a variable is declared global, use only global assignments to it.
  2. Don't forget that all functions should have a colon in their name.
  3. Use \cs_new_protected:Npn when the function does unexpandable jobs (such as setting token lists or sequences).
Related Question