2

The LaTeX3 documentation for the l3basics package lists three functions

\use_none_delimit_by_q_nil:w            ... \q_nil
\use_none_delimit_by_q_stop:w           ... \q_stop
\use_none_delimit_by_q_recursion_stop:w ... \q_recursion_stop

with delimited arguments, which all remove the ... part from the input stream. Another three :nw variants are defined that remove the ... part but put their first argument back into the input stream.

I'm wondering what these functions are supposed to be used for. Reading arguments delimited by a stop marker is quite useful sometimes when the starting command and the final marker have to be split across two different places in the code.

However, there are three such function here with names that indicate these function are supposed to be used in special circumstances. They are also removing their collected tokens from the input, which seems quite strange for a recursive function; collecting tokens to return them as final result would seem more useful to me.

So what is the intended use for these functions?

  • 2
    When you say, e.g. \map_break:, to remain expandable you can't set a variable to signal the loop's end, so instead you have to “gobble” everything until the end, which is what these macros do. – Henri Menke May 25 at 21:19
3

They are intended for exactly the purpose you anticipate: removing up to a given token. However, as the token has to match exactly the end of the use case. We need multiple markers which are be unique, particularly for expandable loops (which use \q_recursion_stop). Depending on the exactly set up, there may be nested tokens or it may be that for other reasons one or the other is preferable. As such, we have a small set based around 'common' end markers.

Whilst we (the team) have some more complex constructs for core loops, the 'generic loop' code illustrates the use of delimited ending well. For example, imagine we want to loop over some input data structure in groups of three tokens. We might set this up as

\input expl3-generic %
\ExplSyntaxOn

\cs_new:Npn \siracusa_loop:n #1
  {
    \__siracusa_loop:NNN
      #1
      \q_recursion_tail \q_recursion_tail \q_recursion_tail
      \q_recursion_stop
  }
\cs_new:Npn \__siracusa_loop:NNN  #1#2#3
  {
    \quark_if_recursion_tail_stop:n {#3}
    \quark_if_recursion_tail_stop:n {#2}
    \quark_if_recursion_tail_stop:n {#1}
    \tl_show:n { First ~"#1";~Second:~"#2";~Third~"#3" }
    \__siracusa_loop:NNN
  }
\siracusa_loop:n { ABC }

\siracusa_loop:n { ABC 123 }

\siracusa_loop:n { ABC D }
\siracusa_loop:n { ABC DE }

\tex_end:D

Here, the 'clean up' is hidden inside \quark_if_recursion_tail_stop:n, which needs \use_none_delimit_by_q_recursion_stop:w. Very rarely, one may need to do that manually: typically for cases where complex shuffling is required.

  • Sorry, I've just recently started learning LaTeX3. I read about the \*_map_break: commands as mentioned by Henri Menke, but still can't see the relation to the delimited functions from my question. For example, \prg_map_break:Nn seems to use \prg_break_point:Nn as recursion terminator. Could you perhaps add a really simple example to your answer that shows how those \use_none_delimit_* functions come into play in conjunction with the loop functions? – siracusa May 26 at 15:39
0

Based on Joseph Wright's very useful answer I think I now understand the idea behind this kind of functions. I played a bit with it and came up with an example in which the set of similar \use_i_delimit_by_* functions can be used:

\input expl3-generic %
\ExplSyntaxOn

\cs_new:Npn \siracusa_loop:n #1
  {
    \__siracusa_loop:NNN
      #1
      \q_recursion_tail \q_recursion_tail \q_recursion_tail
      \q_recursion_stop
  }

\cs_new:Npn \__siracusa_loop:NNN  #1#2#3
  {
    \siracusa_check_for_rest:Nn {#1} { }
    \siracusa_check_for_rest:Nn {#2} { \tl_show:n { Rest ~"#1" } }
    \siracusa_check_for_rest:Nn {#3} { \tl_show:n { Rest ~"#1#2" } }
    \tl_show:n { First ~"#1";~Second:~"#2";~Third~"#3" }
    \__siracusa_loop:NNN
  }

\cs_new:Npn \siracusa_check_for_rest:Nn #1#2
  {
    \tl_if_empty:oT { \__quark_if_recursion_tail:w {} #1 {} ?! \q_recursion_tail ??! }
        {\use_i_delimit_by_q_recursion_stop:nw { #2 } }
  }

\siracusa_loop:n { ABC }

\siracusa_loop:n { ABC 123 }

\siracusa_loop:n { ABC D }
\siracusa_loop:n { ABC DE }

\tex_end:D

The definition of \siracusa_check_for_rest:Nn is based on the \quark_if_recursion_tail_stop:n definition, just with the usage of \use_i_delimit_by_q_recursion_stop:nw instead of \use_none_delimit_by_q_recursion_stop:w. (Who on earth came up with those names? ;))

We now also get the remaining input tokens in the output:

First "A"; Second: "B"; Third "C"

First "A"; Second: "B"; Third "C"
First "1"; Second: "2"; Third "3"

First "A"; Second: "B"; Third "C"
Rest "D"

First "A"; Second: "B"; Third "C"
Rest "DE"

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.