The standard mapping functions are meant for the simple case where you want to pass the mapped tokens to some pre-defined auxiliary. In a non-expansion context you can define the auxiliary dynamically to include other data
\cs_new_protected:Npn \module_main:N #1
{
\cs_set_protected:Npn \__module_aux:n ##1
{
% Code using #1
}
\clist_map_function:NN \l__module_clist \__module_aux:n
}
or as you note use \clist_map_inline:Nn. The first approach can be used where the wrapper does not need to be expandable but the mapping does, while the second cannot.
For fully-expandable mappings the expectation is people will use the generic tools for defining recursions: it's not possible to predict every use case. For example, we might have
\cs_new:Npn \module_main:N #1
{
\exp_after:wN \__module_loop:Nw \exp_after:wN #1
\l__module_clist , \q_recursion_tail , \q_recursion_stop
}
\cs_new:Npn \__module_loop:Nw #1#2 ,
{
\quark_if_recursion_tail_stop:n {#2}
% Code using #1 and #2
\__module_loop:Nw #1 % Loop passing #1 from \module_main:N
}
Passing lots of arguments like this can get a be tricky and might require an auxiliary to do a 'shuffle' of the arguments, e.g.
\cs_new_nopar:Npn \module_main:Nnn
{
\__module_aux:VNnn \l__module_clist
}
\cs_new:Npn \__module_aux:nNnn #1#2#3#4
{
\__module_loop:Nnnw #2 {#3} {#4}
#1 , \q_recursion_tail , \q_recursion_stop
}
\cs_generate_variant:Nn \__module_aux:nNnn { V }
\cs_new:Npn \__module_loop:Nnnw #1#2#3#4 ,
{
\quark_if_recursion_tail_stop:n {#4}
% Code using #1 to #4
\__module_loop:Nnnw #1#2#3 % Loop passing args from \module_main:Nnn
}
For cases where you want to do a test on the input and only use the other arguments in one case you leave the latter in the input stream and do something like
\cs_new_nopar:Npn \module_main:Nnn
{
\exp_after:wN \__module_loop:wNnn
\l__module_clist , \q_recursion_tail , \q_recursion_stop
}
\cs_new:Npn \__module_loop:wNnn #1 ,
{
\quark_if_recursion_tail_stop_do:nn {#1} ( \use_none:nnn }
\str_if_eq:nnT {#1} { fixed-string }
{
\use_i_delimit_by_q_recursion_stop:nw { \__module_aux:nNnn {#1} }
}
\__module_loop:wNnn
}
\cs_new:Npn \__module_aux:nNnn #1#2#3#4
{
% Do stuff
}
where \use_i_delimit_by_q_recursion_stop:nw lets us break out of the loop and insert the auxiliary and the hit, while \use_none:nnn cleans up if there is no hit.
More generally, \use_none_delimit_by_q_recursion_stop:w/\use_i_delimit_by_q_recursion_stop:nw can be used to terminate a generic recursion prematurely irrespective of how many arguments are passed, so we might modify one of the above to
\cs_new_nopar:Npn \module_main:Nnn
{
\__module_aux:VNnn \l__module_clist
}
\cs_new:Npn \__module_aux:nNnn #1#2#3#4
{
\__module_loop:Nnnw #2 {#3} {#4}
#1 , \q_recursion_tail , \q_recursion_stop
}
\cs_generate_variant:Nn \__module_aux:nNnn { V }
\cs_new:Npn \__module_loop:Nnnw #1#2#3#4 ,
{
\quark_if_recursion_tail_stop:n {#4}
\test:T % Terminate the loop early
{
\use_none_delimit_by_q_recursion_stop:w
}
\__module_loop:Nnnw #1#2#3 % Loop passing args from \module_main:Nnn
}
\clist_map_function:NNand\__clist_map_function:Nw(Since I need \clist_map_break:)? – Z.H. Feb 13 '15 at 07:55expl3to create a range of recursion behaviours. – Joseph Wright Feb 13 '15 at 08:40\quark_if_recursion_tail_stop_dofunction, I found it saysthis is part of using \use_none_delimit_by_q_recursion_stop:w. Some mistakes in it? – Z.H. Feb 13 '15 at 10:58