With your code you're essentially doing the same as
\foreach \i in {\separate{\arg}}{[\i]}
so there is only one cycle to do.
You have to first separate the string and then call \foreach, which can't do that job.
Here's how I would do it:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\separate}{sm}
{
\IfBooleanTF #1
{
\linus_separate:o { #2 }
}
{
\linus_separate:n { #2 }
}
}
\NewDocumentCommand{\map}{sm}
{
\IfBooleanTF #1
{
\linus_map:o { #2 }
}
{
\linus_map:n { #2 }
}
}
\cs_new_protected:Npn \linus_separate:n #1
{
% split the input into parts "at nothing"
\seq_set_split:Nnn \l_linus_list_seq { } { #1 }
% deliver the input separated by commas
\seq_use:Nnnn \l_linus_list_seq { ,~ } { ,~ } { ,~ }
}
% a variant for a macro input
\cs_generate_variant:Nn \linus_separate:n { o }
\cs_new_protected:Npn \linus_map:n #1
{
% split the input into parts "at nothing"
\seq_set_split:Nnn \l_linus_list_seq { } { #1 }
% deliver the input by enclosing the parts in brackets
\seq_map_inline:Nn \l_linus_list_seq { [##1] }
}
% a variant for a macro input
\cs_generate_variant:Nn \linus_map:n { o }
\ExplSyntaxOff
\begin{document}
\def\arg{3669887}
\arg
\separate*{\arg}
\map*{\arg}
\separate{1234}
\map{1234}
\end{document}
However you probably don't need the \separate function any more. I'd keep distinct the macros when the input is "symbolic", such as \arg, from when it is "explicit"; thus the two calls \map* and \map.

\mapis\separate{\arg}, so what you get is\foreach \i in \separate{\arg}which is not what you want. – egreg Jul 12 '13 at 16:58\foreachloop with macro-defined list – Werner Jul 12 '13 at 17:04