With great pain, I converted those three lines of Haskell into the ugly splatter of Java you saw above. Later on, I started playing around with Scala and gradually compacted the Java into something strikingly similar to its Haskell ancestor.

So here's a challenge for you Java developers out there. What would you change about the admittedly sloppy Java code at the beginning of this post? I'm issuing an all points bulletin to the refactoring mavericks (Mike, James), the simple-design visionaries (Steve), and the speed-freak optimizers (Dan). I wouldn't even mind seeing a C# version (Ethan), or an improvement on the Haskell (Eric).

Incidentally, I know some people think recursion is hard to read. I'd love to see an iterative solution as well.

P.S. I realize that the comment boxes don't hold code blocks very well. Feel free to link to a solution.

Updates:Based on your input, I am now happy to give three different ways of returning '(()) in one line. I am only including ways that would work in the context I gave (i.e. the inner list must be mutable). The last is my favorite because the others cause compiler warnings.

return Arrays.<List<T>>asList(new ArrayList<T>());// Type safety : A generic array of ArrayList is created for a varargs parameter

return new ArrayList<List<T>>() {{add(new ArrayList<T>());}};// The serializable class does not declare a static final serialVersionUID...// Ricky points out that this is an "Eclipse warning".

Eric has blessed us with a version in Factor (not to be confused with my aversion to Factor). He also added a Haskell version using list comprehensions to achieve better laziness properties.

Meanwhile, back in Javaland, Dan suggested using SortedSet, particularly the subSet method. This seems to be a dead end in this case, but is certainly a useful corner of the Collection hierarchy.

After briefly attaining List Enlightenment, Thomas produced an implementation in Java with no recursion. Aside from being much longer and totally opaque, it also has worse performance charactoristics. It essentially produces every subsequence and then filters by length, similar to the Haskell one-liner suggested in the comments.

25 comments:

hmm...that IS a little frustrating. If I take that your primary problem is how ugly it is to just return a list containing an empty list, then we need to add some sugar to make that more pleasent. Obviously it's never going to look as good as '(()), but perhaps you can do something similar to your Collections.singletonList example, just with less words. If this is a problem that is going to come up frequently, I would mind seeing a signature like this:

Collections.EmptyNester<T>();

Both amusing and a little more succinct. You'll still be using the original "naive" method under the covers, but your loop would be a little less ugly. Like I said, though, not as good as '(()).

Maybe another option is to hack the byte-code compiler you're using and translate any occurance of '<T>(()) into the necessary function. ; )

One of the things that often gets said when language wars heat up is that Java is easy to read. That's often pretty true in the small, but in the large (or even the medium) it's hard to defend. Even though I have written far, far more Java than any of the other languages (by several orders of magnitude) I still found the readability of your samples highest in Haskell, then Scala, then Lisp. Java was so far out of the running it didn't even compete - I really had to puzzle at it to see the essential algorithm buried in all the boilerplate.

Also, for grins consider this powerset function. If you do that and then filter for length you get the desired result (albeit inefficiently) in one line of code. Admittedly, the readability of that solution would be a bit debatable ;-)

Thomas: No, you successfully answered the challenge by producing the correct output with no recursion. I was just stating the caveats as they were. Be not afraid, you've still won free tickets to cadrlife.com and a copy of our home game!

The second generics parameter (List<T>) is either optional, or if it isn't, should have been optional. Fortunately there are some waves in java7 to ensure such stuff is definitely optional. In fact, if the statement is either an assignment or a return (which is a bit like an assignment), there are waves to aggressively infer the type. There is certainly no clear reason why this should be impossible.

In other words, I wouldn't be surprised if this works just fine in java7:

The different solutions give you nine possible combinations of mutable/mutable-with-fixed-size/immutable for both the internal and the external list (i.e. mutable = ArrayList, mutable with fixed size = Arrays.asList, immutable = Collections.(emptyList|singletonList)). Not as nice as [[]] though, but if we try to write down all the possibilities in Haskell the other ones will be less beautiful than the immutable singleton list holding an immutable empty list. The main problem of Java (WRT this problem) is the lack of type inference, lack of suitable literal syntax for building collections and awfully named methods in libraries (due mostly to trying to make everything be a method of a class and lack of proper modules). Fixing those flaws we could even use something like: list(list()), which wouldn't be too bad.

On a second thought if Java placed generic parameters in method calls between the name and the parenthesis (like it does with constructor calls and like C# does) we could write:

import static java.util.Arrays.asList;...return asList(asList<T>());

Which isn't too bad. Creating a static factory method list that calls builds an ArrayList given an varargs array of objects we could even get: list(list<T>()). While I agree that Java has many semantic problems, this particular problem is just a matter of syntax and library names.