warn: all source code here omit trailing % due to blog template issues; if you notice whitespace issues just add them back;

list is a basic data structure used in many languages; and it is common to have a pool of items arranged by lists; for example, all songs of a singer can be put in albums, all paragraphs of a book can be put in chapters, etc.;

the same is true for tex; sometimes we need to process items by lists; there does not seem to be builtin support for lists in plain tex where you can invoke a function on each item in a list; however, we can play with tex macros to do the same thing;

the trick is: we embed the function itself into the items, and do various jobs by changing the definition of the function, like this:

\def\AllItems{
    \doitem{ZeroItem}{0}
    \doitem{OneItem}{1}
    \doitem{TwoItem}{2}
    \doitem{ThreeItem}{3}
}

we can change the definition \doitem to perform different actions on an item;

a full example

to make a full example, assume we have 4 items: zero, one, two, three, whose values are 0, 1, 2, 3, respectively; and these 4 items are organized into 2 lists:

  • list foo: contains zero and one;

  • list bar: contains two and three;

we want to define such a structure and be able to print items by lists;

here is the skeleton of the structure:

\def\AllItems{
    \doitem{ZeroItem}{0}
    \doitem{OneItem}{1}
    \doitem{TwoItem}{2}
    \doitem{ThreeItem}{3}
}
\def\FooList{
    \doitem{ZeroItem}
    \doitem{OneItem}
}
\def\BarList{
    \doitem{TwoItem}
    \doitem{ThreeItem}
}
\def\AllLists{
    \dolist{FooList}
    \dolist{BarList}
}

now the skeleton is there, and we want to add some flesh;

define the items

first of all, we need to actually define all the items; this is done by defining \doitem as below:

\def\doitem#1#2{\expandafter\def\csname #1\endcsname{#2}}

it is a simple macro that defines #1 to be #2; for example:

\doitem{ZeroItem}{0}
\ZeroItem   %%  output: 0;

to define all items, just run the macro \AllItems:

\AllItems

and now we can do:

\ZeroItem   %%  output: 0;
\OneItem    %%  output: 1;
\TwoItem    %%  output: 2;
\ThreeItem  %%  output: 3;

now all the items are defined, and we want to print them by lists; we alter the definition of \doitem from a definition to a print:

\def\doitem#1{\csname #1\endcsname}

we print an item by running its macro;

plus, we need a definition of \dolist to print a list:

\def\dolist#1{\csname #1\endcsname}

ah, the same; we print a list by running its macro;

now we can do:

\AllLists           %%  output: 0123;
\BarList\FooList    %%  output: 2301;

and still we can print an item if we want:

\ZeroItem   %%  output: 0;
\OneItem    %%  output: 1;
\TwoItem    %%  output: 2;
\ThreeItem  %%  output: 3;

the full code

here is the full code you can run with tex:

\def\AllItems{
    \doitem{ZeroItem}{0}
    \doitem{OneItem}{1}
    \doitem{TwoItem}{2}
    \doitem{ThreeItem}{3}
}
\def\FooList{
    \doitem{ZeroItem}
    \doitem{OneItem}
}
\def\BarList{
    \doitem{TwoItem}
    \doitem{ThreeItem}
}
\def\AllLists{
    \dolist{FooList}
    \dolist{BarList}
}

\def\doitem#1#2{\expandafter\def\csname #1\endcsname{#2}}
%%\doitem{ZeroItem}{0}
%%\ZeroItem   %%  output: 0;
%%\bye

\AllItems
%%\ZeroItem   %%  output: 0;
%%\OneItem    %%  output: 1;
%%\TwoItem    %%  output: 2;
%%\ThreeItem  %%  output: 3;
%%\bye

\def\doitem#1{\csname #1\endcsname}
\def\dolist#1{\csname #1\endcsname}

\AllLists           %%  output: 0123;
\BarList\FooList    %%  output: 2301;
%%\ZeroItem   %%  output: 0;
%%\OneItem    %%  output: 1;
%%\TwoItem    %%  output: 2;
%%\ThreeItem  %%  output: 3;
\bye

acknowledgement

this clever construction comes from the ucharclasses package; examples shown in this article have some modifications;