11

I'm trying to build a macro that processes a comma-separated-list of elements so that:

\MapAndUse{a,b,c}

would produce:

expected

My first intuition is to use a expl3 combination of \seq_map* to process each element in turn (here, wrap into parentheses) then \seq_use* to organize them around -- markers.

But this does not work as expected:

\documentclass{standalone}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\MapAndUse}{ m }{%
    \seq_set_from_clist:Nn \l_raw_seq {#1}
    \seq_map_variable:NNn \l_raw_seq \i {(\i)}
    % \seq_show:N \l_raw_seq
    \seq_use:Nn \l_raw_seq {\ --\ }
}

\ExplSyntaxOff

\begin{document}

\MapAndUse{a,b,c}

\end{document}

Since it produces:

unexpected

From what I understand:

  • from the doc: \seq_map_* macros directly expand to the input stream.
  • from \seq_show:N \l_raw_seq: the sequence is not actually affected by the\seq_map command (elements are not parenthesized)
The sequence \l_raw_seq contains the items (without outer braces):
>  {a}
>  {b}
>  {c}.

How do I process each element "in place" with \seq_map* without having them pushed to the input stream?

Naive tries:

  • \seq_set_from_clist:Nx \l_processed_seq {\seq_map_variable:NNn \l_raw_seq \i {,(\i)}}: does not compile in consistence with the doc: this Nx variant does not exist, and \seq_map* cannot be expanded this way into another "variable".
  • \Use{\Map{a,b,c}} with a 2-stages processing: does not work as expected since \Map{a,b,c} remains unexpanded.

Is there anything I've missed about expl3 logic there?
Is it possible to process my comma-separated input this way?
Are there alternatives or workarounds?

10

You can use two sequences; first apply the mapping to get the “adorned” items, then use them.

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \l__iagolito_in_seq
\seq_new:N \l__iagolito_out_seq

\NewDocumentCommand{\MapAndUse}{ m }
 {
  \seq_set_from_clist:Nn \l__iagolito_in_seq { #1 }
  \seq_set_map:NNn \l__iagolito_out_seq \l__iagolito_in_seq { (\exp_not:n { ##1 }) }
  \seq_use:Nn \l__iagolito_out_seq {~--~}
}

\ExplSyntaxOff

\begin{document}

\MapAndUse{a,b,c}

\end{document}

An extended version where you can specify how to adorn the items and what to use between them:

\documentclass{article}

\usepackage{expl3}
\usepackage{xparse}

\ExplSyntaxOn

\seq_new:N \l__iagolito_in_seq
\seq_new:N \l__iagolito_out_seq

\NewDocumentCommand{\MapAndUse}{ mmm }
 {
  \cs_set_protected:Nn \__iagolito_mapanduse:n { #2 }
  \seq_set_from_clist:Nn \l__iagolito_in_seq { #1 }
  \seq_set_map:NNn \l__iagolito_out_seq \l__iagolito_in_seq
   {
    \__iagolito_mapanduse:n { \exp_not:n { ##1 } }
   }
  \seq_use:Nn \l__iagolito_out_seq { #3 }
}

\ExplSyntaxOff

\begin{document}

\MapAndUse{a,b,c}{(#1)}{ -- }

\end{document}

enter image description here

  • 2
    Awesome, cheers :) I was missing \seq_set_map and \exp_not. It turns out the second one was actually the one I was trying to build :) – iago-lito Feb 16 at 12:21
  • \MapAndUse does not work within \caption in a figure environment, what could be wrong? The compiler spits ! Illegal parameter number in definition of \reserved@a. <to be read again> I can work around this bug using \savebox. – iago-lito Feb 18 at 9:17
  • 1
    @iago-lito The generic \MapAndUse should be employed for defining semantic macros rather than explicitly. Do \NewDocumentCommand{\parendash}{m}{\MapAndUse{#1}{(##1)}{ -- }} and use \parendash{a,b,c}. – egreg Feb 18 at 9:27
  • This is what I actually did but the error was spat by the very semantic macro. My mistake was to define the semantic macro with \newcommand instead of \NewDocumentCommand.. so your version does work :) – iago-lito Feb 18 at 9:37
  • 1
    @iago-lito Always remember that the argument to \caption is a moving argument and that fragile commands need to be protected or made robust at the outset (which \NewDocumentCommand does). – egreg Feb 18 at 9:46

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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