# Using etoolbox to automatically generate input for \xymatrix

I'd like to make a command \exactseq such that, for example,

\exactseq{A,f,B,g,C}


corresponds to

\xymatrix{A \ar[r]^{f} & B \ar[r]^{g} & C}


and such that this works for inputs of arbitrary length, not just for some fixed length. To be precise, I want to input a list and have the nth element of the list made into an entry in an xymatrix when n is odd, and to be an arrow when n is even.

Edit: As Werner asks about below, I'd usually have entries and arrows that are more than one character long, and may not be plain text, e.g. \Omega, or f_{i}, or \mathbb{Z}. The simpler example given above was just for illustration purposes.

I've been trying to accomplish this using the etoolbox package's list commands; as an initial attempt (without even defining \exactseq), I tried

\documentclass[11pt]{article}
\usepackage{amsmath,amssymb,amsthm,amsfonts}
\usepackage{etoolbox}
\usepackage[all]{xy}
\begin{document}

\newcounter{obfun}
\setcounter{obfun}{0}
\renewcommand*{\do}[1]{\ifnumodd{\value{obfun}}{\ar[r]^{#1} &}{#1}\stepcounter{obfun}}

$\xymatrix{\docsvlist{A,f,B,g,C}}$

\end{document}


but this produced a massive collection of errors, mostly relating to missing or misplaced \cr's (I'm afraid I don't understand what that means). I tried putting \expandafter before \xymatrix, but that didn't help.

How can I create a command to make writing exact sequences more automated? Of course, it doesn't have to use etoolbox, or xy for that matter.

Edit: egreg's answer does work, but I'm not familiar with all of these new commands introduced by expl3 so I don't really understand how it works, and I wouldn't know how to go about modifying it if I wanted to later. Thus, I'd like to request a "lower-tech" solution (perhaps using packages that are more common or "basic" in some sense), or just other solutions if you see any. If there don't seem to be any others, I'll accept egreg's answer.

Perhaps there's a way using this TikZ code that could also work for more general arrays of objects and arrows?

-
Would you always have only single characters in your CSV list? –  Werner Sep 22 '12 at 2:02
@Werner: Most exact sequences I'd want to write would have more than one character for each object and arrow; for example, I might use Greek letters for the maps, or subscripts for indexing the entries. –  frustrated Sep 22 '12 at 2:12
Could you please give a few details about what your obfun function is supposed to do? –  T. Verron Sep 22 '12 at 5:47
The obfun is just a counter to keep track of whether an element of the list of inputs is to be considered an ob ject or a fun ction. Every time the \docsvlist command processes an element of the list, it increments the counter, changing whether or not it's odd or even, which is what \ifnumodd tests for. –  frustrated Sep 22 '12 at 5:57
@frustrated Maybe you can switch to tikz-cd package. –  percusse Sep 30 '12 at 21:33

Here's a method with expl3.

\documentclass{article}
\usepackage[all,cmtip]{xy}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\exactseq}{ O{+0pt} m }
{
\exactseq_main:nn { #1 } { #2 }
}

\int_new:N \l__exactseq_place_int
\tl_new:N \l__exactseq_seq_tl
\cs_new_protected:Npn \exactseq_main:nn #1 #2
{
\tl_clear:N \l__exactseq_seq_tl
\int_zero:N \l__exactseq_place_int
\clist_map_inline:nn { #2 } { \__exactseq_process:n { ##1 } }
\xymatrix@C#1 { \l__exactseq_seq_tl }
}

\cs_new_protected:Npn \__exactseq_process:n #1
{
\int_if_even:nTF { \l__exactseq_place_int }
{
\int_compare:nT { \l__exactseq_place_int > 0 }
{ \tl_put_right:Nn \l__exactseq_seq_tl { & } }
\tl_put_right:Nn \l__exactseq_seq_tl { #1 }
}
{
\tl_put_right:Nn \l__exactseq_seq_tl { \ar[r]^{#1} }
}
\int_incr:N \l__exactseq_place_int
}
\ExplSyntaxOff

\begin{document}
$\exactseq{A,f,B,g,C}$

$\exactseq[+1em]{A,f,B,g,C,h,D}$
\end{document}


The command \exactseq has an optional argument for changing the intercolumn space (\xymatrix@C+1em{...} in the example).

We process the list keeping track of the place we're at with an integer variable, starting at 0. We add to a token list variable the first object and then, at even positive places (corresponding to the objects other than the leftmost one) we add & and the object. At odd places we add \ar[r]^{f} (here f denotes the arrow label).

We end by issuing \xymatrix@C<optional argument>{<contents of the token list>}.

Version with etoolbox, elaborating on your example.

\documentclass[11pt]{article}
\usepackage{amsmath,amssymb,amsthm,amsfonts}
\usepackage{etoolbox}
\usepackage[all]{xy}

\newcounter{obfun}
\newcommand{\exactseq}[2][+0pt]{%
\setcounter{obfun}{0}%
\def\storedsofar{}%
\forcsvlist{\appendtoseq}{#2}%
\xymatrix@C#1{\storedsofar}
}
\newcommand{\appendtoseq}[1]{%
\ifnumodd{\value{obfun}}
{\appto\storedsofar{\ar[r]^{#1} &}}
{\appto\storedsofar{#1}}
\stepcounter{obfun}%
}

\begin{document}

$\exactseq{A,f,B,g,C}$

$\exactseq[+1em]{A,f,B,g,C}$

\end{document}


This method is very similar to the one with expl3; \storedsofar takes the place of \l__exactseq_seq_tl, where we append the items one after the other. The \forcsvlist command is the analog of \clist_map_inline:nn, as it makes a loop over the argument processing them with \appendtoseq. In the expl3 version above every item in the list is processed by an auxiliary function that performs the actions that \appendtoseq does.

The problem in executing everything inside the \xymatrix is that this uses internally an \halign (as does tabular) and so using & is dangerous (and the cause of your massive collection of errors). So the best strategy is collecting all the material in an auxiliary storage place (\l__exactseq_seq_tl or \storedsofar) and feed this one to \xymatrix.

-