# Expand a macro with parameters in tabular head

My eventual goal is to create my own tabular-like environment in which all entries are in math-mode by default, let's call it fancytable. (One requirement is that the first column be separated from the others by a line, but that shouldn't be the main problem.)

In Math mode in tabular without having to use $...$ everywhere I found how to approach the problem:

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\begin{document}
\begin{tabular}{ >{$}c<{$} | >{$}c<{$} >{$}c<{$} }
x & x^2 & x^3\\
y & y^2 & y^4
\end{tabular}
\end{document}


but this is not what I'm looking for. (Note I am including tabularx because I need it for other purposes, I think it is relevant to mention.) The tabular may become large (say 15 columns) so writing >{$}c<{$} every time would be tedious. Also, some day I might change my mind and choose another lay-out, and changing all tables isn't really a thing I'm looking forward to. That's why I try to make it an environment.
Recently I asked how to copy and print a string a few times, in A command which concatenates a string an arbitrary number of times. So currently I have a command \repeatstring available and I expect to need it as in \repeatstring{5}{>{$}c<{$}}. (I have included its current definition below)
The first thing I tried is something like

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\newenvironment{fancytable}[1]%
{\begin{tabular}{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} } }
{\end{tabular}}
\begin{document}
\begin{fancytable}{2} % the argument of fancytable is 1 less than the desired number of columns
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}


but tabular does not accept arbitrary commands in its header. I read trough How do I expand a macro into a tabular head? and tried to adapt the answers given there. Meanwhile I figured out that I should somehow expand \repeatstring before tabular sees what's going on in its head. I think defining a new columntype every time a fancytable is created is not a good thing to do (I fail to do it anyway, getting the same error as with the above approach). Some tries:

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\newenvironment{fancytable}[1]%
{%
\renewcommand\buildtabularhead{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
{\endtabular}
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}


(based on Matthew Leingang's answer) but I keep getting

Package array Error: Illegal pream-token (\repeatstring): c' used.

as usual. The same with Bruno Le Floch's answer:

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
% definition of \repeatstring left out, see below
\makeatletter
\newcolumntype{\expand}{}
\long\@namedef{NC@rewrite@\string\expand}{\expandafter\NC@find}
\makeatother
\newcommand\mypream{}
\newenvironment{fancytable}[1]%
{%
\renewcommand\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
\begin{tabular}{\expand\mypream}}
{\endtabular}
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}


I really don't know what to do. I read When to use \edef, \noexpand, and \expandafter? but didn't achieve to use \expandafter of \edef in the right way. I always and up with

Package array Error: Illegal pream-token (\repeatstring or \edef or \expandafter or \setcounter): c' used.

\setcounter comes from my current definition of \repeatstring when I expand it:

\usepackage{etoolbox}
\newcounter{countdown}
\newcommand\concathere{}
\newcommand\repeatstring[2]{
\setcounter{countdown}{#1}
\renewcommand\concathere{}
\whileboolexpr{test {\ifnumcomp{\thecountdown}{>}{0}}}{
\appto\concathere{#2}
}
\concathere
}

• At some point a command appeared here (dissappeared by now) which gave the solution \begin{tabular}{>{$}c<{$} | * {#1} {>{$}c<{$}} }. This works. Perhaps I shouldn't spent that much time trying, since some smart command may solve it. >_< – Bart Michels Sep 3 '14 at 8:40
• I was just about to suggest the * operator :-) Please post your solution as an answer. – Daniel Sep 3 '14 at 8:42
• I would be interested to see how to solve the issue anyway ;-) – Bart Michels Sep 3 '14 at 8:51
• essentially the only difference between the array and tabular environments is that the entries are in math mode, why not simply use an array? c in array and >$c<$ in tabular are the same thing. – David Carlisle Sep 3 '14 at 10:38
• I did try with arrays but back then something went wrong, seems like now everything works fine. It could have been a typo. – Bart Michels Sep 3 '14 at 11:29

The best solution to a simply 'repeat n-times' in a tabular preamble is indeed to use the * syntax as in barto's answer. However, if you do want to use a macro containing the preamble for some reason, using Bruno's solution to How do I expand a macro into a tabular head?, then the important thing to do is to make sure it contains exactly the preamble text. That requires a definition of \repeatstring which is expandable and the use of an \edef-like expansion of the code

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\usepackage{xparse}

\ExplSyntaxOn
\DeclareExpandableDocumentCommand{\repeatstring}{mm}
{
\prg_replicate:nn { #1 } { #2 }
}
\ExplSyntaxOff
\makeatletter
\newcolumntype{\expand}{}
\long\@namedef{NC@rewrite@\string\expand}{\expandafter\NC@find}
\makeatother
\newcommand\mypream{}
\makeatletter
\newenvironment{fancytable}[1]%
{%
\protected@edef\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%
\begin{tabular}{\expand\mypream}}
{\end{tabular}}
\makeatother
\begin{document}
\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}
\end{document}


In the above, I've used an expl3 based expandable repeat function to define \repeatstring (much the same as egeg's solution to A command which concatenates a string an arbitrary number of times), which means that when \protected@edef is applied \mypream ends up with definition >{$}c<{$} | >{$}c<{$}>{$}c<{$}, i.e. exactly what is needed in the tabular preamble.

All of this is needed as array avoids any expansion of the tabular preamble. Thus if you do

\renewcommand\mypream{ >{$}c<{$} | \repeatstring{#1}{>{$}c<{$}} }%


what array sees is exactly that: not a string of repeated >{$}c<{$} entries but the token \repeatstring, which is does not know (and so raises an error).

• putting \expand\romannumeral-0 just before \repeatstring also works (well, except that \repeatstring was not defined). Admittedly, that's hardly something to recommend :-). – Bruno Le Floch Sep 3 '14 at 10:09

Replacing c by >$c<$ in a tabular as requested here is basically defining the array environment. Also there is no harm in declaring more columns than used, so the number of columns argument isn't really needed, just declare a large number (50 here)

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\newenvironment{fancytable}
{$\begin{array}{c| * {50} {c} } } {\end{array}$}
\begin{document}

\begin{fancytable}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}

\end{document}


Thanks to Daniel for the suggestion, no need of \repeatstring here.

\documentclass{article}
\usepackage{array}
\usepackage{tabularx}
\newenvironment{fancytable}[1]%
{\begin{tabular}{>{$}c<{$} | * {#1} {>{$}c<{$}} }  }
{\end{tabular}}
\begin{document}

\begin{fancytable}{2}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}

\end{document}


There is another approach: direct usage of \halign primitive. Note the following feature of \halign:

\halign{first:#. && rep:# \cr
a& b& c& d& e \cr
u& v& w& x& y \cr}


creates:

 first:a. rep:b rep:c rep:d rep:e
first:u. rep:v rep:w rep:x rep:y


In other words: you needn't to declare all columns in declaration part of \halign. If there are more actual columns then the processing returns to the && mark and the declaration part is read again and again...

The implementation of your fancytable can look like:

\documentclass{article}

\newenvironment{fancytable}
{\vbox\bgroup\offinterlineskip \let\\=\cr
\halign\bgroup$##$\ \vrule height2ex depth1ex &&\ $##$\ \cr}
{\crcr\egroup\egroup}

\begin{document}

\begin{fancytable}
x & x^2 & x^3\\
y & y^2 & y^4
\end{fancytable}

\end{document}


No special package you needs. The first column is processed by

$##$\ \vrule height2ex depth1ex


declaration part and arbitrary number of next columns are processed by

\ $##$\
`

Sometimes, it is usable to know the TeX primitives.