Many years ago I was visiting a computer trade fair, and I asked the AutoDesk salesman a polite question about AutoCAD:
"Why on earth did you choose Lisp for AutoCAD's customization language?"
His reply surprised me:
"Well, it's very powerful and takes up very little memory. It was chosen by NASA for the Apollo 11 moon missions, you know."
I suppose I half believed him, like you do when a salesmen tells you something with conviction and enthusiasm and you're being a polite punter.
It was certainly fun to imagine Neil Armstrong or Buzz Aldrin typing:
(setq course 'moon)
on a clunky keyboard while floating around inside the Command Module. Or perhaps Mike Collins could have radioed:
"Houston, this is Columbia. We have a problem: unbalanced parentheses at line 1202."
And it occurs to me now that a Lisp-powered Apollo space mission would likely not have got off the ground at all if the Lisp-niks had been in charge:
"It's gotta have bignums! We can't go to the moon without bignums ... no, we must have fexprs and closures first, and proper scoping, then bignums ..."
But joking aside, I'm fairly sure that the Saturn V and Apollo rockets weren't Lisp-powered. And many things contributed to the eventual success of the space program, including, in their own way, Coca-Cola, Marlboro cigarettes, and possibly even Lisp in some form.
Do the math
Recently, I've been doing some simple mathematics with newLISP. Mostly translating between the language of mathematics and the language of computer programs. Computers aren't very good at understanding mathematical notation, despite being very good at computation, so one's always translating definitions from one form into another - from one language into another.
Here's an nice little equation for you to translate:
It's the formula for calculating the number of different ways you can write a number as a sum of smaller numbers. (It's the Hardy-Ramanujan-Rademacher partition function.) In mathematical equations like this, addition and subtraction operations are explicitly shown, but multiplication is implied, and many other operations are shown graphically, in two dimensions. It's mind-boggling stuff, really, but it has to be translated into another language before a computer can get to work on it. Ironically this picture of the equation was created by a computer that didn't understand at all what it was drawing.
I haven't been working on that one, though... I've been trying to calculate the moon's orbit, using some astronomical formulas from a little book called "Practical Astronomy with your calculator" by Peter Duffet-Smith. Here, for example, are the equations for converting ecliptic latitude (beta) and longitude (lambda) into their equivalent equatorial coordinates, ie Right Ascension (alpha) and Declination (delta), given epsilon, the current obliquity of the ecliptic:
Many computer languages use conventional algebraic notation, so a straightforward transcription of the first of these into a C or Java-like language might look a bit like this:
ra=atan(((sin(Math.toRadians(lambda))*cos(Math.toRadians(epsilon)))- (tan(Math.toRadians(beta))*sin(Math.toRadians(epsilon))))/ cos(Math.toRadians(lambda)))
which is harder for humans to read than the elegant formula pictured above.
In fact, though, there are a number of ways to make this easier to read and write. For example, programmers could provide an alternative set of trignometric functions that accept degrees rather than the more usual radians. And we can should perhaps use the atan2 function here.
Notice the five parentheses between the 'cos' and the '-' operator above. Have I got them right? One of the things to watch out for when using algebraic mathematical notation is operator precedence. If you know exactly how the operators work, you'll be able to safely miss out some of the parentheses. But if you get it wrong, you'll do the subtraction or the multiplication at the wrong time, or with the wrong numbers. I think this simplified version should work:
ra = atan2((sind(lambda) * cosd(epsilon) - tand(beta) * sind(epsilon)),cosd(lambda))
To be on the safe side, I tend to use lots of parentheses. Which brings me neatly to newLISP! My newLISP version looks like this:
(set 'right-ascension (atan2 (sub (mul (sind lamda) (cosd epsilon)) (mul (tand beta) (sind epsilon))) (cosd lamda)))
which certainly doesn't look much worse than the C/Java-like version above. Perhaps it would look better if I redefine the standard integer arithmetic operators such as + and - to do floating-point arithmetic:
(constant '+ add '- sub '* mul '/ div) (set 'right-ascension (atan2 (- (* (sind lamda) (cosd epsilon)) (* (tand beta) (sind epsilon))) (cosd lamda)))
And perhaps you might prefer it without the strangely generous layout that my formatting script applies:
(set 'right-ascension (atan2 (- (* (sind lamda) (cosd epsilon)) (* (tand beta) (sind epsilon))) (cosd lamda)))
Sometimes I find it useful to start in the middle of the expression, and gradually build it up from 'blocks'. These blocks can be lifted, moved, or copied with your editor's 'Select Text between Parentheses' command. All those parentheses turn out to be more useful than you think!
Another good thing about Lisp (not shown in this short example) is that many operators accept more than just one or two arguments. So, for example, only a single mul is required in equations that multiply many items together. This echoes the way mathematical formulas can place a number of terms side by side implying multiplication for all of them.
What about newLISP's performance? Well, I don't have much interest in benchmarking, only in speeding up slow programs if I want them to be faster. The script that calculates the moon's current position and phase currently takes 1 millisecond, so I haven't yet had any reason to think about execution speed.
Things have changed a lot since the 1960s. As the Apollo 11 Lunar Module approached the moon's surface, looking for a landing site, the onboard computer started to crash, overloaded with too much incoming data. NASA engineers didn't know whether the errors were serious or could be ignored. When you've only got 30 seconds of fuel left, you really don't want to have misbehaving computers!