18 February 2008

Is Python an Acceptable Haskell?

So I struggled with some Python this weekend. I'm taking over a piece of code that is written in Python, but the original is very imperative, with a lot of for loops. It was giving me a headache. It just looked way too long and tedious. I'm too old to spend my life debugging off-by-one errors in for loops.

After staying up half the night struggling with a malfunctioning IDLE on MacOS X, I finally discovered the cure for the headache was -- more Python!

# This gives us a "curry" equivalent
from functools import partial

# Reduce a list of strings to a single string by concatenation
reduce_stringlist = partial( reduce, str.__add__ )

# Given a list of XML elements, return a list of only the data from only the text nodes
# (ignores any non-text nodes)
def get_text_data( nodelist ):
    return map( lambda node: node.data,
           filter( lambda node: node.nodeType == node.TEXT_NODE, nodelist ) )

# Now, combined: reduce a list of nodes to the concatenated text extracted out of only
# the text node data
def extract_text( nodelist ):
    return reduce_stringlist( get_text_data( nodelist ) )

# Given a portion of the parsed XML tree and a name, extract a single string. Expect
# only one element.
def get_one_text_element( node, name ):
    elt_list = node.getElementsByTagName( name )
    assert elt_list.length == 1
    return extract_text( elt_list[0].childNodes )

# Given a starting node and a list of tag names, retrieve one text string each and
# put them in a newly created dictionary using the tag name as a key
def make_text_element_dict( node, namelist ):
    return dict
        zip( namelist,
             map ( partial( get_one_text_element, node ),
                   namelist ) ) )

Ahhh, I feel much better! All that excess hairy boilerplate seems to be just melting away!

The only thing I did not like is that there did not seem to be a nice way to specify keyword arguments to "reduce" so that I could create a partial (curried) application that supplied the first and optional third parameter, leaving the second as the one to be supplied at runtime.

I experimented with writing the above with Python's list comprehension idiom, generators, and various permutations on join(). The above just seems to make more sense to me. Haskell has apparently ruined me for other languages.

Apparently Guido would like to ban reduce() from Python. I say -- prefer the standard idiom to the offbeat, and avoid the Not Invented Here syndrome. Python's comprehensions and generators are nice, but apparently I've been ruined by seeking more and more expressive languages, seeking truth and beauty on my wandering but inexorable path from Dylan to NewtonScript to Scheme to Haskell. Lambda, map, curry, reduce, and zip now seem to me to be fundamental primitives that any reasonable dynamic language ought to provide, and it seems to me that they ought to be preferred to an obscure language-specific trick. As long as I have to use Python, Guido will have to pry the curried functions from my cold, dead hands!

14 February 2008

A Pet Peeve -- Proprietary Fasteners

As if it wasn't hard enough to keep tools on hand for the following screws:

- Flat blade

- Hex (in metric and fractional inch sizes)

- Philips

- Torx

- Tamper-resistant Torx (with a post in the middle)

- Torx Plus (with wider holes)

- Tamper-resistant Torx Plus (hard to come by -- with wider holes, a post in the middle, and five points instead of six)

- TTAP (a six-point variation with a deep hole in the middle, also hard to come by)

