A Logo demo in Haskell

Ran across the homepage of Berkeley Logo a few days ago. One of the things on there is this demo code

to choices :menu [:sofar []]
  if emptyp :menu [print :sofar stop]
  foreach first :menu [(choices butfirst :menu sentence :sofar ?)]
end

When invoked as

choices [[small medium large]
         [vanilla [ultra chocolate] lychee [rum raisin] ginger]
         [cone cup]]
we get a list of choices starting with
small vanilla cone
small vanilla cup
small ultra chocolate cone
small ultra chocolate cup
…
I got curious about how Haskell stacks up against Logo here… After a whole bunch of fiddling around with various versions I ended up with this
choices = foldr (\c cs -> [e : es | e <- c, es <- cs]) [[]]
which when invoked as
choices [["small", "medium", "large"],
         ["vanilla", "ultra chocolate", "lychee", "rum raisin", "ginger"],
         ["cone", "cup"]]
prints a list of choices that starts
[["small","vanilla","cone"],["small","vanilla","cup"] …

I have deliberately left the "ugly" input and output of the Haskell. One can paper around it, but I wanted to stress that the Haskell choices, unlike the Logo version, is a generic combinator that returns its lists rather than printing them, so that they can be further processed; for example

map sum $ choices [[1, 2], [3, 4]]
yields the list
[4, 5, 5, 6]

The other important point about the Haskell version is the lack of any kind of explicit iteration or recursion. This is of course not because Haskell has special operators for this case, but because Haskell's general-purpose operators normally allow one to avoid recursion or iteration—here it is wrapped up by the foldr and by the list comprehension.

As I noted earlier, by extending our code from a one-liner to a two-liner we can get pretty output:

prettyChoices = putStr . unlines . map unwords . choices
Again, there's no recursion here, just applying a series of transformations to the list of choices until it's a Haskell string and then printing that string.

I like Haskell a lot. I'm seriously considering teaching it to my boy. I'm working on a tutorial to that effect; I talked with a lot of folks about it at Open Source Bridge a week or more ago. This code snippet is something I think my boy may be able to learn to write if he gets interested. I'll be curious to find out. (B)