Books of Note

Practical Common
LispThe best intro to start your journey. Excellent coverage of CLOS.

ANSI Common
LispAnother great starting point with a different focus.

Paradigms of Artificial Intelligence
ProgrammingA superb set of Lisp examples. Not just for the AI crowd.

Monday, January 23, 2006

Commentary on "Lisp is Sin" 

I had great fun reading Sriram Krishnan's essay "Lisp is Sin" last week. Sriram works at Microsoft, so it was interesting to see some of his comments, particularly with regards to C# and how it compares with some Lisp features.

A couple things struck me. First, Sriram writes:

After looking at Norvig's implementation of memoization in his book, I set out today to do the same in C# 2.0. Here's what I wound up with after 10 minutes.

public delegate TReturn Function<TParam, TReturn>(TParam param);

static Function<TParam, TReturn> Memoize<TParam, TReturn> (Function<TParam, TReturn> func)
{

Dictionary<TParam,TReturn> memoDict = new Dictionary<TParam,TReturn>();
return delegate(TParam arg)
{

    TReturn result = default(TReturn);

    if(memoDict.ContainsKey(arg))
    {
        result = memoDict[arg];
    }
    else
    {
        result = func(arg);
        memoDict[arg] = result;
    }
    return result;

};

}

Is it as pretty as the Lisp counterpart? Probably not. But I'm willing to bet that a lot more developers will be able to understand this since this is in a programming language they understand well. And it gets the job done in most cases.

The final paragraph sums up a lot of Lisp vs. something-else dynamic. Smug Lisp Weenies read that paragraph and think, "So what. Learn to use the best tool." And they're partially right. If I built houses for a living, it would be so much better to learn about screwdrivers than to keep pounding in screws with a hammer, just because that's all I know and I want everything to look like a nail.

Where Smug Lisp Weenies fail is that they often don't provide much information for a newbie trying to learn. Fortunately, that seems to be changing.

The second point that struck me about the essay were the comments that followed it. It is amazing that with all the growth in Lisp awareness fueled by Paul Graham and Joel Spolsky recently, people still fail to see the advantages of Lisp. They take one look at the parentheses and head for the door.

Now, Smug Lisp Weenies often just roll their eyes and fail to educate as to why Lisp is better. Being new to the Smug Lisp Weenie order, let me break with tradition and try to share my experience.

  1. Lisp is actually the most simple programming language I have ever learned. Bar none. And I have learned more than a few. The core of the language itself could be specified in just a page or two. Yes, really. If you don't believe me, go read my comments on John McCarthy's original paper describing, Lisp, Recursive Functions of Symbolic Expressions and Their Computation by Machine (Part I).
  2. Everything else in Lisp is a library. Learning a library in one language is basically the same as learning a library in another language. The core of common Lisp could be nearly as small as the core of Scheme (identically small?), but Common Lisp packs a larger standardized library (essentially the functionality of many of the Scheme SRFIs). The main difference between Common Lisp and Scheme is one of heritage: Common Lisp was evolved and Scheme was designed. Common Lisp carries 40 years of baggage. Scheme was able to buff-off some rough spots. If I was designing Lisp again from scratch, I'd probably take Scheme as a core and then add back in a bunch of good ideas from Common Lisp, resulting in something that looks a lot like Common Lisp, but with Scheme's cleaner lines. (Honestly, I love Scheme, too. I think a 50-page spec is pretty cool.)
  3. Everybody balks at the parentheses. Don't. Honestly, they're weird for about a week and then you start to see them as a virtue, not a vice. In fact, I love the parentheses now. Yep, read that again slowly. I love the parentheses. It isn't just that they fade into the background such that you don't see them. The parentheses help drive Lisp's ultra-powerful code = data dynamic, enabling a macro system far superior to any of the simplistic template languages in C++. They allow smart editors to easily move around s-expressions. In short, they're great.

In any case, Sriram's essay made me chuckle. It was a good piece of writing from the point of view of somebody struggling with whether to commit or not. Some of the comments also made clear that Lisp's status as a Secret Weapon™ is safe for some time to come.


Comments:


I'm just touching on the surface of Lisp. I've never programmed before.

What parenthesis do for me is that they allow me to think in graphical representations of boxes. Which makes it real easy to think in data, function, macro-structures.
To me it is the most visual language that I have seen and therein lies the beauty. At least for me.
 


Everyone claims that Scheme is the cleaner language, and most who try to design a new Lisp dialect start from something like Scheme. I don't understand that. I think the fundamental design decisions in Common Lisp are better than in Scheme, especially the preference for multiple namespaces (which introduces some redundancy but makes programming more straightforward, IMHO). Another good starting point for a new dialect could be ISLISP, which is much closer to, but also much smaller than, Common Lisp at the same time. Another of those mysteries, the fact that ISLISP is so underrated...
 


