• Advertisement
Sign in to follow this  

A Lisp tutorial

This topic is 4309 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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 javascript that opens source code box when clicked.

Thanks.

It's a great read!

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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.

Share this post


Link to post
Share on other sites
* 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 =-)

Share this post


Link to post
Share on other sites
Quote:
Original post by Alpha_ProgDes
[...]Still kinda fuzzy on the macros though.
Macros are like functions in a time accelerator - they're just regular code that is evaluated in the regular way [1], but they're evaluated earlier (at compile time, instead of during program execution).

For a macro to be useful, it has to have output of some kind. There are many options - since macros consist of Lisp in it's entirity, you can do file input and output, console input and output, etc. The most common use of macros, though, is to take some data (parameters or a file) and use that information to create code.

A macro returns code (as a quoted list), and the compiler pretends there never was a macro call and compiles the returned code as part of the program (just as if you had typed that code there instead of the macro call).


For example, "back in the day" when floating point was so slow that it was avoided at almost any cost, one use of a macro could have been to generate a table of trigonometry values in fixed-point format. Then put a call to the macro in a statement like (setf Trig-Table (GenerateTrigTable)) and when the compiler actually compiles it, instead of a call to generate the table (if it's a macro) the table itself would be generated at compile time and put in that place.

Lets say your Lisp compiler wasn't so great (and they weren't for a long while) and didn't do much optimization. You could create macros for mathematical functions such as Sine() and Cosine() that tests what type the argument is. If it's a constant number, the macro could calculate the appropriate value at compile time and insert it instead of a function call. If it wasn't a simple number, the macro could insert a call to the appropriate function.

If you wanted to use trig tables, you could make your 'trig optimization macros' replace Cosine with a call to Sine (with an appropriate adjustment in the angle) at compile time (and you wouldn't need to worry about whether or not the compiler optimized 'wrapper functions' away or not).

[1] Macros don't evaluate their parameters automatically. If you want the parameter evaluated, you can do so yourself using 'eval'. This means that any list passed to a macro is basically quoted automatically.

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrarius
[1] Macros don't evaluate their parameters automatically. If you want the parameter evaluated, you can do so yourself using 'eval'. This means that any list passed to a macro is basically quoted automatically.

hmmmm. i guess this is where the AP's complaint holds some water. I thought I read in the article that the quote (') kept the list from being evaluated and the tilde (~) forced evaluation.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Alpha_ProgDes wrote:

"hmmmm. i guess this is where the AP's complaint holds some water. I thought I read in the article that the quote (') kept the list from being evaluated and the tilde (~) forced evaluation."

I didn't complain about the macros. In fact, I didn't even get to that part.

Usual syntax in macros as I know it (tilde I've never seen to work that way):

quoting a list stops everything in it from being evaluated. The functionality of his quote and tilde is usually provided by backquote ( ` ) and comma ( , ). comma-at ( ,@ ) splices a list into another one:

[67]> (defvar alist '(1 2 3))
ALIST
[68]> (defvar x 5)
X
[69]> '(x x alist)
(X X ALIST)
[70]> `(x ,x alist ,alist)
(X 5 ALIST (1 2 3))
[71]> `(x ,x alist ,@alist)
(X 5 ALIST 1 2 3)

Share this post


Link to post
Share on other sites
Good write up. It sounds like your well on your way to understanding lisp:) Have you read Paul Grahams's ANSI Common Lisp?? I found that to be the most helpful lisp book I could find.

lisp refers to common lisp:)

Cheers
Chris

Share this post


Link to post
Share on other sites
From someone who has only vague knowledge of lisp, I thought it was pretty good. In fact, it made me re-iterate my ambition to "get around to learning some lisp, one of these days".

What I'd have liked at the end of your tutorial is a "where to go from here" section. Something like:

Hope you enjoyed the tutorial, if you want to start using lisp for real. go to www.heresafreelispimplementation.com to get an interpreter. More detailed language references are available at www.toolazytogoogleforlisp.com and www.yesImlazybutidlikeatutorialrecommendedtome.com

Share this post


Link to post
Share on other sites
Looks pretty good, skimming over it. Nice domain name, by the way. I'm surprised it wasn't already registered.

Share this post


Link to post
Share on other sites
Quote:
Original post by ChaosEngine
[...]What I'd have liked at the end of your tutorial is a "where to go from here" section.[...]
The best lisp compiler I've found that is entirely free is Corman Lisp - download the trial, and just use the command-line version after the IDE times out (the command-line REPL doesn't time out). You can set up e-macs to use corman lisp's REPL, but I had great difficulty getting it to work (randomly works or doesn't for no apparent reason - part of the reason I stopped playing with Lisp).

As far as where to go, I strongly suggest the book ANSI Common Lisp. It's a great introduction to the language and doesn't cover the 'fluff' that you should already know as a programmer (what variables, functions, etc are).

Share this post


Link to post
Share on other sites
Quote:
Original post by Extrarius
The best lisp compiler I've found that is entirely free is Corman Lisp - download the trial, and just use the command-line version after the IDE times out (the command-line REPL doesn't time out). You can set up e-macs to use corman lisp's REPL, but I had great difficulty getting it to work (randomly works or doesn't for no apparent reason - part of the reason I stopped playing with Lisp).

As far as where to go, I strongly suggest the book ANSI Common Lisp. It's a great introduction to the language and doesn't cover the 'fluff' that you should already know as a programmer (what variables, functions, etc are).

Or even better, get SBCL. Even if the Windows port is still WIP it seems to be actually usable for testing purposes. I actually prefer SBCL over Lispworks(which has a trial version available btw) and once the Windows version gets more mature there will finally be a standard+crossplatform+free+native-compiling CL implementation to use for game-devving :)

Share this post


Link to post
Share on other sites
I've found lisp-in-a-box to be a great all in one package for getting up and running with Lisp. It automatically loads emacs in slime mode and it just works for getting you up and running.

One caveat, I've been unable to get asdf working on it:(

Cheers
Chris

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement