1

Can someone show me how to make the following macro (\applyeach) expandable using expl3, if it is possible?

\documentclass{article}

\newcounter{applyeachposition} \newcommand\applyeachmacro{}

% #1 : macro to apply % #2 : multi-args \newcommand\applyeach[2]{ \setcounter{applyeachposition}{0} \renewcommand\applyeachmacro{#1} \applyeachrecu#2|\nil \renewcommand\applyeachmacro{} }

\def\applyeachrecu#1|#2\nil{ \stepcounter{applyeachposition} \applyeachmacro{#1} \if\relax\detokenize{#2}\relax\else \applyeachrecu#2\nil \fi }

\newcommand\decoone[1]{% [(\textbf{#1})] \quad% }

\newcommand\multiapply[1]{% \applyeach{\decoone}{#1} }

\begin{document}

\multiapply{1|12|123|1234}

\end{document}

projetmbc
  • 13,315
  • You need the counter? – Phelype Oleinik Aug 06 '20 at 14:50
  • The counter is used for extra traitment (typically to do special stuf with the first argument). – projetmbc Aug 06 '20 at 14:51
  • What's the expected output? And what's the purpose of the counter? Sorry, but one cannot answer without knowing what you expect and why you add some seemingly unneeded details. Anyway, you cannot have something expandable if you need to set counters. – egreg Aug 06 '20 at 14:54
  • @egreg I use this macro to decorate trees by applying a graphical macro to the parts : doc here (https://github.com/typensee-latex/tnsproba/blob/master/tnsproba/tnsproba-doc%5Bfr%5D.pdf : see section 6) and related codes here (https://github.com/typensee-latex/tnsproba/blob/master/factory/02-tree/01-tree.sty at the end) and here (https://github.com/typensee-latex/tnscom/blob/master/factory/07-metaprog/02-multi-args.sty). The name of the macros are different. – projetmbc Aug 06 '20 at 15:00
  • This seems a typical XY question. You've never explained why you want to use | as a delimiter, nor what the output 1|12|123|1234 is used for. Now we discover that it's probably an intermediate step. Please, avoid piling up questions and disclose *what* you're trying to do. – egreg Aug 06 '20 at 18:13
  • @egreg You're right. I will try to be more specific in the future. – projetmbc Aug 06 '20 at 20:56
  • @egreg I use the pipe | for macros proposing an unknown numbers of semantic arguments. For example, I have a macro \coord for coordinates and I just type \coord{x_1} for 1D-space, \coord{x_1 | x_2} for 2D-space \coord{x_1 | x_2 | x_3} for 3D-space and so on... – projetmbc Aug 08 '20 at 17:57
  • Without the requirement of being expandable tokcycle works quite well, among other options -- see macros - How to iterate through a token list to make characters uppercase, while preserving spaces? - TeX - LaTeX Stack Exchange – user202729 Nov 09 '21 at 10:46

1 Answers1

2

Without the ability to change the delimiter, the definition is pretty straightforward. Though note that, as egreg says, setting a counter is an assignment, and assignments are not expandable, so you can't use them. You have to increase a number “on the fly” and pass that to the macro, but not as a counter.

The macro itself splits the argument at a | and applies a given function to that, until the end of the loop is reached. Adding a \prg_do_nothing: (and removing it later) takes care of braced items and spaces around the argument. If you need to change the delimiter then the code will get more complicated.

I defined \multiapply<cmd>{<list>} such that it iterates on the |-separated <list> and applies <cmd> to each item. The <cmd> needs to take two arguments: #1 is the number of the item in the list, and #2 is the item itself.

enter image description here

\documentclass{article}

\ExplSyntaxOn \NewExpandableDocumentCommand \multiapply { m +m } { \mbc_multiapply:Nn #1 {#2} } \cs_new:Npn \mbc_multiapply:Nn #1 #2 { __mbc_multiapply:nNw { 0 } #1 | \prg_do_nothing: #2 | \q_recursion_tail | \q_recursion_stop } \cs_new:Npn __mbc_multiapply:nNw #1 #2 | #3 | { \exp_args:Nof __mbc_multiapply:nnN {#3} { \int_eval:n {#1+1} } #2 } \cs_new:Npn __mbc_multiapply:nnN #1 #2 #3 { \quark_if_recursion_tail_stop:n {#1} \exp_not:e { \exp_not:N #3 {#2} { \tl_trim_spaces:n {#1} } } __mbc_multiapply:nNw {#2} #3 | \prg_do_nothing: } \ExplSyntaxOff

\newcommand\decoone[2]{% Item #1: [(\textbf{#2})]\quad}

\begin{document} \multiapply\decoone{ 1 | 12 | 123 | 1234 } \end{document}

  • This makes me think that I really need to work with expl3 in some cases like the one in this post. Thanks a lot. I will study this answer seriously and the other answers you give to me. – projetmbc Aug 06 '20 at 15:14
  • @projetmbc Glad you liked it! In this particular example, there is very little actual expl3 code (other than the _ and : in the syntax). For this one you can copy some definitions and make the core in LaTeX2e style: https://pastebin.com/raw/Vdy0JACf But as you can see in that link, the amount of auxiliaries you need to copy from expl3 is larger than the code you have to write (and this is a very simple example!), so the advantage of expl3 is the large amount of tools it provides you (and the far more readable syntax). If you have any questions, do ask :-) – Phelype Oleinik Aug 06 '20 at 16:03
  • What is the simplest way to ignore trim the initial and final spaces of the parts separated by the pipes ? – projetmbc Aug 07 '20 at 19:38
  • @projetmbc Do you want space-trimming by default or to enable it with some option, like \multiapply*? – Phelype Oleinik Aug 07 '20 at 19:44
  • I only need a default behaviour. That's the way I will use it. – projetmbc Aug 07 '20 at 19:46
  • @projetmbc Okay. In that case, adding \tl_trim_spaces:n does the job. See the edit – Phelype Oleinik Aug 07 '20 at 19:49
  • What is the meaning of + in +m ? – projetmbc Aug 10 '20 at 09:26
  • @projetmbc That makes the argument \long (as in \long\def\macro#1{(#1)}). Try removing the + then do \multiapply\decoone{1|2\par 3|4}. It allows paragraph breaks (blank lines) in the argument. – Phelype Oleinik Aug 10 '20 at 10:08
  • Thanks. That is very useful. – projetmbc Aug 10 '20 at 11:56