5

I am looking for a good explanation of the differences and use cases, between the tl_map_function:nN and tl_map_inline:Nn. I provide a MWE for the inline which also appears to be the fastest.

\documentclass{article}
\usepackage{expl3,xparse}

\begin{document}
\ExplSyntaxOn
\cs_new:Nn\whatever:n{..{#1}~}
\tl_new:N  \tl_phd_temp_a
\tl_new:N  \tl_phd_temp_b
\tl_new:N  \tl_phd_temp_c
\DeclareDocumentCommand\Test{ }
    {
       \tl_set:Nn  \tl_phd_temp_a {Yiannis Mary John}
       \tl_set:Nn  \tl_phd_temp_b {{Lazarides}{Lou}{Smith}}
       \tl_concat:NNN \tl_phd_temp_c \tl_phd_temp_a \tl_phd_temp_b
       \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
   }   
\ExplSyntaxOff 
\Test
\end{document}
  • I always thought the difference was expandability. With \tl_map_inline:Nn you have to define the function that everything is mapped onto. With \tl_map_function:NN you already have it defined, so it's expandable. And, the reason of \tl_map_inline:Nn is faster, I think, is that since it's not expandable, they don't care how to do the mapping, with map_function I guess they have to play a little more with the code so the map is expandable. – Manuel May 1 '15 at 18:37
  • My comment applies to seq_map, sorry for the confusion. In case of tl_map it seems that tl_map_inline defines first the function and then maps, while the other one just maps. – Manuel May 2 '15 at 13:00
  • @Manuel Thanks for the comments, just made me look at the code for both. – Yiannis Lazarides May 2 '15 at 13:02
1

The functions \tl_map_function:nN and \tl_map_function:NN are fully expandable (with x-expansion, not f-expansion), while the inline version aren't.

The function version is also slightly faster.

Example file

\documentclass{article}
\usepackage{expl3}

\begin{document}

\ExplSyntaxOn
\cs_new:Nn\whatever:n{}
\tl_new:N  \tl_phd_temp_a
\tl_new:N  \tl_phd_temp_b
\tl_new:N  \tl_phd_temp_c
\tl_set:Nn  \tl_phd_temp_a {Yiannis Mary John}
\tl_set:Nn  \tl_phd_temp_b {{Lazarides}{Lou}{Smith}}
\tl_concat:NNN \tl_phd_temp_c \tl_phd_temp_a \tl_phd_temp_b

\cs_new:Npn \xinline
 {
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
  \tl_map_inline:Nn\tl_phd_temp_c{\whatever:n{##1}}
 }
\cs_new:Npn \xfunction
 {
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
  \tl_map_function:NN\tl_phd_temp_c \whatever:n
 }

\cs_new:Npn \y #1
 {
  #1 #1 #1 #1 #1 #1 #1 #1 #1 #1
 }
\cs_new:Npn \z #1
 {
  \y{#1}\y{#1}\y{#1}\y{#1}\y{#1}
  \y{#1}\y{#1}\y{#1}\y{#1}\y{#1}
 }
\cs_new:Npn \zz #1
 {
  \z{#1}\z{#1}\z{#1}\z{#1}\z{#1}
  \z{#1}\z{#1}\z{#1}\z{#1}\z{#1}
 }
\cs_new:Npn \zzz #1
 {
  \zz{#1}\zz{#1}\zz{#1}\zz{#1}\zz{#1}
  \zz{#1}\zz{#1}\zz{#1}\zz{#1}\zz{#1}
 }

\ExplSyntaxOff

\zzz{\xinline}
%\zzz{\xfunction}

\stop

inline version

This is the response by time

real    0m4.635s
user    0m4.613s
sys     0m0.016s

and this is the memory report

 140188 words of memory out of 5000000

function version

This is the response by time

real    0m4.163s
user    0m4.139s
sys     0m0.020s

and this is the memory report

 140188 words of memory out of 5000000

What's to be preferred? I tend to consider \tl_map_inline:nn easier, because it doesn't require defining a new function, but when the code becomes complicated, the function version should be employed for better clarity. It should be adopted whenever the mapping to be performed uses a function defined elsewhere.

The inline version makes it easier to add break points; the function version needs a specially tailored function containing \tl_map_break:.

Also, the function version is a bit more complex when the mapping requires more than one argument (for instance we're in a nested mapping, using both the outer and the inner item).

  • Thanks for your fine answer. Personally I prefer the function style as it is nearer to the concept of callback in other languages. – Yiannis Lazarides May 2 '15 at 14:52

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.