Thursday 21 April 2011

Starting Lisp

First off, Lisp isn't a language. At least, it's not just 1 language - it's a family of them which all share a similar syntax and manner of operation.
The variant I've been acquainting myself with is Common Lisp.
It's intimidating for several reasons, the main one being the elitist attitude attached to many of those who use it. Maybe it *is* the best, most advanced language in the world(I can't say), but hearing that makes it no easier to learn.
The syntax looks....bloated. One would tend to skim though a line of code and assume there is some kind of unnecessary, 'yet beautiful' paradigm at work which could only be appreciated by an academic, but in all makes a less useful language.
It definitely helps to have a background in functional languages to understand just how useful Lisp can be. 

After downloading and installing a Lisp runtime (clisp, for example), you will notice that the front-end takes the form of a Read-eval-print loop, something very familiar if you come from a ruby/python/similar background.

For those unfamiliar with this concept, it's exactly what it says it is. You type text in the correct syntax, which gets *read* into an internal format, then gets *eval*-uated, and the resulting data *print*-ed on the screen.

Now to the code :)

In the loop try evaluating some data, like 1 or 3 or "sandwiches", and hitting enter to evaluate. That shouldn't do anything really very surprising at all.
What's happening here is that the reader is converting the text, "1", into the internal Lisp object which represents an integer.
This object is then passed to the evaluator, which does nothing with the object.
Still the integer object representing 1, it gets passed to the printer, which converts it to a textual representation "1".

Thrilling stuff, eh?
Not really, no. In that example, the evaluator did absolutely nothing, but it's in fact the most complex part which makes up a Lisp system, as we shall see.

But, how do we write out a Lisp list?
Like this: (1 2 3 4), this is a list containing 4 objects.
Lists can also contain other lists: (1 2 3 4 (1 2 3))

Now lets try to evaluate a list.
Type (1 2 3 4) into the read-eval-print prompt, and hit enter.
This will now throw a potentially very ugly error(ugliness is implementation-dependant).
clisp responds with the following insult:


*** - EVAL: 1 is not a function name; try using a symbol instead
The following restarts are available:
USE-VALUE      :R1      You may input a value to be used instead.
ABORT          :R2      Abort main loop

Not nice to look at, but it's point is that the object '1' isn't the name of a function.
Why was it expecting a function name? Because that's how Lisp code is written. It's a list. It's all lists.
Want to call a function? Create a list beginning with the function name, and the parameters as the other list elements.

Here's a practical function call, the seminal "hello world" program:
(print "Hello world")
This is a list containing two objects. One is a name, the other is a string. The reader, takes this, creates these objects in memory, and passes the list to the evaluator. The evaluator notices it's been given a list, and after evaluating all of the other elements, calls the function named by 'print' with the "Hello world" string as an argument(remember, simple objects like strings do nothing when evaluated).

But what if we feel we need to stop evaluation for some reason? What if we just want to tell the evaluator to stop and, for example, not evaluate a list. Rather, leave it as a list?

This is where the special name "quote" is used.
When the evaluator encounters a list to evaluate whose first element is the name: "quote", it simply returns the other element in the list without trying to evaluate it.
Given this, we can do what we described, and get the evaluator to leave our list alone by writing the following:
(quote (1 2 3 4))
After the reader has done it's job, and turned everything into objects(2 lists, one inside the other), the evaluator sees the first element of the list passed to it is the name 'quote'. This makes it stop in it's tracks, and simply evaluate to whatever object was given as the argument, in this case, a list of 1, 2, 3 and 4.
This is then passed to the printer, and is displayed as:
(1 2 3 4)
on the screen.

As the reader(you, not the Lisp reader) will hopefully now understand, this quote thing is useful. Most obviously, when you want to write out lists. This assumption is true enough, in fact, that in Common Lisp, there is a shorthand in the form of the single-quote, eg:
(quote someobject)
is completely and utterly equivalent to
'someobject

and (quote (1 2 3 4))
is totally and thoroughly the same as
'(1 2 3 4)


Now, a quick test. If you want the printer to show a list, why can't you type:
(print (1 2 3 4))
when instead you must type:
(print '(1 2 3 4)) ?


It may not say much, but I feel this tutorial clearly outlines the workings of the language, which are easily misunderstood.

More Common Lisp:
Make a greeting function, 'greet':
(defun greet () (print "hello"))

Make a better greeting function, which takes a string as a parameter:
(defun greet2 (name) (print (concatenate 'string "Hello, " name)))

Call the greet2 function:
(greet2 "Lee")
prints => "Hello, Lee"


That's all for now :)

No comments:

Post a Comment