237FW: [XP] Lisp's attractions (was: Polymorphism)
- Aug 21, 2002Pascal:
Thanks for the intro to Lisp. Lots of good info there.
Here is something I wrote to the XP list on Lisp
recently that to some extent is a rehash of
a point that Richard Gabriel made earlier:
Lisp is bigger than even its creator thought it would
ever be and the main cause for this is _serendipity_,
or emergence if you prefer the term.
This goes on to show that Feyerabend philosophy of Science is
of utmost importance and that its tenets need to be
considered seriously in making progress in a field such as ours.
I also have to admit here a few things about Lisp:
1) For years I missed the importance of Lisp. I thought
it was just another language. It wasn't until
a couple of years ago that I started to realize there
was something truly special about it.
2) Understanding Lisp, I think, it is very key to
understanding what software is all about and being able to
contrast the good, the bad and the ugly.
From that perspective, I've got a better education
from Richard Gabriel and others on the "patterns-discussion"
mailing list than most get while getting
Computer Science Ph. D.s.
3) My ideas about Paterno, the pattern-oriented language,
and L4, Lifestreams, Living Metaphor (agents),
Linda and Lisp, the ideas about simulating organic
processes in software; would have _never_ seen the light
had I not implemented them with Lisp. In Lisp is
possible to do many things that are very difficult, if
not impossible, in other languages.
Though I have ran with a variety of Lisp environments, my
preferred environment these days, btw, is Allegro Franz Lisp
6.2 with AllegroServ running on both Linux and WinXP. I like
a lot of their libraries/extensions.
Get a free trial at:
But there are many other free implementations of course:
From: Mike Beedle [mailto:beedlem@...]
Sent: Wednesday, July 31, 2002 2:46 AM
Subject: RE: [XP] Lisp's attractions (was: Polymorphism)
George Paci wrote:
> Kevin Lawrence wrote:The most amazing thing is what Lisp ended up being out of
> > Strangely enough, I wrote a lisp compiler a few weeks ago while
> > experimenting with genetic programming and I have to confess
> that I do not
> > understand the merits of that language at all.
> Compiler, or interpreter? A bit of Lisp lore: the very first Lisp
> interpreter was written in a few weeks, by a graduate student whom
> McCarthy had advised not to try.
pure serendipity. McCarthy was going after a universal function
that would compete or replace a Turing machine.
But when S.R. Russell noticed that eval could serve as an interpreter
for LISP, and promptly coded it -- against McCarthy's advise and
wishes, we ended up with a very special programming language, where
code is always data, and data can be code!!, where a simple
interpreter and a handful of primitives define a powerful language:
(define (eval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
(make-procedure (lambda-parameters exp)
(eval-sequence (begin-actions exp) env))
((cond? exp) (eval (cond->if exp) env))
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(error "Unknown expression type - EVAL" exp))))
(define (apply procedure arguments)
(cond ((primitive-procedure? procedure)
(apply-primitive-procedure procedure arguments))
"Unknown procedure type - APPLY" procedure))))
Understanding this "universal function" is equivalent as
understanding a 400 page programming language.
To prove that McCarthy had little intention in doing this,
take a look at what he wrote:
"Another way to show that LISP was neater than Turing machines
was to write a universal LISP function and show that it is
briefer and more comprehensible than the description of a
universal Turing machine. This was the LISP function eval[e,a],
which computes the value of a LISP expression e - the
second argument a being a list of assignments of values
to variables. (a is needed to make the recursion work). Writing
eval required inventing a notation representing LISP
functions as LISP data, and such a notation was devised for
the purposes of the paper with no thought that it would
be used to express LISP programs in practice. Logical
completeness required that the notation used to express
functions used as functional arguments be extended to
provide for recursive functions, and the LABEL notation
was invented by Nathaniel Rochester for that purpose.
D.M.R. Park pointed out that LABEL was logically unnecessary
since the result could be achieved using only LAMBDA - by
a construction analogous to Church's Y-operator, albeit
in a more complicated way."
Which goes to show that he had _no_ vision or plan to
create the monster that he did: it just happened out of
pure luck. (Feyerabend lives!) This statement is specially
"Writing eval required inventing a notation representing
LISP functions as LISP data, and such a notation was
devised for the purposes of the paper with no thought
that it would be used to express LISP programs in practice."
Thank God someone took his original notation seriously and
literally .... otherwise, Lisp as we know it, may have never
existed. And humanity would be deprived of its power, flexibility
In terms of impact, Genetic programming, most Agent Technology,
Artificial Intelligence and all of its branches (Logical programming,
Rule-Oriented, Natural Language Processing, Neural Nets, Game
Programming, etc. etc.), Hybrid or Multi-Paradigmic programming,
Aspect Oriented Programming, Meta-Object Protocols, and a great
deal of programming language research could have never been
possible if it wasn't for Lisp.
Literally, we would not be where we are in programming if
it wasn't for a crazy guy that took a programming language
research paper literally, and did a very dumb thing:
wrote some code in a short amount of time.
The rest was generated by this little "historical accident".
George Paci wrote:
> I think you're getting close to what's great about Lisp. Basically,Yes, absolutely, once code is data, there is not need for
> you're typing in parse trees. There's very little syntactic sugar
> to get between you and the interpreter (or compiler, these days).
> Since you've got your program in a form that's so easy for other
> programs to deal with, you can write very useful macros -- Lisp code
> that changes other Lisp code.
ASTs (Abstract Syntax Trees). Lisp notation is basically a condensed
form for writing ASTs.
But what that means is that to modify the meaning of the
language and/or to do even things like meta-programming, Lisp
is the natural choice. Think about this: it is easy to generate
data from a program, right? Well, if code is data, then it
is easy to generate _code_. Things like genetic programming are
easy with Lisp.
Also, parsing "other languages" is easy with Lisp. It is no
coincidence that most ACLs (Agent Communication Languages) are
Lisp-based, because the "verb/data exchanges" can be simply
interpreted on either side. No need for SAX-like parsers that
waste cycles in serialization and deserialization -- simply
take the stream and interpret it. And if it is not exactly Lisp,
get inspired by Lisp and create an eval-like function and then
interpret the "new language". In that sense, eval is like a
"universal SAX parser". Wouldn't you like to have one of those?
On the meta-programming side, imagine this, you can set any
level of filtering, execution of extra actions, change interpretation,
or give new meanings to anything that is interpreted or
"evaluates" by just changing eval. So if you want to keep
meta data or meta processing on your programs there is nothing
as simple as Lisp.
In Lisp, for example, is incredibly easy to do Aspect Oriented
Programming because you can manage at every point what happens
to the joint and cut points of functions and it is easy
to do so.... everything goes through eval.
If that wasn't enough, Lisp comes with a myriad of nice features
such as lambdas (first order functions), closures (functions that
generate functions), powerful macros (that can generate anything
data, functions, classes, patterns, or even other macros),
generics (methods that cut across multiple classes in CLOS), and
by extension, MOPs; and with a wide variety of powerful
Open Source Lisp source code scattered throughout the planet.
(The Lisp community was perhaps the first community that
embraced Open Source.)
In my opinion, Lisp is the most powerful and flexible language,
and in fact, I would say that once you understand Lisp, other
languages seem very constraining, underpowered and unnecessary
Also, Lisp programmers were probably the first "agile developers"
on the planet, because as far back as the mid-60s, many of the
practices that we know today as "agile practices" or even
"extreme programming" were already in practice:
- Bottom-up Design. LISP programmers have practiced
bottom-up design since the 60s. So bottom-up architecting
and emergent design have lived in this community from
the very beginning.
- Test-first programming In LISP you test everything
with eval all the time. Also it is customary to write
libraries by writing tests at the end of source code
that get commented when the source code is released.
The test are typically test evaluations that you
want to remember.
- Development in pairs. This was used to mentor
juniors through the "buddy system". Practiced at
MIT, for example.
- Customer-Driven implementations with rapid
prototyping being practiced. It is easier
to show the customer what he or she may want
in LISP than to write a long document
- Continuous Integration, since individual developer's
speed was high, continuous integration was
necessary and mandatory
- Iterative Development, was natural since
development was goal-oriented
Sorry for my longish post -- I could rave and rant all day about
the powers of Lisp.
I'll leave you with a thought. Here is simple example to
extend Lisp to do Object-Oriented programming. Try to do something
similar in C, C++, Java or even Smalltalk ;-)
(defmacro define-class (class inst-vars class-vars &body methods)
"Define a class for object-oriented programming."
;; Define constructor and generic functions for methods
(mapcar #'ensure-generic-fn ',(mapcar #'first methods))
(defun ,class ,inst-vars
,@(mapcar #'make-clause methods))))))
(defun make-clause (clause)
"Translate a message from define-class into a case clause."
`(,(first clause) #'(lambda ,(second clause) .,(rest2 clause))))
(defun ensure-generic-fn (message)
"Define an object-oriented dispatch function for a message,
unless it has already been defined as one."
(unless (generic-fn-p message)
(let ((fn #'(lambda (object &rest args)
(apply (get-method object message) args))))
(setf (symbol-function message) fn)
(setf (get message 'generic-fn) fn))))
(defun generic-fn-p (fn-name)
"Is this a generic function?"
(and (fboundp fn-name)
(eq (get fn-name 'generic-fn) (symbol-function fn-name))))
To Post a message, send it to: extremeprogramming@...
To Unsubscribe, send a blank message to:
ad-free courtesy of objectmentor.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/
- Next post in topic >>