I chose Scheme over Common Lisp
I know this may seem like heresy, but it’s the truth. A few weeks ago I made the choice to move from Common Lisp (I had been using the Allegro implementation for about 2.5 years) to PLT Scheme.
I don’t want to go on and on like I know have reached some level of enlightenment that CL users haven’t, but I would like to briefly list some of my feelings about the switch.
What I like better about Scheme even though I once mentioned it as a reason why I wouldn’t
- Functions and variables in the same namespace
This always seemed like the move from a Lisp-1 to a Lisp-2 was a positive thing. You wouldn’t have to worry about having a variable that clashed with the name of a function, but it seems like was only an issue of having way too many functions with crazy names all over the place. The big problem that it creates is that you have to use FUNCALL to execute a function store in a variable, you have to use #’ to pass a function to an applicative, and you have to treat functions different than variables in general. (If you want to see something really scary try looking at the Y Combinator implemented in Common Lisp)
I’ve found that in Scheme my code is more elegant, tends to be far more functional and the only real concession I’ve had to make is that i can’t call a variable LIST (like any one ever actually does that, even in CL people use LST or LIS).
I should also mention that I’ve read that as of R6RS Scheme will be case-sensitive by default, which would allow you to use case conventions to separate variables from functions if you so desired.
- The define syntax
Whenever I used to try and read Scheme code I found myself overwhelmed by the define statement. Not only was it significantly different looking that the defun, defparameter, and let statements that I was used to, but that they were used differently, they were nested all over the place, functions created inside other functions and other odd things that made my brain hurt.
As it turns out, for me, using (DEFINE (square x) is way more natural for lisp than (defun square (x), since in the end it’s the same syntax as that way that you call the function. Also by using Swindle (an add-on to PLT-Scheme) you have the syntactic-sugar available for currying.
(define ((add a) b) (+ a b))
winds up being compiled to
(define (add a) (lambda (b) (+ a b)))
Like I said above I find now that my Scheme code is way more functional than my CL code ever was and I think this is a big part of it, I wind up using recursion and folds all the time instead of the doTimes, doList, while and loop constructs that I used to use. As much as this was a bit hard to get used to, it wound up being way more readable and concise than the iteration constructs.
Ever since I heard of continuations I was intrigued, but they aren’t available in CL. All the reading that I did as to why mentioned that the reason for this is that it was essentially a GOTO statement, and that THROW and CATCH were available. Also, the feeling that I got was that unless you’re doing a continuation-based webserver that they are just an interesting toy that’s fun to play with.
Turns out that I find it hard to believe that I lived without continuations before (the same feeling that I had when I discovered closures). The AMB and AMB-COLLECT macros wind up being particularly useful for permutations. The following code collects a list of all lists with lengths from 1-4, where each item in the list is 1-4.
(define (make-list n)
(if (positive? n) (cons (amb 1 2 3 4) (make-list (- n 1)))
(make-list (amb 1 2 3 4)))
this is pretty cool too.
(define (between a b)
(if (<= a b)
(amb a (between (+ a 1) b))
(let ((a (between 2 9))
(b (between 2 9))
(c (between 2 9)))
(amb-assert (= (+ (* a a) (* b b)) (* c c)))
(list a b c))
The only other thing that I going to mention is that I really enjoy APPEND! being the destructive version of APPEND instead of the CL NCONC, there are tons of examples like this. These kinds of decisions made by the Scheme crowd actually make a ton of sense, where as when trying to learn CL was kind of like memorizing history.
The only thing that still bugs me about Scheme is the separation of #f from NIL. I know I shouldn’t have a problem with this since it makes tons of sense, but it still bothers me that when I’m using recursion, instead of (IF LST , I’m forced to write (IF (NOT (NULL? LST)).
That’s all I have for now. Let the angry comments begin.