recursive list type like definition in LaTeX

Here is an alternative solution which does not need to iterate the list twice. After the first element, the \do is replaced by \mydo:

\documentclass{article}

\usepackage{etoolbox}

\newcommand*{\mydo}[1]{;\,#1}

\newcommand{\mylist}[1]{%
  \renewcommand*{\do}[1]{##1\let\do\mydo}%
  \left[\docsvlist{#1}\right]% Process list
}

\begin{document}

$\mylist{aa,bb,cc}$

$\mylist{aa}$

\end{document}

The character ; must be shifted to be placed inside of the \ifnum\value....\fi test.

I also added a much, much, much shorter expl3 version right before \begin{document}, although the expl3 syntax might be very strange to L3 newbies...

I used the \docsvlist and \forcsvlist macros up to two years (2015) ago, but shifted then to he much more powerful expl3 syntax (although not easy to learn), especially for the multitude of lists there are in expl3, such as seq or clist or prop lists, which provide more functionality, in my point of view.

But first to the \ifnum... test:

 \ifnum\value{listcount} < \value{totalcount}
 ;\,
 \fi

just tests whether the current value of the listcount counter is smaller than the value of totalcount counter and prints a ;\, then, otherwise it doesn't.

The expl3 version is at the end and much simpler in its usage, no tests are needed (in fact, they are hidden behind \seq_use).

First enter the expl3 - syntax style with \ExplSyntaxOn and store the comma separated list values of the argument to a temporary sequence variable \l_tmpa_seq. Later display this list with \seq_use:Nn \l_tmpa_seq {;\,} -- the command takes care about the end of the list.

In order to prevent space gobbling, the wrapper command \displaylist is defined outside, see also Spaces in l3prop for the topic of spaces with expl3.


\documentclass{article}

\usepackage{etoolbox}

\newcounter{listcount}
\newcounter{totalcount}%
\newcommand{\mylist}[1]{%
  \setcounter{totalcount}{0}% Reset total count
  \renewcommand*{\do}[1]{\stepcounter{totalcount}}% Reconfigure count
  \docsvlist{#1}% Count number of items
  \setcounter{listcount}{0}% Reset current item count
  \renewcommand*{\do}[1]{% Reconfigure item \do
    \stepcounter{listcount}% Next item
    ##1\ifnum\value{listcount}<\value{totalcount};\,\fi% Print item
  }
  \left[\docsvlist{#1}\right]% Process list
}


\begin{document}
$\mylist{aa,bb,cc}$

$\mylist{aa}$


\end{document}

Of course $\mylist{}$ will yield [].

enter image description here

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\newcommand{\myotherlist}[1]{%
  \seq_set_from_clist:Nn \l_tmpa_seq  {#1}
  \displaylist{\seq_use:Nn \l_tmpa_seq {;\,}}
}
\ExplSyntaxOff
\newcommand{\displaylist}[1]{%
  \left[#1\right]%
}

\begin{document}

$\myotherlist{}$

$\myotherlist{aa,bb,cc}$

$\myotherlist{aa}$

\end{document}

A fully expandable version:

\documentclass{article}

\makeatletter
\newcommand{\ocamllist}[1]{\left[\ocaml@list#1,,\@nil}
\def\ocaml@list#1,#2,#3\@nil{%
  \if\relax\detokenize{#2}\relax
    \expandafter\@firstoftwo % no comma
  \else
    \expandafter\@secondoftwo
  \fi
  {\if\relax\detokenize{#1}\relax\,\else#1\fi\right]}
  {#1;\ocaml@list#2,#3,\@nil}
}
\makeatother

\begin{document}

$\ocamllist{}$

$\ocamllist{aa}$

$\ocamllist{aa,bb}$

$\ocamllist{aa,bb,cc}$

\end{document}

enter image description here

Not expandable, but more compact:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\ocamllist}{m}
 {
  \left[
  \clist_set:Nn \l_hongxu_ocamllist_clist {#1}
  \clist_if_empty:NTF \l_hongxu_ocamllist_clist
   { \, }
   { \clist_use:Nn \l_hongxu_ocamllist_clist {;} }
  \right]
 }
\clist_new:N \l_hongxu_ocamllist_clist
\ExplSyntaxOff

\begin{document}

$\ocamllist{}$

$\ocamllist{aa}$

$\ocamllist{aa,bb}$

$\ocamllist{aa,bb,cc}$

\end{document}