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?
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
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.
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.
Anyone 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?
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 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.
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:
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.
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.
(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).
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.
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.
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
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.
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.
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.
Why do you think that Common Lisp (LISP) is abstract?
This seems to imply there's some kind of benefit to only learning a single language, which I don't understand at all.
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.
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.
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. ;)
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.
"[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."
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?)
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.