- Tamper-resistant TTAP (which I've never seen)

- Several other unusual fastener heads, such as square, two-pin, etc.

I've found that certain hard drive screws use a five-pointed variant of the six-pointed Torx star shape, which corresponds to "none of the above" and which doesn't seem to be available, anywhere. I found this out the hard way after buying a very nice set of Torx bits. The screws in question are so small it is very hard for my 40-year-old eyes to distinguish the five-pointed star from the six. They are roughly the size of a Torx T3 or T4.

The only reason I can imagine that manufacturers would use a fastener like this is sheer perversity. It isn't to make the devices tamper-proof -- the screws can be turned with a flat-head screwdriver of just the right width, although this is not ideal for either fastener or tool. Or, I could always just drill them out, as I've done on more than one occasion with a very stripped or damaged screw.

To the best of my knowledge the correct tool is not available for purchase _anywhere_ for a nobody like me, although I think you can sometimes find tools for larger versions of the bits for sale on eBay.

Several of these fasteners are apparently actually patented, and several apparently can't be legally sold except to properly licensed OEMs or other authorized personnel. Wiha sells, but will not sell to me, tamper-resistant Torx Plus tools, for example. And even if they would, they don't seem to have any this small.

As far as I'm concerned, such restrictions should be illegal. I'm sure there is an analogy here to be made to software APIs. I'm reminded of a talk I saw by Stallman, in which he drew puzzle pieces representing APIs, and talked about the evils of proprietary APIs. I bought it, I ought to have the right to take it apart!

By the way, the device in question is an iPod hard drive, made for Apple by Toshiba. But I'm sure there are many other variants of the same thing going on.

13 February 2008

Trying Programming Environments for Children

I am home sick today, feeling terrible and feverish, and should be sleeping, but can't sleep, so I thought I would try out some of the programming environments for kids. A while back I set up my son with the Haskell tools used for The Haskell School of Expression and Thompson's Craft of Functional Programming book, hoping my son would work his way into one of the texts a bit. He didn't get that far, so I thought I'd try out some other options for him.

I started learning when personal computers came with BASIC interpreters built-in, so I am looking for something equally as easy to start with, although I think teaching my son BASIC might be considered child abuse.

I thought I'd try to set him up with Hackety Hack, a Ruby environment found here. On Ubuntu Gutsy, I found that it segfaults immediately upon launch. According to the forum this issue has been reported for close to a year, with no patch.

OK, the next one on my list to try is Greenfoot. Greenfoot is Java-based, and requires a JDK. I haven't been a Java hacker since the dot-com crash, but at one point knew it pretty well, so how hard could it be for a feverish software engineer? My install of Gutsy tells me its java is "java version "1.7.0, IcedTea Runtime Environment (build 1.7.0-b21), IcedTea Client VM (build 1.7.0-b21, mixed mode, sharing)." So I'll try installing the IcedTea JDK. That looks promising, although the notes indicating it is a "temporary fork" make me a little nervous; Ubuntu lives up to its ease-of-use repuation, the JDK installs, and the Greenfoot installer now seems to be able to figure out for itself where the JDK is. The Greenfoot executable launches, and looks at least moderately interesting, so I'll call that a qualified success for now, and see if he can get his head around it.

I had it on my list to check out Nodebox, but that's for MacOS X only, and today I'm on the Linux box, so we'll save that for another sick day.

Finally, I wanted to take a shot at setting up Sugar, the Python-based environment that was designed for the One Laptop Per Child system. I'm not hugely keen on Python; having used Python and Ruby, I harbor a slight preference for Ruby, and I've got a laundry list of things I don't like about both of them. However, I'm being asked to use and get comfortable with extending several tools in my workplace that are based on Python, so for better or worse I'm getting myself re-familiarized with Python. It's quite a mature language with lots of libraries. My son could do worse, so let's see what Sugar has to offer.

There are various ways to get Sugar going on Ubuntu. See the Wiki pages here. To begin, I'm going to try the emulated route, where my Linux PC will literally emulate an OLPC laptop. The other options look considerably more complicated and error-prone; in particular, there is an absolute rat's nest of required packages. So let's see how painful setting up emulation is. First, we download a bzip'ed image file. While it is downloading, I install QEMU, which is not difficult. For now I'm not going to attempt to install the kernel support for accelerating QEMU; we'll see if it is really painfully slow. This machine is "only" a Pentium 4 2.8 GHz system that I built from parts a few years ago; pretty obsolete, but usually plenty fast.

So, image is done downloading, unzip it, and try running QEMU on it -- it works! Although it does indeed take a very long time to launch. I still find it quite surreal to watch Linux boot on top of Linux!

That's all for now -- I am still home sick, after all -- it's time to have some hot lemon tea and try to get a nap!

Followup: installing the kqemu acceleration tools does make the OLPC image run _significantly_ faster -- it is quite tolerable now, although I have no idea how it compares to how the image runs on the target hardware itself.