A Lisp tutorial

Started by
18 comments, last by chollida1 17 years, 11 months ago
For a long time now, on and off, I've been writing a Lisp tutorial for regular programmers. The idea was not to explain intricate details of Lisp, but help people understand what exactly the nature of the language is, and why some of its features are great for modern software development. I'm very interested in feedback so I can improve upon the tutorial and explain things people still don't understand. You can read it here.
Advertisement
It's looking good. I can't say I agree with your conclusions about lisp macros, but it was still a good read, nonetheless :)
Well since I'm learning Scheme and it's closer to Lisp then C++ [smile], I'm definitely gonna read the rest of your article!

Two suggestions: 1) Could you break the text into pages? Unfortunately, it seems like long unending text (sorry I have some sort of reading ADD). 2) When comparing or transforming XML or Lisp to another language is there a way to have the two pieces of code closer together either by clicking a link that shows a pop-up of the two piece of code or some &#106avascript that opens source code box when clicked.<br><br>Thanks. <br><br>It's a great read!

Beginner in Game Development?  Read here. And read here.

 

You should be clear about what dialect of lisp you're using. When people say 'lisp' without qualifiers, they usually mean the Common Lisp standard. But your example code is not Common Lisp compatible, so you must be using something else. You're not using R5RS scheme either.

You talk about built-in functions head and tail. They aren't built into either R5RS scheme nor into clisp.

In most lisps, your head and tail functions are called car and cdr. Let's try your example code in scheme:

Language: Textual (MzScheme, includes R5RS).
> (head '(* 3 4))
reference to undefined identifier: head
> (car '(* 3 4))
*
> (tail '(* 3 4))
reference to undefined identifier: tail
> (cdr '(* 3 4))
(3 4)

and in common lisp:

[1]> (head '(* 3 4))

*** - EVAL: undefined function HEAD

Way to really confuse a newbie.

If I were you, I'd use built in functions in my examples that are actually built into the popular lisps.
You write:

"At this point something must smell wrong. If we can assign strings and integers to symbols like *, how does Lisp do multiplication? After all, * means multiply, right? The answer is pretty simple. Functions in Lisp aren't special. There is a data-type, function, just like integer and string, that you assign to symbols. A multiplication function is built into Lisp and is assigned to a symbol *. You can reassign a different value to * and you'd lose the multiplication function. Or you can store the value of the function in some other variable. Again, using pseudo-code:

*(3, 4) // multiplies 3 by 4, resulting in 12
set(temp, *) // symbol '*' is equal to the multiply function
// so temp will equal to the multiply function
set(*, 3) // sets symbol '*' to equal to 3
*(3, 4) // error, symbol '*' no longer equals to a function
// it's equal to 3"

Something does indeed smell wrong: this actually is NOT what happens in standard Common Lisp and in many other lisp variants:

[31]> (* 3 4)
12
[32]> (setf * 3)
3
[33]> *
3
[34]> (* 3 4)
12

Because Common Lisp and many (most?) other lisps have separate function and value namespaces, you can comfortably assign values to symbols that also denote functions (the * and + symbols' value cells are used by the top-level REPL, so be careful because the values in them WILL be modified by interacting with the toplevel).

That is, a given symbol can have an associated value (which can be a function!) AND an associated function AT THE SAME TIME. Depending on use, the value is looked up in either the function namespace or the value namspace. This is why this works in Common Lisp, contradicting what you wrote in the tutorial:

[56]> (defun test () "I'm in the function namespace!")
TEST
[57]> (setf test "I'm in the value namespace!")
"I'm in the value namespace!"
[58]> test
"I'm in the value namespace!"
[59]> (test)
"I'm in the function namespace!"

This doesn't work in scheme and other lisp-1s, but does in ansi standard Common Lisp and other lisp-2s.

If anyone following your tutorial was using a standard Common Lisp implementation, you'd have confused them beyond repair, because their lisp doesn't do what you say it does. They read your footnote:

"Lisp has many different dialects (the most popular of which are Common Lisp and Scheme). Each dialect deals with intricate details differently yet shares the same set of basic principles. Since the goal of this article is to give you an understanding of Lisp's principles I will use Blaise for examples (which at the time of this writing is vaporware). With some minor modifications these examples can be translated to other Lisp dialects."

and think your examples can be translated with minor modifications. But your explanation of how 'lisp' in general treats variables is actually completely opposite to how Common Lisp actually does treat them!

I think this tutorial is more confusing than helpful.
Quote:Original post by Anonymous Poster
I think this tutorial is more confusing than helpful.

I actually gave this a lot of thought. When I started out with Lisp I had a few immediate issues with the language: parentesis, stupid (from my perspective at the time) function names, weird symbols (#' for example). I found that many people I spoke with had the same issues.

I tried to create an introduction that will help people understand what Lisp is about (at least partially), without stumbling into these issues. That's why I chose an imaginary dialect. Naturally parentesis needed to be explained but I saw no reason to keep unfamiliar function names and symbols.

You can't satisfy everyone. Some people will find it confusing, others will find it helpful. I'll likely add a Q&A section at the end of the article that clarifies many of these issues.
You wrote:

"You can't satisfy everyone. Some people will find it confusing, others will find it helpful."

You've certainly set a high standard.

You first write examples in some weird pseudocode which uses 'set' instead of typical assignment operators (eg = or :=), but looks more or less traditionally algol-like. This arbitrary syntax of yours is supposed to make it easier for readers, because of course it is simpler and more regular than lisp function application syntax. Yeah right.

THEN you write example code in some OTHER pseudocode, which is lisp-like and looks EXACTLY like Scheme only with different function names. Making up your own function names is important, because god forbid that your readers actually try out your example code in a real lisp system and play around with the language. So your readers can't actually execute your example code, because you like your own function names better. I'm sure your readers will find that convenient.

You explain how assigning a value to a variable will overwrite the function the symbol stands for. That's nice, only it's

1) completely incorrect as far as Common Lisp and many other lisps are concerned.

2) thus NOT a feature of 'lisp' in general.

You go into this at length.

Inexplicably, you fail to mention the cons cell, which probably IS one of the defining features of any lisp and is the data structure on top of which lists are built.

You fail to mention the notion of binding as opposed to assignment, which imperative programmers might like to read.

You fail to give examples of higher-order functions. One of the great features of the language.

You seem to think that if concepts require more than a few paragraphs for explanation, it's safe to gloss them over. So an overlong HTML page with no cohesive structure suddenly becomes a 'tutorial'.

So at the end of this 'tutorial', your readers can't even write "hello world" in any typical lisp dialect, let alone understand how they'd implement the map function.

A tutorial is something that teaches you how to do something. I'd either tone it down and call that a 'lisp advocacy paper' or hunker down and make it worthy of the name 'tutorial'.

And yet you have the gall to say:

"Even though in Computer Science terms Lisp is an ancient language, few people to date figured out how to teach it well enough to make it accessible."

That's amazingly insulting. You write a barely coherent lisp advocacy ramble and suddenly feel you have the authority to criticize people whose shopping lists are likely more informative than your 'tutorial'.

See, for example, for scheme, the brilliant and VERY accessible SICP:

http://mitpress.mit.edu/sicp/full-text/book/book.html

or the even more accessible (but more boring imo) htdp:

http://www.htdp.org/

or lisp for programmers:

http://www.gigamonkeys.com/book/

a personal favorite, but maybe not as accessible:

http://www.paulgraham.com/onlisp.html
Quote:Original post by Anonymous Poster
Making up your own function names is important, because god forbid that your readers actually try out your example code in a real lisp system and play around with the language.

It's explicitly stated that the dialect is imaginary. Furthermore, it's explicitly stated that the goal is not to teach a particular dialect of Lisp, but to explain some things that make Lisp great. The examples and arbitrary syntax was chosen for that purpose.
Quote:Original post by Anonymous Poster
Inexplicably, you fail to mention...

I can't mention everything in the chosen format. This wasn't really a book.
Quote:Original post by Anonymous Poster
So at the end of this 'tutorial', your readers can't even write "hello world" in any typical lisp dialect, let alone understand how they'd implement the map function.

Teaching people how to write a "hello world" program or how to use a map function wasn't the goal. It is stated explicitly. Other people have done that already, there was no reason to repeat the same information. You're clearly not part of the target audience. You can't be all things to all people.
Quote:Original post by Anonymous Poster
That's amazingly insulting.

No it isn't. These resources fail to relate to imperative programmers and the world they live in. If they did, you wouldn't hear complaints that Lisp is hard to get into all over the web.

Why the insulting tone? I try to help people and ask for nothing in return. At worst, the tutorial is garbage and it won't teach anybody anything. So what? There's no reason to get angry. Lighten up [smile]
You wrote:

"It's explicitly stated that the dialect is imaginary. Furthermore, it's explicitly stated that the goal is not to teach a particular dialect of Lisp, but to explain some things that make Lisp great. The examples and arbitrary syntax was chosen for that purpose.

...


Teaching people how to write a "hello world" program or how to use a map function wasn't the goal. It is stated explicitly. Other people have done that already, there was no reason to repeat the same information. You're clearly not part of the target audience. You can't be all things to all people."

Then I'd suggest you don't call it a tutorial. It doesn't actually help you how to *do* anything with lisp.

I still think your choice of two more levels of indirection (your two pseudocodes) is very ill-advised. The lisp REPL is one of its strengths; use it to your pedagogical advantage. The lisp syntax's incredible simplicity and regularity can be a strength when teaching it; use it to your advantage. Lisp syntax is simpler than your arbitrary pseudocode syntax; explain it clearly at first and just stick to it.

You wrote:

"I can't mention everything in the chosen format. This wasn't really a book."

I feel you introduce trivial and misleading detail (the whole overwriting variables bit) at the expense of important and essential details.

You wrote:

"No it isn't. These resources fail to relate to imperative programmers and the world they live in. If they did, you wouldn't hear complaints that Lisp is hard to get into all over the web."

Or not. I do not know the reason for lisp's lack of popularity and why so many people dislike it. I suspect you don't either. It has been discussed by people more knowledgeable than me ad nauseum. Maybe it IS harder to get into. Maybe it just doesn't appeal to some people on a basic level. Maybe the syntax puts people off.

In any case, hazy claims demonstrated in a make-believe language are hardly going to sway imperative programmers if the Practical Common Lisp book didn't. Even Haskell is more pragmatic than your imaginary language. This is why I find your claims of inaccessibility ironic and offensive to authors who I consider paragons of clarity of exposition and lucidity in comparison. That made me angry and insulting, and I apologize for that.

You wrote:

"I try to help people and ask for nothing in return. At worst, the tutorial is garbage and it won't teach anybody anything. So what?" I fear that someone will read your 'tutorial' thinking it is one, wonder why none of it seems to help him actually DO anything in a lisp, and conclude that lisp is not for them.

I worry about your general claim of how lisp handles assignment to variables. No information is better than wrong information.

Sorry for the insulting tone. My brutally honest opinion is that your tutorial as it stands is useless advocacy at best and dangerously misleading at worst. I say this now without meaning to offend, but it is genuinely my opinion.

I suggest you ask yourself: what new concepts has a reader of your 'tutorial' LEARNED? Not what concepts have been mentioned or hinted at. What concepts have been well-enough explained to stick in a readers' mind. When programming, concepts usually do not stick well unless one codes them up oneself.

What precisely can a reader of your article DO after reading it that he couldn't do before? Why should an imperative programmer be swayed into lisp by an article that doesn't actually teach him how to DO cool stuff? Stuff he can try out at the REPL while reading the article and modify and experiment on.
* I think it'd be a good idea to include a paragraph (or table) that maps your psuedo-language to Common Lisp or Scheme. That way, somebody that goes from your article to a language tutorial won't be completely lost when they don't see any of the names you used.

It might also be a good idea to change "tail" to "rest" or something equivalent, since IMO tail has the connotation of returning the last element. "Tail" makes sense if you're working with cons cells, but you don't mention them in the article that I see.

You might want to mention that operators are normal functions in Lisp before you start using "set", since it could help some understand why you left behind the assignment operator. I know you mention it just afterwards, but maybe changing the sentence "Assume that a function set assigns some value to a symbol (like = does in Java or C++)." to "Lisp doesn't have operators in the same way other languages do, so instead of using the = symbol for assignment, it has a 'set' function that does almost the same thing. For the next code segmentt, we'll use a set function but with a syntax closer to C++ and Java." or something to that effect.

* Also, I didn't notice any explicit warning that the dialect was an artificial one created solely for this tutorial, though I did find the small footnote mark after explicitly searching for it (after reading this thread). Perhaps you should include a sentence in the text saying that it's a made-up dialect or put the footnote somewhere other than the end of the paragraph where it's more likely to be noticed.

* Aside from 'language correctness' (meaning your dialect differs in IMO significant ways from Common Lisp and Scheme), I think it's well done and might help convince some people to seriously look into scheme or lisp. Don't forget that the Lisp community is rather elitist, so criticism might be harsher than otherwise deserved.

Minor corrections:
"time-two(5)" should be "times-two(5)"
"rip the benefits" should probably be "reap the benefits"

* Overall, Nice Work =-)
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk

This topic is closed to new replies.

Advertisement