Lisp after Python after Lisp.


(Or, Python vs Clojure rant)

This post assumes some familiarity with Lisp and Python from the reader.

Like loads of programmers, I have read most of Paul Graham’s essays, and I always finish them with that feeling that if I’m not using Lisp then I must be an idiot. Like most programmers, I certainly don’t want to be an idiot, so I went ahead and learned Lisp, Common Lisp.

At first, I was horrified by all those damned parentheses. Still, I kept at it until I was able to write code half-decently. I didn’t get very far, and truly diving into Lisp was buried deep into my to-do list.

I didn’t really got Lisp until I learned about Clojure.
Clojure is a new functional Lisp that runs on the JVM. It is a great language with brilliant design and it has the potential to bring some great research ideas into the mainstream.

Learning Clojure has gotten me to really appreciate Lisp for what it is.
Some months ago I wrote about how I loved LINQ. With Lisp, I can’t complain if I don’t have LINQ, I can just write a macro to implement it.
I understand that when I’m writing Lisp code, what I am writing is an abstract syntax tree (AST) in human-readable form. You can see code as the very data structure that represents your program, and you can modify it as such. That is why Lisp must be just the perfect language for Genetic Programming, where code needs to modify itself.

I love the fact that in Lisp everything is an s-expression. S-expressions have an advantage that I hadn’t anticipated. They make editing easier in an editor like Emacs where you have commands that explicitly handle sexps.
Editing Lisp inside Emacs, after a while, is a very enjoyable experience. You can transpose,kill,navigate through and mark sexps as if they were letters or words. And since everything in Lisp is an s-expresion, it becomes very malleable.

So, after having my Lisp epiphany, I started seeing Python through a new light. I saw that Python was just like Lisp in so many ways, yet it was different in many others.

Python is dynamic and has a REPL. Both are huge advantages that Lisp has had for decades.
In Python, there is a difference between statements and expressions. This was my first big no-no on my comeback to Python.
I would like to write something like this:

a = if (x == 2):

Lisp code is elegant, and Lisp as a language is mathematically beautiful. It is also true that once you get used to all the parentheses you start not to notice them. However, Lisp is just not as pretty as Python. There’s only so much you can do when your language requires the programmer to write the AST directly.

Python has the most beautiful syntax I have yet to see. Letting whitespace have syntactic meaning is a great design decision. The resulting code is indented the way people should indent their C-style programs anyway.
I have found downsides to this approach. In programs with lots of consecutive, horrible OpenGL API calls, things would look prettier if the language would let you indent at will. 99% of the time, however, it is a feature rather than a bug.

Every programmer has some personal pseudocode. This pseudolanguage is the language we think in. Python is as close to most programmers’ pseudocode as you can get. I get this warm, fuzzy feeling when I code in Python. Its philosophy dictates that programming is so hard that the language should really just get out of the way of the programmer.

Programming in Clojure has definitely changed the way I program. More thanks to the fact that it is functional than to the fact that it is a Lisp. After you pass the brain-freeze that is inevitable when dealing with lack of state, you reach a point of enlightenment. That is that you realize that programming functionally frees you from worrying about post-conditions and pre-conditions. It is such a nice feeling when you know that a function isn’t really changing the world, that it will change the way you code in other languages. Being stateless lets you stop worrying about a huge set of problems. It makes you smarter, since you are keeping less things in your head, and it reduces the bugs you can create. I am not saying you’ll absolutely loathe state after spending time with a functional language. I love a for loop as much as the next dude, I am saying that you will avoid state when you can. I agree with Tim Sweeney in that the functional paradigm should be the default. And that modifying state should be made explicit. I think this concept is present in Clojure’s STM approach, although it hasn’t really been proven effective in huge, complex applications.

I still prefer to code in Python than to code in Clojure, just like I still prefer to speak in Spanish, my native language, than to speak in French.

When I code in Lisp, I write pseudo-code that is pretty similar to Python and then I translate to Lisp as I write. Yet now, when I’m writing in Python, I often say “This would could be easier to express with Clojure”. I would like to know if my pseudolanguage is a product of having been exposed to imperative programming all these years. I don’t know if there are programmers out there whose pseudo-language is functional. Maybe it’s just human nature to think imperatively.
If my pseudolanguage ever starts to look like Clojure, I guess I’ll have my answer


16 thoughts on “Lisp after Python after Lisp.

  1. The new ‘with’ keyword may help out with those piles of OpenGL API calls. if true: is also a simple semantically null way to let you indent a level.

  2. this works in python:a = (“Hello” if x==2 else “Goodbye”)but generally your point is true. the one line limit on lambdas is a pain. one thing I like that you may not do is for a one line function definitionfn = lambda x: x*x – x + 1

  3. w.r.t your pseudocode question, Haskell is fairly similar to pseudocode, at least once you learn Kaskell. I’m a lisper, btw, first and foremost.

  4. I just found out that my article is on Hacker News =D That’s awesome, thanks to the wave of visitors. Subscribe to my blog! Expect more posts like this in the future.pjz: Thanks for the tip!kib: Then you feel my pain =). I’m glad you liked it!notaddicted: I actually don’t mind the lambda limit much since you can define new functions inside other functions.nyaj: I like Haskell a lot. In the first draft I actually said that my pseudocode is a haskelly python. It may be a sign that my brain is starting to think functionally

  5. My pseudo-Language allways has been functionnal (something between Ocaml and Haskell). My problem is translating it to C++ at my day Job. Have you ever tried to do algebraic datatypes in C++? You know, these tagged unions of sorts.Knowing a functionnal language may have expanded my mind. Anyway, it did expand my sorrow.

  6. You might want to give ruby a go as a way of making your pseudocode more functional. The syntax of ruby and python is very similar. It allows more functional constructs than python however. For example, this is valid ruby code, and works as expected:a = if (x == 2) then “hello”else “goodbye”endAlso, blocks allow you to easily pass anonymous functions to other functions. For example:[1,2,3].map {|x| x * 2 }Ruby also makes some distinction between side effect free and normal code. Functions with side effects often have a ! and the end of the name. Ega = [10,100]puts {|x| x + 1} # [11,101]p a# [10,100]p! {|x| x + 2}# [12,102]p a# [12,102]Ruby does have its problems though, mainly poor documentation, some syntax issues, a slow interpreter, and less libraries than python. If you’re looking for a more functional pseudocode language though, it might be the way to go.

  7. It’d be interesting to see if those that learned programming in Scheme (most common of the Lisp family for teaching) write pseudo code in Lisp instead of an imperative-like form.I’d guess that pseudo code is like math and dreams; people tend to use their most native language (though in pseudo code people probably match paradigm and short-hand it a bit, since that’s the point).

  8. It’s interesting to know the common mind effects that code-jamming in Lisp causes in other people! Experienced quite the same here, with Peter Seibel’s PCL, SICP and now Clojure.Nice that you read Tim Sweeney’s mainstream programming languages paper! I’ve written an Essay inspired on it :) stuff btw!

  9. Thanks for all the comments!There seems to be people whose pseudo-language is functional. Good to know.I will try out Ruby in the near future, but right now I am very excited about Clojure and I’m concentrated on being able to think in lisp and to think functionally. Every day it is getting more natural.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s