Declarative Languages
Lecture #12
Purpose: Loose ends / CLOS in 10 minutes / revision quiz / summary
12.1 Loose ends
There are a couple of specific points that I want to tie up. The first
is that one of the great things about lisp is that it offers so many different
ways of expressing your intent. Recall from the first lecture:
A declarative
language is a language in which you describe the problem you are working
on and the computer decides how to solve it. Lisp and Prolog are declarative
languages.
On the other hand a procedural
language is a language in which you tell the computer what to do. The
machine will then do what you tell it and you hope that what it tells you
is the answer to the question you wanted to ask. Pascal is a procedural
language.
I am still unhappy with the thought of languages being declarative
(if that is what the word means) - although code like
(def-url "/" ...) ; define root
page of my web server
is getting close to that ideal. However, I think it is indisputable that
lisp gives you so many ways of telling the computer what to do that you
can effectively get on with the task of describing your actual problem
relatively unencumbered by small details.
For example, the following would all find the position in the list things
of a sublist of length 1. The first is fairly compact, and fine if you
know how to use the :key argument to position. The next
is almost as neat but depends on knowing about position-if, the
third works but might be criticized for wasteful allocation (generating
a list of length (length things) and then throwing it away again).
The dolist form uses "primitive" parts, which is fine and might
even in some circumstances run faster than the others; the mapc-closure
solution is quite frankly revolting. Presumably, we could also have written
a recursive function to do the search.
(position 1 things :key 'length)
(position-if #'(lambda (x) (= (length x) 1)) things)
(position 1 (mapcar 'length things))
(let ((where 0))
(dolist (x things)
(when (= (length x) 1)
(return where))
(incf where)))
(block found
(let ((where 0))
(mapc #'(lambda (x)
(when (and x (not (cdr x)))
(return-from found where))
(incf where))
things))
nil)
A lot of the functions I have told you about take additional (optional)
arguments, and I may not always have told you about these. They quite frequently
permit greater flexibility, and sometimes additional sophistication, in
how you use them. For example, the following
(or (gethash key table)
default)
(gethash key table default)
both allow you to retrieve a value from a hash-table and state a default
value in case the key wasn't present. However, suppose that the
key
is
present in the table, and the value stored against it is
nil.
In the first case above, gethash returns nil and so the
or
form returns default; in the second, gethash again finds
key
and returns nil. So the second form, while ostensibly similar
to the first, can be used to distinguish between a stored value of nil
and no stored value.
You'll find many cases like this in lisp: where different treatments
can have similar results but for fine tuning you have to really know how
each operator works.
12.2 What did we miss out? (incorporating "CLOS in
ten minutes"TM)
We have covered around 160 Common
Lisp symbols - looked at one way that's one sixth of the language.
In practice, it's considerably more than that because a lot of the remaining
symbols involve more book-work to cover less ground. (Or: less dramatic
ground.) I'd reckon we're about half-way there. We didn't touch:
-
packages (other than in passing)
-
streams (other than in passing)
-
pathnames (other than very much in passing)
-
compilation issues
-
declarations
-
optimization
-
defining your own setf behaviour
-
multiple values (other than in passing)
-
the complex loop macro
-
the condition system
-
advanced macro building techniques
-
extending the syntax
-
vast numbers of functions dealing with lists, arrays, string, characters,
numbers
12.3 Summary
So why use Lisp? Because it is
-
Standardized
-
Extensible
-
Dynamic
-
Large
-
Powerful
-
Robust
-
Reliable
-
Y2K proof ;-)
-
Flexible
-
Cheap
-
High-level
-
Interactive
-
Elegant
-
Fun
It offers (see also the
white paper)
-
simple consistent syntax
-
a rich set of datatypes
-
run-time (dynamic) typing
-
automatic memory management (garbage collection)
-
a fully integrated object system (CLOS)
-
sophisticated error handling
-
stunningly powerful macro system ("programs as data")
-
features (such as unwind-protect and closures) which you simply
won't find elsewhere
It is particularly suitable for applications which are
-
large and complex
-
server side
-
non-stop
12.4 Revision Quiz
-
How would you add (i.e. insert) an extra element to the start of a list?
-
How could you splice two lists together?
-
How would you add (i.e. insert) an extra element to the end of a list?
-
Suppose you wanted to perform some operation on each element of a list:
how could you do this? (3 different answers...)
-
What kinds of things can you use lists for?
-
Give an example of a special operator.
-
How could you find out the variable value of a symbol?
-
How could you find out whether a symbol had a functional value?
-
Give an example of a lisp object which is of two types, neither of which
is a subtype of the other.
-
True or false: every valid expression, when evaluated, returns a value?
-
True or false: and is a function?
-
How could you define a function so that it can take 0 or more parameters?
-
How do you give a default value for an optional argument?
-
Give five lisp datatypes.
-
What does eval do?
-
What defining forms do you know?
-
Give some advantages of macros.
-
Give an example of an iterative operator.
-
Give 3 different equality predicates.
-
How would you decide which equality predicate to use?
-
If you wanted to find an operator which worked on strings, you might look
in a reference manual in the chapter on string operators. Which other chapters
would you look in?
-
What is tail recursion?
-
How do you write comments in lisp code?
-
What conventions do you know for lisp code?
-
How would you choose whether to use structures, hash-tables, lists or arrays
for a particular application?
-
What kinds of applications do you think lisp is good for?
-
How do you ask a lisp programmer if they want a drink?
12.5 Practical session / Suggested activity
-
Implement a recursive function to find the position in a given list of
a sublist of length 1.
-
Implement the function append. Is your solution elegant? fast?
robust?
-
Implement a function which takes a lisp object and says something useful
about it (the way that describe does).
-
Go back through all the practicals and exercises and complete everything
you missed out first time through.
12.6 Revision reading
-
Graham chapters 1-8 and 10
-
Take at least one look through chapter 13 and appendix D of Graham.
As a final word, I just want to thank all my students at APU for helping
me deliver this course, for working so hard and (I hope) for coming to
appreciate at least the edges of why for me lisp is the only language
to write your programs in.
Last modified 2000-09-14
$Id: //info.ravenbrook.com/user/ndl/lisp/declarative/lectures/lectures/lecture-12.html#2 $