Brian Harvey throws down the gauntlet: implement the Ice Cream [1] problem [2] in a small number of lines of Java. Well, since I don't know Java, I'll take up the challenge in C++...
template<template<class> class Out, class Obj, template<class> class G, template<class> class F>
Out<Obj> comb(typename G<F<Obj> >::const_iterator b, typename G<F<Obj> >::const_iterator e)
{
typename G<F<Obj> >::const_iterator tail = b;
if(++tail == e) { return *b; }
else
{ // recursivly concatenate the items in the head of the list
// with the tails...
G<F<Obj> > temp;
transform((*b).begin(),(*b).end(),back_inserter(temp),bind1st(ptr_fun(aux<Out,Obj>),comb<Out,Obj,G,F>(tail,e)));
//now flatten temp...
Out<Obj> out;
for(typename G<F<Obj> >::const_iterator i = temp.begin(); i != temp.end(); ++i)
copy((*i).begin(),(*i).end(),back_inserter(out));
return out;
}
}
template<template<class> class Container, class Obj>
Container<Obj> aux(Container<Obj> ps, Obj n)
{
Container<Obj> out;
transform(ps.begin(),ps.end(),back_inserter(out),bind1st(plus<string>(),n));
return out;
}
...OK. That's pretty verbose. But it is interesting to note that there are only ~5 lines of code doing the work there. The rest is dedicated to declaring stuff like types. The other thing to notice is that the C++ solution above is pretty generic. You can feed it a list of list of strings, or a vector of deque's of strings, or even a list of stacks of valarray<double>'s (don't ask me what you'd use that for). You can save a few LOC and a little bit of uglyness by specializing it for lists of lists of strings. Of course, that still pales in comparison to the two line Haskell solution...
combs [a] = a
combs (x:xs) = concat $ map (\n -> map (n++) (combs xs)) x
...and for interested parties, here is a driver program, so you can get up to speed quickly (and catch any of my mistakes)...
#include <list>
#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
template<template<class> class Out, class Obj,
template<class> class G, template<class> class F>
Out<Obj> comb(typename G<F<Obj> >::const_iterator b,
typename G<F<Obj> >::const_iterator e);
template<template<class> class Container, class Obj>
Container<Obj> aux(Container<Obj> ps, Obj n);
int main()
{
char *c[] = {"small ","medium ","large ",
"vanilla ","ultra chocolate ","lychee ","rum raisin ","ginger ",
"cone","cup"};
int len[] = { 3, 5, 2 };
list<list<string> > choices;
for(int i=0, off=0; i<3; off += len[i++])
{
list<string> temp(c+off,c+off+len[i]);
choices.push_back(temp);
}
list<string> o = comb<list,string,list,list>(choices.begin(),choices.end());
copy(o.begin(),o.end(),ostream_iterator<string>(cout, ".\n"));
return 0;
}