Common Lisp is the best language to learn programming
carcaddar.blogspot.com
carcaddar.blogspot.com
Scheme isn't perfect, of course, and I'd love to see a modern Scheme-like Lisp with a canonical implementation and borrowing freely from Haskell, Erlang, and friends while preserving its minimalist ethos (somehow neither Racket nor Clojure is this).
Of course, the readiness is all ... while there's a beauty in simplicity, can a novice without any higher mathematics really appreciate the style of programming one does in Scheme?
I think that people think that imperative programming is somehow 'more natural'. I still sort of think that but, I haven't seen that bourne out when I try teaching programming.
All programming is foreign to people when they start. And you are influenced by what you start with.
I started with Forth ( ages ago ) and when I first started using an imperative language, it was a struggle for me.
Why don't you think Clojure meets those criteria?
- Canonical implementation on the JVM
- Borrows modern functional programming concepts from Haskell (type classes -> protocols, immutability, etc)
- Robust concurrency constructs. While not directly copied from Erlang, designed with clear understanding-of and respect-for Erlang's successes and failures.
- Minimalist standard library
The only thing I can think of that isn't minimalist would be the reader-macros for vectors, maps, sets, lambdas, etc. However, it seems like those serve to reduce confusion & strike a decent balance between uniformity of syntax and clarify of meaning.
- Clojure has these horribly huge Java stack traces when you hit an error. Newbies are going to run into errors frequently, and they don't know Java. Even I find this kind of frustrating when using Clojure (and I know Java), if only because it's annoying to have to scroll back just to read the error. This could change! I'm sure it will. But it's the state of Clojure today.
- Modern function programming and concurrency stuff isn't really necessary for beginners. Sure, teach them purely functional programming to start out with, a la SICP, if that's your thing, but I think that Clojure's concurrency primitives (various reference types, immutable data structures) are a bit too advanced.
Scheme is just ever so slightly simpler and I think that matters. Just my 2 c. I love Scheme and Clojure and Lisp, I'm just not experienced with teaching programming to total beginners, so take all this with a handful of salt. I tend to be conservative when it comes to these kinds of discussions and would be happy with new programmers using Python, because it's so much better than Java.
While newbies rarely need reference types (other than var, of course), I don't think there's anything particularly "advanced" about immutable data structures. Considering that most people learn math before they learn programming, immutable data might even be an easier concept to grasp for a complete newbie than imperative programming with mutable data is.
You might think immutability is advanced but that's most likely because you learned to program with mutable things initially.
As an aside, I agree that Clojure's stack traces are pretty bad, but there are tools that improve the mess quite a bit, eg. clj-stacktrace. The stacktraces might not be quite as intractable to newbies if you integrate that into the REPL.
Re: Stacktraces, they have nicer formatting at least, but cutting out irrelevant parts of stack is tough. You can also set
*stack-trace-depth*
http://dev.clojure.org/display/design/StacktracesAnyone can pick up Scheme syntax really fast. Where it gets difficult is when people start telling you to not use state, not change values of variables, and to stop using side-effects.
Most people have never done functional programming. How does one make the leap from imperative programming to functional programming?
Common Lisp code is much more portable across implementations so there are way more libraries and bindings to things like graphics and sound around (and easily available via quicklisp).
Racket OTOH is the best environment for learning to program in that I've come across, and I recommend it to people who ask me for advice about learning to program (despite being the author of that article). If Common Lisp had a similar environment for newbies it would be sweet, but not many people (myself included) care about Lisp IDEs.
The problem with Racket is that it has a huge problem with NIH as a project, and a lot of the libraries are opinionated about the way you use things like state.
Scheme is a little bit on the 'toolkit-y' side and slightly less accessible than smalltalk for someone just starting out but, both have what I consider most important:
a minimum of rules and syntax. anyone learning to programming in either would be primarily focused on how to solve the problem in front of them rather than solving the language.
This all said, I haven't tried this out in any scientific fashion so it is mostly just intuition.
This remains the biggest problem with places like HN. When everyone has a similar background, they can agree on conclusions that the rest of the world would find ludicrous.
I'm with you though. Lisp can be great for some problems but it's mostly not. The lisp guys hate hearing that and shout you down.
One measure of a language is how well it works to pass on a source base to a new team of programmers. I bet if someone were to go measure lisp against C they would find at least a 100x greater success rate with the passing on of C.
The lisp guys are profoundly focussed on how easy it is for them to write code. The real world is more concerned with how easy it is to maintain, review, enhance code.
I think this provides an interesting counterpoint: http://www.infoq.com/presentations/Simple-Made-Easy
I TAed intro CS in Java for a couple years and the vast majority of fundamental misunderstandings students had were caused by preconceptions and expectations of how things should have worked based on exactly this kind of previous experience. I think I spent at least as much time helping people un-learn things as I helped them learn novel concepts.
In the short term Java and C are friendlier, but this friendliness allows a student to put off confrontation with the essence of programming in a way lisps do not.
At my school, all engineering majors had to take freshman intro to programming in Scheme and it worked pretty well.
The important thing about learning to program is having an accurate mental model of what goes on in your program. C, and especially C++, make that much harder than it actually is and the way Lisp presents it.
(The reason I'm distinguishing between programming and CS here is that 'programming' is a broad term that encompasses a number of use cases. If someone wants to learn 'programming' to throw together a few simple webapps or do some text processing, Lisp will get the job done, but they probably won't care too much about learning these fundamentals).
Teaching students assembly as their very first language seems akin to teaching students Latin before they can learn French, German, Spanish, etc. Sure, it's helpful and...IF they get pass that first dry session.
Seems like that should qualify as comparable.
That's not to say you couldn't learn lisp first and assembly later. But that seems like the hard way to me.
I see CS as basically dual-grounded: everything is ultimately just syntactic sugar on machine code, and everything is ultimately just syntactic sugar on lambda calculus. Which reduction makes more sense depends on what you care about; the bare-metal view comes into play more when you're talking about low-level performance, while the mathematical view comes into play more when you're talking about algorithms and correctness. I guess it can get into some philosophical debate about which reduction is more "real"...
I'm not entirely sure which way is easier to start from. The argument you make here, that students have trouble going from mathematical abstraction to bare-metal implementation, is probably true; but I think students who first learn on asm and C also have trouble going the other way, from thinking about executing a series of instructions to thinking about enacting computations. That's one reason there's been some experimentation at places like MIT and UT-Austin with not starting with an imperative language, which they feel is very hard to get people off of once they've started with it.
For example, learning manual memory management and instilling habits around needing to worry about this made learning Java and C# a breeze. I can't imagine moving from a language with garbage collection to C would be as easy or smooth.
The execution model behind Lisp is trivially simple compared to C which makes the corresponding mental model of what your program is doing simpler.
As for what goes on "under the hood," SICP builds a virtual register machine and a Scheme compiler for it in one chapter. Find me a C book that does the same.
But you don't even need a chapter. Abdulaziz Ghuloum shows how to build a Scheme to x86 native code compiler in 10 pages: http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf
Edit: To the downvoters (and feel free to keep downvoting, if that rocks your boat): the "+1 for Python, because" comments were as empty as this one, and less warranted at that.
Ultimately where you start isn't as important as where you go. It's just a matter of picking a language, any language, some books, and shutting your ears down to everyone telling you that it doesn't get any better than that.
This seems to imply there's some kind of benefit to only learning a single language, which I don't understand at all.
I adore Clojure (and Common Lisp to a lesser extent), but getting a new person excited about programming is far easier when they can do something useful really quickly. Python's massive collection of libraries makes that easy.
JavaScript is the language the modern web is written in and it's a language you can use to build and automate cool stuff that you can show immediately to your friends. You can build interactive programs, save state (in cookies), deal with formatting and input, and even do graphics with CSS or canvas. jQuery or its competitors will cover up most of the warts.
It's not a brain dead verbose bondage experience like Java nor deep in the metal like assembler. It isn't historic and systems oriented like C or mathy and abstract like Scheme or LISP. It can take advantage of much of the semantics of those languages as you learn it if you need them.
The tools to write and run it are simple and some good debuggers are built into your browser. Everyone owns a few client interpreters with a great application environment.
It's not pretty (boy is it ever not pretty) but JavaScript is the best language to start with.
If I couldn't choose JavaScript, I'd point my friends at Python or Ruby. They're better languages for both beginners and experts but they're not JavaScript.
There's a place for command-line programs, but it isn't at the very beginning. JavaScript is great not only because it lets you start with concrete stuff immediately, but it's stuff you're already familiar with: everybody uses the internet now. I also found the basics of HTML much easier than any other UI framework I have ever used (Swing, WPF and TK mostly).
All of this is coupled with the fact that, ultimately, JavaScript is a really nice, really expressive language, also makes it my choice for a first language.
However, if not for JavaScript, I probably wouldn't point people towards Python/Ruby so much as Logo, which has many of the advantages of JavaScript and is well regarded by CS educators.
I agree that javascript is very easy to get started with. The syntax is similar enough with other languages (C, Java) such that you could just into one of them easily after a bit of experience with javascript. It's also very easy, as you said, to actually DO something with it. You don't have to import 500 libraries to draw a line on the screen or make highly interactive (or even beautiful) interfaces. Javascript is also somewhat close to lisp in its functionality.
That being said, I feel as though learning javascript first is putting the carriage before the horse. If someone is learning to program, I believe it's best they start off learning the basics. The idea is to learn the concepts behind mathematical thought...to learn the rules, and then learn to break them. I think someone who learned javascript first would know how to do things great in javascript, but not necessarily any other languages. They would know how to program interactions, but not necessarily how to program in general.
Another thing to keep in mind is that javascript is highly concurrent. You almost can't do anything in it without dealing with layers of events interacting with each other. This could be confusing and detrimental to someone who's just beginning to learn.
I'd argue it's best to start with C/assembly for a low-level view of how computer work, and then afterwards lisp and perhaps javascript for higher mathematical programming.
Why do you think that Common Lisp (LISP) is abstract?
HTML5 Canvas is also awesome - IMO it's the most convenient way for beginners to do computer graphics in any "real world" programming environment/language.
I think one of the biggest problems with advocating Python as a teaching language is that programmers don't understand what the hard parts of Python are. Python is great because it's sort of a lingua franca for people who are well-versed in conventional, Algol-based imperative programming—it boils it down to its essence and omits anything unnecessary—so to a person who was versed in Java/C/C++/Perl/PHP/&c previously, moving to Python feels like everything unnecessary has dropped away. Consequently, it feels easy, and you look at it and think, "Oh, wow, this would be no big deal to teach someone, even a non-programmer."
In reality, though, you'd be surprised at the concepts people struggle with. Assignment poses a huge problem to beginners, and I have spent hours and hours of my life trying to explain the concept to baffled undergrads. Not that Scheme concepts are necessarily easier (e.g. recursion—although loops are not necessarily easier to a beginner) but that Scheme makes a point to have far fewer of those concepts to begin with. Keep in mind that in an introductory class, every new feature, no matter how small, can mean another week of instruction, which is why an intro class in C++ could mean almost no projects at all, but an intro class in Scheme could very easily give way to writing object systems, programming languages, and adventure games, as my first computer science class—using Scheme—did.
People who taught themselves to program often have a hard time understanding what novices find difficult. The one that gobsmacked me -- and I only ever ran into this when teaching Pascal -- was twofold: one, that the computer does things in the order they are in the program, and two, that the definition of a function or procedure does NOT execute the function or procedure. Something about Scheme made the distinction between "we are defining a function" and "we are executing a function" much easier to understand.
And I concur about the terseness of Python. I've been using Perl professionally for, um, 15 years now (and I just dated myself again). I've written a few toy programs in Python, enough to establish that it's a worthy programming language.
But the pedagogical problem is that there's a lot of depth under the surface of Python (Perl, PHP, Visual Basic) - a lot of things going on that the experienced programmer understands and that the novice programmer needs to. It's often easier to learn in languages that have less going on, because the programmer needs to do more explicitly.
Of course, this is becoming less of an issue in Common Lisp thanks to QuickLisp. There's a Racket book coming out next year, which might help with adoption and result in better libraries. Still, it will take years before any of these languages catch up to Python/Ruby/Java.
Edit: I thoroughly enjoyed learning and playing with all three languages. Smalltalk, in particular, felt very natural. It has the eerie property of seeming like an extension of your brain.
While you're not going to write my-first-blog in Logo, it's something my 5 year old can get her head around. And it's the thin edge of the lisp wedge :)
Sounds like it needs more extensions.
It was awesome. It was a long learning curve, and I couldn't do almost anything for a really long time, but I got to a point where I knew everything about this tiny universe and had a solid foundation to branch out from. With that I went on to learning java, python, js, and c, and became fascinated at how much faster things became as I used more state and therefore got closer to the hardware.
For a while I was a little worried that I would only be able to use functional programming and would not be able to learn how to use state, but that was not the case.
Languages are tools, people learn differently, there is no best way.
If there was though, it'd be Ruby. ;)
Ruby is a very good choice for sure. Between the two(CL or Ruby) I don't know which one I'd pick. I guess ruby has a little more practical aspects to it. Lisp has some advanced features that could be used for more advanced students.
I know you're being tongue-in-cheek with that, but I think there are three distinct use cases for learning to program.
For people who want to learn CS from a ground-up, theoretical foundation, Lisp is a nice choice. It is very easy to teach functional programming while simultaneously teaching the fundamentals of theoretical computer science, so you get the best of both.
For people who want a bit more 'traditional' approach, and also want to learn about computer science from a low-level perspective, C is a good choice. It teaches memory management and gives an insight into computer hardware & systems that higher-level scripting languages don't. (This latter part is where Java fails - how can you appreciate references and garbage collection until you've mucked around with pointers and malloc() in C?)
For people who just want to dabble in programming, or for people without a mathematical background, or for people who just want to prototype small projects quickly... then yes, scripting languages like Ruby (or Python) would be the 'best' way.
As you said, languages are like tools, but I think these three categories of tools cover the majority of use-cases nowadays for the beginning programmer.
Still, I agree that something like Python is a very suitable language for somebody who just needs to simplify their lives. (At my old school they've switched from Pascal to C# now... why?)
"[Bernie Greenberg] wrote a version of Emacs in Multics MacLisp, and he wrote his commands in MacLisp in a straightforward fashion. The editor itself was written entirely in Lisp. Multics Emacs proved to be a great success — programming new editing commands was so convenient that even the secretaries in his office started learning how to use it. They used a manual someone had written which showed how to extend Emacs, but didn't say it was a programming. So the secretaries, who believed they couldn't do programming, weren't scared off. They read the manual, discovered they could do useful things and they learned to program."