Good article. Another great thing about parentheses is that you can use structured editing packages to cut, kill, and move through whole expressions. There's none of this clumsy "delete the rest of this line" business. Instead, you can think of each expression as representing a concept in your program, and you can treat that concept as a first-class object - to be killed, yanked, or simply moved past. Plus, the regular syntax makes it easy for editors to do phenomenally good indenting.
 


I took a look at the original "Lisp is Sin" article and compared the code to the code you listed and it looks as if Sriram's template syntax is getting eaten by the browser, probably because it's coming through un-meta-quoted.

Maybe you need to supply the character-entity equivalents or something? Maybe blogger has facilities for this...I don't know.
 


"I think the fundamental design decisions in Common Lisp are better than in Scheme"

Add a new category of Smug Common Lisp Weenie. ;)
 


Thanks, Anonymous. I just forgot to convert the less/greater-than signs to HTML entities. Grrr... Roll the John Wiseman tape grumbling about HTML entities...
 


Pascal, I'd have to sit down and think about each feature individually. I think in some cases CL got things right that Scheme didn't (macros comes to mind). I don't know that I agree with you about namespaces, however. Current CL namespaces seems like a hack. I know you don't agree and I have seen the ll1-discuss arguments between you and the MzScheme module proponents. I don't know enough about MzScheme modules to know whether they are better, but I can't help but feel that CL's namespaces are a hack. Comments made by People Who Know seem to indicate that they are indeed a hack to basically allow mutiple programs to be loaded into the same Lisp image without symbol collision.
 


Dave, are you talking about packages or the separation of variable and function namespaces? I got the impression Pascal was talking about the latter.
 


Concerning Scheme vs Common Lisp, I have to agree with Dave. I like Common Lisp, but compaired to Scheme, Common Lisp just seems dirty, like a hack. Yes there are several places where I feel Common Lisp is better, but multiple namespaces (at least as it's implemented in Common Lisp) is one of the features I feel was a really bad decision. The whole idea of functions/procedures as first class objects is undermined by the separate namespaces for functions vs. other values. Not only that, but these separate namespaces end up adding extra cruft to the language that shouldn't be needed (funcall, #', etc.) Whenever I need a funcall, or #' I wish Common Lisp were a little more like Scheme in some respects.
 


Bill, yes I was talking about packages. Sorry, I should have been more clear and it looks like I misread Pascal's comment. If Pascal is talking about Lisp-1 vs. Lisp-2 namespaces, then yes, I think I agree with him. Originally, I found Scheme's Lisp-1 namespaces to be more "normal" but after using Lisp-2 for a while, I have found that it's no big deal and it's sometimes a help.
 


I think it's not hard to see why Scheme is generally considered cleaner than Common Lisp. Ignoring the size of the languages, the design goals the languages were created with show another large difference: Scheme was created with simplicity and a small core in mind, Common Lisp had to deal with a lot of historical baggage.
Regarding designing a new Lisp dialect: Don't you think it's much easier to design and implement a [mostly] R5RS-compliant implementation of Scheme than it is to design and implement a [mostly] ANSI CL-compliant implementation of CL? Even modifying/enhancing the language while ensuring that one doesn't break the spec (unwillingly) seems a lot easier to me for Scheme than for ANSI CL, if only for the size and complexity of the specification.
 


I think neither solution (CL vs. Scheme) is necessarily best. When I used Scheme, I strongly disliked the renaming, leading me to think Lisp-N is good. But that said, CL could stand to use nicer syntax for cases like this.

Tayssir
 


If I was designing Lisp again from scratch, I'd probably take Scheme as a core and then add back in a bunch of good ideas from Common Lisp, resulting in something that looks a lot like Common Lisp, but with Scheme's cleaner lines.

Just another data point from someone who's not a lisper. Scheme seems to be getting a little long in the tooth. I'd really like to see an s-expr lanugage which is small and has applicative-order evaluation like Scheme, but has a modern inferencing static type system like Haskell or Omega. And I also prefer it to be purely functional/referentially transparent (again like Haskell). That would eliminate the difference between let, let*, letrec, letrec*, named let, etc., but I'm not going to insist on that idea. Type classes are also nice, so we can unify eq?, eqv?, equal?, and "=". And I want to use it as a functional language, so it should be a lisp-1 language and support automatic currying. Also, let's eliminate historically crufty names like lambda and car/cdr/progn/setf. Pretty much I'm looking for a cleaned up s-expr Ocaml/Haskell hybrid with a little bit of Joy spice sprinkled on top for flavor (take a look at the Joy language to see a cleaner/simpler language than Scheme).
 


It might be that I'm spoiled by many
years looking at Lisp and Scheme code,
but his memoization example is just
horrible. At a first sight I have to look for the logic
behind the code in this jungle of keywords and funny brackets.

Sigh, even Perl is less distracting.

Pascal: regarding different namespaces: it's just baroque in a language where
code *is* data and results in things
like `flet', `function' etc. It's
distracting. But I prefer Common Lisp any day over C#! :-)
 

Post a Comment


Links to this post:

Create a Link

This page is powered by Blogger. Isn't yours?