|February 5th, 2009|
|shell, programming, lisp [html]|
Bash is REPL based. As I build things up in bash that are quite complex I'm always testing as I go. I'll cat a bunch of files, pipe to something else, and if I get anything wrong I notice almost right away. This is very powerful because
Bash puts arguments first. I start with the files I want to work with (cat logs/tuesday/*) then pipe to grep to filter out the ones I don't want, then maybe pipe to wc. All along the way, I can print out what I have so far. And I can think about the data before the next processing step. Some things break this pattern, for example "for x in $(big long expression)" or "diff " but the former can be replaced with "big long expression | while read x" as long as it's not spaces you want to split on. And the latter necessarily takes two input streams, so you have to accept some loss of linearity.
This is not to say I think bash is ideal. The way it deals with unset variables (evaulating to the empty string) is pretty annoying. And always having to worry about special characters doing crazy things is also frustrating. And the things I write are rarely easy for even me to read looking back on them after a while. But it's definitely fast to write.
Lisp shares the first property with bash, but in the other it's nearly the opposite. The analog of "cat | grep | wc" is "(wc (grep (cat)))". Most languages are niether all one way or all the other. They can go "wc(grep(cat))" or "a = cat(); b = grep(a); c = wc(b)" and most programmers use some of both.
Thinking about how easy it would be to write inverted lisp with a reversing macro interpreting everything (not that I actually think this is better -- the top down style of lisp with more thinking ahead is probably good for me) brought me on to the other idea: it might not actually be good for languages to be as extensible by the individual programmer as lisp is. Paul Graham writes that a language annoyance that a java or python programmer would have to wait for a language fix for a lisp programmer can generally just fix themself. Take generics in java or, better, with in python. It's really nice. Instead of having to remember to close things or release locks even in complex error situations, they're dealt with when the block ends. But it wasn't in python for a long time and had to be centrally added. In lisp anyone could write with and not have to wait. This sounds good.
Except that in the lisp case only that person benefits; any one who didn't think to write with doesn't get to use it. In python it became available to everyone. Because smart people who want to have an extended version of the language can't just do it themselves easily, they suggest it as a feature and everyone gets it. Maybe this isn't ideal, but it improves the core language much faster. Looking at arc, I think almost all of it could be implemented entirely as macros and functions in common lisp. And many of the good ideas probably have been implemented in lisp by many people over and over. But without the pressure of users frustrated by the limits of the language, lisp didn't get centralized improvement.
Comment via: facebook