gbrain: sync converted org-mode brain files

This commit is contained in:
Hermes
2026-05-28 03:01:01 +00:00
parent 3efbf760e6
commit af132f7e88
26 changed files with 48165 additions and 1 deletions

View File

@@ -0,0 +1,44 @@
:PROPERTIES:
:CREATED: [2026-05-27 Wed]
:ID: ee8f3b2a-4c7d-4e1b-9b0a-6d8f2e3c1a5b
:END:
#+title: Neurosymbolic AI — Paper Library
#+filetags: :resources:neurosymbolic:papers:survey:
Local library of recent neurosymbolic AI papers, updated monthly from arXiv. Papers are downloaded in PDF format and cataloged below.
See also the companion note [[id:be9bccc7-5adf-4d0d-8ee4-8855892189bf][Neurosymbolic Loop Architectures]] for a design taxonomy that positions these papers relative to Passepartout.
* 2026 Papers
| arXiv ID | Title | Date | Keywords | File |
|----------|-------|------|----------|------|
| 2605.22885 | ImProver 2: Iteratively Self-Improving LMs for Neurosymbolic Proof Optimization | May 2026 | LLM, theorem proving, proof optimization, self-improvement | [[file:papers/2605.22885.pdf]] |
| 2605.22874 | NeuroNL2LTL: Neurosymbolic Framework for NL Translation of LTL | May 2026 | NL translation, LTL, formal logic | [[file:papers/2605.22874.pdf]] |
| 2605.10327 | SCALAR: Symbolic Conjecture and LLM-Assisted Reasoning | May 2026 | Conjecture generation, theorem proving, LLM | [[file:papers/2605.10327.pdf]] |
| 2605.10279 | DeepLog: Neurosymbolic Framework Unifying Logic and Deep Learning in PyTorch | May 2026 | Logic, deep learning, PyTorch, neurosymbolic | [[file:papers/2605.10279.pdf]] |
| 2605.08011 | LLM + Formal Logic Integration for Neurosymbolic Reasoning | May 2026 | Survey, formal logic, LLM, neurosymbolic reasoning | [[file:papers/2605.08011.pdf]] |
| 2605.01430 | Measuring Understanding in Artificial Cognitive Systems | May 2026 | Verification, cognitive systems, neurosymbolic | [[file:papers/2605.01430.pdf]] |
| 2605.26169 | ESBMC: Survey of Formal Software Verification | May 2026 | Formal verification, bounded model checking, SMT | [[file:papers/2605.26169.pdf]] |
| 2604.05427 | LLM Verification Gates for Robot Task Planning | Apr 2026 | Gates, verification, robotics, LLM | [[file:papers/2604.05427.pdf]] |
| 2604.04177 | Formal Logic in LLM Fact-Checking Pipelines | Apr 2026 | Fact-checking, logic, verification | [[file:papers/2604.04177.pdf]] |
| 2604.23377 | The Alignment Problem in Neurosymbolic Systems | Apr 2026 | Alignment, concept-label correspondence, neurosymbolic | [[file:papers/2604.23377.pdf]] |
| 2603.14628 | LLM Neurosymbolic Reasoning in Theorem Proving | Mar 2026 | Theorem proving, LLM, neurosymbolic | [[file:papers/2603.14628.pdf]] |
| 2603.04019 | Fluid Logic: Neurosymbolic Modal Reasoning | Mar 2026 | Modal logic, neurosymbolic, reasoning | [[file:papers/2603.04019.pdf]] |
* Related Neuromorphic Architecture Papers
| arXiv ID | Title | Date | Keywords | File |
|----------|-------|------|----------|------|
| 2604.04605 | Benchmarking Neuromorphic AI Processors | Apr 2026 | Neuromorphic, benchmarking, hardware | (not yet downloaded) |
| 2604.21924 | Spiking Neural Network Optimization | Apr 2026 | SNN, optimization, neuromorphic | (not yet downloaded) |
* How the Monthly Update Works
A monthly cron job (set on 2026-05-27) runs on the 1st of each month:
1. Queries arXiv API for new papers with keywords: neurosymbolic, neural+symbolic+reasoning, LLM+verification, neural+theorem+proving
2. Filters by the current month's submissions
3. Downloads PDFs of relevant papers
4. Updates this index
5. Commits and pushes the brain repo

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@@ -0,0 +1,60 @@
:PROPERTIES:
:CREATED: [2026-05-27 Wed]
:ID: 09a03e7f-c3f8-438a-abe3-7a7570957565
:END:
#+title: Worse is Better — Reference Articles
#+filetags: :resources:worse-is-better:gabriel:graham:lisp:
Collection of the canonical articles in the Worse is Better debate, saved as local resources. See [[id:dddd52a7-adb8-470e-a459-614ade5f76af][Closing the Lisp Gap]] for the strategic analysis in context of Passepartout.
* Richard P. Gabriel
Original essays and sequels on the worse-is-better dynamic. Text versions (.html) render in a browser. PDF versions (.pdf) include the original published formatting.
| Article | Format | Year | File |
|---------|--------|------|------|
| Lisp: Good News, Bad News, How to Win Big | HTML | 1990 | [[file:worse-is-better/lisp-good-news-bad-news.html]] |
| The Rise of Worse is Better | HTML | 1991 | [[file:worse-is-better/rise-of-worse-is-better.html]] |
| Worse Is Better Is Worse (as Nickieben Bourbaki) | PDF | 1991-1992 | [[file:worse-is-better/worse-is-better-is-worse.pdf]] |
| Is Worse Really Better? | PDF | 1992 | [[file:worse-is-better/is-worse-really-better.pdf]] |
| Back to the Future: Is Worse (Still) Better? | PDF | 2000 | [[file:worse-is-better/back-to-future-is-worse-still-better.pdf]] |
| Back to the Future: Worse (Still) is Better! | PDF | 2000 | [[file:worse-is-better/back-to-future-worse-still-is-better.pdf]] |
All sourced from https://www.dreamsongs.com/
** Lisp: Good News, Bad News, How to Win Big
Gabriel's 1990 EuroPAL keynote. The original essay containing the Worse is Better argument in the context of an analysis of Lisp's failure in the marketplace compared to C/Unix. Diagnoses Lisp's technical advantages contrasted with its lack of ecosystem adoption.
** The Rise of Worse is Better
The section from the above essay that Jamie Zawinski extracted and circulated in 1991. Contains the canonical statement of the Worse is Better philosophy: simplicity of implementation over interface, sufficient correctness over perfect, consistency and completeness subordinate to simplicity.
** Worse Is Better Is Worse
Gabriel's pseudonymous attack on his own Worse is Better concept, written under the name Nickieben Bourbaki (modeled after Nicolas Bourbaki, the collective pseudonym of French mathematicians). Argues that the Worse is Better approach produces systems that cannot be repaired because the accumulation of compromises makes them structurally unsound.
** Is Worse Really Better?
Gabriel's rebuttal to his own pseudonymous attack, published in the Journal of Object-Oriented Programming (JOOP). Written as his real self defending the Worse is Better position.
** Back to the Future (both sides)
OOPSLA 2000 panel position papers. Martine Devos requested a position paper; Gabriel wrote one against Worse is Better, then a month later wrote one in favor. Both were combined into the panel's position paper. The fishbowl format had participants switching sides throughout.
* Paul Graham
| Article | Format | Year | File |
|---------|--------|------|------|
| Beating the Averages | HTML | 2001 | [[file:worse-is-better/beating-the-averages.html]] |
| The Hundred-Year Language | HTML | 2003 | [[file:worse-is-better/hundred-year-language.html]] |
Sourced from https://www.paulgraham.com/
** Beating the Averages
Argues that Lisp's power (macros, REPL, dynamic typing) gives its users a "quantum advantage" in productivity, but that this advantage is invisible to competitors because they cannot distinguish superior technology from luck. Introduces the "Blub paradox": programmers in mediocre languages cannot recognize the power of better ones.
** The Hundred-Year Language
Argues that languages evolve toward Lisp-like features over long timescales: garbage collection, dynamic typing, macros, interactive development. Claims that the features we add to languages today are all things Lisp had in 1960. Predicts that future languages will look like Lisp with better syntax.

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,498 @@
<html><head><title>The Hundred-Year Language</title><!-- <META NAME="ROBOTS" CONTENT="NOODP"> -->
<link rel="shortcut icon" href="http://ycombinator.com/arc/arc.png">
</head><body bgcolor="#ffffff" background="https://s.turbifycdn.com/aah/paulgraham/bel-6.gif" text="#000000" link="#000099" vlink="#464646"><table border="0" cellspacing="0" cellpadding="0"><tr valign="top"><td><map name=1d31a69a99c0a2c9><area shape=rect coords="0,0,67,21" href="index.html"><area shape=rect coords="0,21,67,42" href="articles.html"><area shape=rect coords="0,42,67,63" href="http://www.amazon.com/gp/product/0596006624"><area shape=rect coords="0,63,67,84" href="books.html"><area shape=rect coords="0,84,67,105" href="http://ycombinator.com"><area shape=rect coords="0,105,67,126" href="arc.html"><area shape=rect coords="0,126,67,147" href="bel.html"><area shape=rect coords="0,147,67,168" href="lisp.html"><area shape=rect coords="0,168,67,189" href="antispam.html"><area shape=rect coords="0,189,67,210" href="kedrosky.html"><area shape=rect coords="0,210,67,231" href="faq.html"><area shape=rect coords="0,231,67,252" href="raq.html"><area shape=rect coords="0,252,67,273" href="quo.html"><area shape=rect coords="0,273,67,294" href="rss.html"><area shape=rect coords="0,294,67,315" href="bio.html"><area shape=rect coords="0,315,67,336" href="https://twitter.com/paulg"><area shape=rect coords="0,336,67,357" href="https://mas.to/@paulg"></map><img src="https://s.turbifycdn.com/aah/paulgraham/bel-7.gif" width="69" height="357" usemap=#1d31a69a99c0a2c9 border="0" hspace="0" vspace="0" ismap /></td><td><img src="https://sep.turbifycdn.com/ca/Img/trans_1x1.gif" height="1" width="26" border="0" /></td><td><a href="index.html"><img src="https://s.turbifycdn.com/aah/paulgraham/bel-8.gif" width="410" height="45" border="0" hspace="0" vspace="0" /></a><br /><br /><table border="0" cellspacing="0" cellpadding="0" width="435"><tr valign="top"><td width="435"><a href="https://s.turbifycdn.com/aah/paulgraham/the-hundred-year-language-20.gif"><img src="https://s.turbifycdn.com/aah/paulgraham/the-hundred-year-language-21.gif" width="410" height="110" border="0" hspace="0" vspace="0" /></a><br /><br /><img src="https://s.turbifycdn.com/aah/paulgraham/the-hundred-year-language-22.gif" width="228" height="18" border="0" hspace="0" vspace="0" alt="The Hundred-Year Language" /><br /><br /><font size="2" face="verdana">April 2003<br /><br /><i>(This essay is derived from a keynote talk at PyCon 2003.)</i><br /><br />It's hard to predict what
life will be like in a hundred years. There are only a few
things we can say with certainty. We know that everyone will
drive flying cars,
that zoning laws will be relaxed to allow buildings
hundreds of stories tall, that it will be dark most of the
time, and that women will all be trained in the martial arts.
Here I want to zoom in on one detail of this
picture. What kind of programming language will they use to
write the software controlling those flying cars?<br /><br />This is worth thinking about not so
much because we'll actually get to use these languages as because,
if we're lucky, we'll use languages on the path from this
point to that.<br /><br /><br /><br />I think that, like species, languages will form evolutionary trees,
with dead-ends branching off all over. We can see this
happening already.
Cobol, for all its sometime popularity, does not seem to have any
intellectual descendants. It is an evolutionary dead-end-- a
Neanderthal language.<br /><br />I predict a similar fate for Java. People
sometimes send me mail saying, "How can you say that Java
won't turn out to be a successful language? It's already
a successful language." And I admit that it is, if you
measure success by shelf space taken up by books on it
(particularly individual books on it), or by
the number of undergrads who believe they have to
learn it to get a job. When I say Java won't
turn out to be a successful language, I mean something more
specific: that Java
will turn out to be an evolutionary dead-end, like Cobol.<br /><br />This is just a guess. I may be wrong. My point here is not to dis Java,
but to raise the issue of evolutionary
trees and get people asking, where on the tree is language X?
The reason to ask this question isn't just so that
our ghosts can say, in a
hundred years, I told you so. It's because staying close to
the main branches is a useful heuristic for finding languages that will
be good to program in now.<br /><br />At any given time, you're probably happiest on
the main branches of an evolutionary tree.
Even when there were still plenty of Neanderthals,
it must have sucked to be one. The
Cro-Magnons would have been constantly coming over and
beating you up and stealing your food.<br /><br />The reason I want to
know what languages will be like in a hundred years is so that
I know what branch of the tree to bet on now.<br /><br /><br /><br />The evolution of languages differs from the evolution of species
because branches can converge. The Fortran branch, for example,
seems to be merging with the descendants
of Algol. In theory this is possible for species too, but it's
not likely to have happened to any bigger than a cell.<br /><br />Convergence
is more likely for languages partly because the space of
possibilities is smaller, and partly because mutations
are not random. Language designers deliberately incorporate
ideas from other languages.<br /><br />It's especially useful for language designers to think
about where the evolution of programming languages is likely
to lead, because they can steer accordingly.
In that case, "stay on a main branch" becomes more than a
way to choose a good language.
It becomes a heuristic for making the right decisions about
language design.<br /><br /><br /><br />Any programming language can be divided into
two parts: some set of fundamental operators that play the role
of axioms, and the rest of the language, which could in principle
be written in terms of these fundamental operators.<br /><br />I think the fundamental operators are the most important factor in a
language's long term survival. The rest you can change. It's
like the rule that in buying a house you should consider
location first of all. Everything else you can fix later, but you
can't fix the location.<br /><br />I think it's important not just that the axioms be well chosen,
but that there be few of them. Mathematicians have always felt
this way about axioms-- the fewer, the better-- and I think they're
onto something.<br /><br />At the very least, it has to be a useful exercise to look closely
at the core of a language to see if there are any axioms that
could be weeded out. I've found in my long career as a slob that
cruft breeds cruft, and I've seen this happen in software as
well as under beds and in the corners of rooms.<br /><br />I have a hunch that
the main branches of the evolutionary tree pass through the languages
that have the smallest, cleanest cores.
The more of a language you can write in itself,
the better.<br /><br /><br /><br />Of course, I'm making a big assumption in even asking what
programming languages will be like in a hundred years.
Will we even be writing programs in a hundred years? Won't
we just tell computers what we want them to do?<br /><br />There hasn't been a lot of progress in that department
so far.
My guess is that a hundred years from now people will
still tell computers what to do using programs we would recognize
as such. There may be tasks that we
solve now by writing programs and which in a hundred years
you won't have to write programs to solve, but I think
there will still be a good deal of
programming of the type that we do today.<br /><br />It may seem presumptuous to think anyone can predict what
any technology will look like in a hundred years. But
remember that we already have almost fifty years of history behind us.
Looking forward a hundred years is a graspable idea
when we consider how slowly languages have evolved in the
past fifty.<br /><br />Languages evolve slowly because they're not really technologies.
Languages are notation. A program is a formal description of
the problem you want a computer to solve for you. So the rate
of evolution in programming languages is more like the
rate of evolution in mathematical notation than, say,
transportation or communications.
Mathematical notation does evolve, but not with the giant
leaps you see in technology.<br /><br /><br /><br />Whatever computers are made of in a hundred years, it seems
safe to predict they will be much faster than
they are now. If Moore's Law continues to put out, they will be 74
quintillion (73,786,976,294,838,206,464) times faster. That's kind of
hard to imagine. And indeed, the most likely prediction in the
speed department may be that Moore's Law will stop working.
Anything that is supposed to double every eighteen months seems
likely to run up against some kind of fundamental limit eventually.
But I have no trouble believing that computers will be very much
faster. Even if they only end up being a paltry million
times faster, that should change the ground rules for programming
languages substantially. Among other things, there
will be more room for what
would now be considered slow languages, meaning languages
that don't yield very efficient code.<br /><br />And yet some applications will still demand speed.
Some of the problems we want to solve with
computers are created by computers; for example, the
rate at which you have to process video images depends
on the rate at which another computer can
generate them. And there is another class of problems
which inherently have an unlimited capacity to soak up cycles:
image rendering, cryptography, simulations.<br /><br />If some applications can be increasingly inefficient while
others continue to demand all the speed the hardware can
deliver, faster computers will mean that languages have
to cover an ever wider range of efficiencies. We've seen
this happening already. Current implementations of some
popular new languages are shockingly wasteful by the
standards of previous decades.<br /><br />This isn't just something that happens with programming
languages. It's a general historical trend. As technologies improve,
each generation can do things that the previous generation
would have considered wasteful. People thirty years ago would
be astonished at how casually we make long distance phone calls.
People a hundred years ago would be even more astonished that
a package would one day travel from Boston to New York via Memphis.<br /><br /><br /><br />I can already tell you what's going to happen to all those extra
cycles that faster hardware is going to give us in the
next hundred years. They're nearly all going to be wasted.<br /><br />I learned to program when computer power was scarce.
I can remember taking all the spaces out of my Basic programs
so they would fit into the memory of a 4K TRS-80. The
thought of all this stupendously inefficient software
burning up cycles doing the same thing over and over seems
kind of gross to me. But I think my intuitions here are wrong. I'm
like someone who grew up poor, and can't bear to spend money
even for something important, like going to the doctor.<br /><br />Some kinds of waste really are disgusting. SUVs, for example, would
arguably be gross even if they ran on a fuel which would never
run out and generated no pollution. SUVs are gross because they're
the solution to a gross problem. (How to make minivans look more
masculine.)
But not all waste is bad. Now that we have the infrastructure
to support it, counting the minutes of your long-distance
calls starts to seem niggling. If you have the
resources, it's more elegant to think of all phone calls as
one kind of thing, no matter where the other person is.<br /><br />There's good waste, and bad waste. I'm interested
in good waste-- the kind where, by spending more, we can get
simpler designs. How will we take advantage of the opportunities
to waste cycles that we'll get from new, faster hardware?<br /><br />The desire for speed is so deeply engrained in us, with
our puny computers, that it will take a conscious effort
to overcome it. In language design, we should be consciously seeking out
situations where we can trade efficiency for even the
smallest increase in convenience.<br /><br /><br /><br />Most data structures exist because of speed. For example,
many languages today have both strings and lists. Semantically, strings
are more or less a subset of lists in which the elements are
characters. So why do you need a separate data type?
You don't, really. Strings only
exist for efficiency. But it's lame to clutter up the semantics
of the language with hacks to make programs run faster.
Having strings in a language seems to be a case of
premature optimization.<br /><br />If we think of the core of a language as a set of axioms,
surely it's gross to have additional axioms that add no expressive
power, simply for the sake of efficiency. Efficiency is
important, but I don't think that's the right way to get it.<br /><br />The right way to solve that problem, I think, is to separate
the meaning of a program from the implementation details.
Instead of having both lists and strings, have just lists,
with some way to give the compiler optimization advice that
will allow it to lay out strings as contiguous bytes if
necessary.<br /><br />Since speed doesn't matter in most of a program, you won't
ordinarily need to bother with
this sort of micromanagement.
This will be more and more true as computers get faster.<br /><br /><br /><br />Saying less about implementation should also make programs
more flexible.
Specifications change while a program is being written, and this is not
only inevitable, but desirable.<br /><br />The word "essay" comes
from the French verb "essayer", which means "to try".
An essay, in the original sense, is something you
write to try to figure something out. This happens in
software too. I think some of the best programs were essays,
in the sense that the authors didn't know when they started
exactly what they were trying to write.<br /><br />Lisp hackers already know about the value of being flexible
with data structures. We tend to write the first version of
a program so that it does everything with lists. These
initial versions can be so shockingly inefficient that it
takes a conscious effort not to think about what they're
doing, just as, for me at least, eating a steak requires a
conscious effort not to think where it came from.<br /><br />What programmers in a hundred years will be looking for, most of
all, is a language where you can throw together an unbelievably
inefficient version 1 of a program with the least possible
effort. At least, that's how we'd describe it in present-day
terms. What they'll say is that they want a language that's
easy to program in.<br /><br />Inefficient software isn't gross. What's gross is a language
that makes programmers do needless work. Wasting programmer time
is the true inefficiency, not wasting machine time. This will
become ever more clear as computers get faster.<br /><br /><br /><br />I think getting rid of strings is already something we
could bear to think about. We did it in <a href="arc.html">Arc</a>, and it seems
to be a win; some operations that would be awkward to
describe as regular expressions can be described
easily as recursive functions.<br /><br />How far will this flattening of data structures go? I can think
of possibilities that shock even me, with my conscientiously broadened
mind. Will we get rid of arrays, for example? After all, they're
just a subset of hash tables where the keys are vectors of
integers. Will we replace hash tables themselves with lists?<br /><br />There are more shocking prospects even than that. The Lisp
that McCarthy described in 1960, for example, didn't
have numbers. Logically, you don't need to have a separate notion
of numbers, because you can represent them as lists: the integer
n could be represented as a list of n elements. You can do math this
way. It's just unbearably inefficient.<br /><br />No one actually proposed implementing numbers as lists in
practice. In fact, McCarthy's 1960 paper was not, at the time,
intended to be implemented at all. It was a <a href="rootsoflisp.html">theoretical exercise</a>,
an attempt to create a more elegant alternative to the Turing
Machine. When someone did, unexpectedly, take this paper and
translate it into a working Lisp interpreter, numbers certainly
weren't represented as lists; they were represented in binary,
as in every other language.<br /><br />Could a programming language go so far as to get rid of numbers
as a fundamental data type? I ask this not so much as a serious
question as as a way to play chicken with the future. It's like
the hypothetical case of an irresistible force meeting an
immovable object-- here, an unimaginably inefficient
implementation meeting unimaginably great resources.
I don't see why not. The future is pretty long. If there's
something we can do to decrease the number of axioms in the core
language, that would seem to be the side to bet on as t approaches
infinity. If the idea still seems unbearable in a hundred years,
maybe it won't in a thousand.<br /><br />Just to be clear about this, I'm not proposing that all numerical
calculations would actually be carried out using lists. I'm proposing
that the core language, prior to any additional notations about
implementation, be defined this way. In practice any program
that wanted to do any amount of math would probably represent
numbers in binary, but this would be an optimization, not part of
the core language semantics.<br /><br /><br /><br />Another way to burn up cycles is to have many layers of
software between the application and the hardware. This too is
a trend we see happening already: many recent languages are
compiled into byte code. Bill Woods once told me that,
as a rule of thumb, each layer of interpretation costs a
factor of 10 in speed. This extra cost buys you flexibility.<br /><br />The very first version of Arc was an extreme case of this sort
of multi-level slowness, with corresponding benefits. It
was a classic "metacircular" interpreter written
on top of Common Lisp, with a definite family resemblance
to the eval function defined in McCarthy's original Lisp paper.
The whole thing was only a couple hundred lines of
code, so it was very easy to understand and change. The
Common Lisp we used, CLisp, itself runs on top
of a byte code interpreter. So here we had two levels of
interpretation, one of them (the top one) shockingly inefficient,
and the language was usable. Barely usable, I admit, but
usable.<br /><br />Writing software as multiple layers is a powerful technique
even within applications. Bottom-up programming means writing
a program as a series of layers, each of which serves as a
language for the one above. This approach tends to yield
smaller, more flexible programs. It's also the best route to
that holy grail, reusability. A language is by definition
reusable. The more
of your application you can push down into a language for writing
that type of application, the more of your software will be
reusable.<br /><br />Somehow the idea of reusability got attached
to object-oriented programming in the 1980s, and no amount of
evidence to the contrary seems to be able to shake it free. But
although some object-oriented software is reusable, what makes
it reusable is its bottom-upness, not its object-orientedness.
Consider libraries: they're reusable because they're language,
whether they're written in an object-oriented style or not.<br /><br />I don't predict the demise of object-oriented programming, by the
way. Though I don't think it has much to offer good programmers,
except in certain specialized domains, it is irresistible to
large organizations. Object-oriented programming
offers a sustainable way to write spaghetti code. It lets you accrete
programs as a series of patches.
<!--, without the effort of understanding,
or the risk of breaking, existing code. -->
Large organizations
always tend to develop software this way, and I expect this
to be as true in a hundred years as it is today.<br /><br /><br /><br />
As long as we're talking about the future, we had better
talk about parallel computation, because that's where this
idea seems to live. That is, no matter when you're talking, parallel
computation seems to be something that is going to happen
in the future.<br /><br />Will the future ever catch up with it? People have been
talking about parallel computation as something imminent
for at least 20
years, and it hasn't affected programming practice much so far.
Or hasn't it? Already
chip designers have to think about it, and so must
people trying to write systems software on multi-cpu computers.<br /><br />The real question is, how far up the ladder of abstraction will
parallelism go?
In a hundred years will it affect even application programmers? Or
will it be something that compiler writers think about, but
which is usually invisible in the source code of applications?<br /><br />One thing that does seem likely is that most opportunities for
parallelism will be wasted. This is a special case of my more
general prediction that most of the extra computer power we're
given will go to waste. I expect that, as with the stupendous
speed of the underlying hardware, parallelism will be something
that is available if you ask for it explicitly, but ordinarily
not used. This implies that the kind of parallelism we have in
a hundred years will not, except in special applications, be
massive parallelism. I expect for
ordinary programmers it will be more like being able to fork off
processes that all end up running in parallel.<br /><br />And this will, like asking for specific implementations of data
structures, be something that you do fairly late in the life of a
program, when you try to optimize it. Version 1s will ordinarily
ignore any advantages to be got from parallel computation, just
as they will ignore advantages to be got from specific representations
of data.<br /><br />Except in special kinds of applications, parallelism won't
pervade the programs that are written in a hundred years. It would be
premature optimization if it did.<br /><br /><br /><br />How many programming languages will there
be in a hundred years? There seem to be a huge number of new
programming languages lately. Part of the reason is that
faster hardware has allowed programmers to make different
tradeoffs between speed and convenience, depending on the
application. If this is a real trend, the hardware we'll
have in a hundred years should only increase it.<br /><br />And yet there may be only a few widely-used languages in a
hundred years. Part of the reason I say this
is optimism: it seems that, if you did a really good job,
you could make a language that was ideal for writing a
slow version 1, and yet with the right optimization advice
to the compiler, would also yield very fast code when necessary.
So, since I'm optimistic, I'm going to predict that despite
the huge gap they'll have between acceptable and maximal
efficiency, programmers in a hundred years will have languages
that can span most of it.<br /><br />As this gap widens, profilers will become increasingly important.
Little attention is paid to profiling now. Many people still
seem to believe that the way to get fast applications is to
write compilers that generate fast code. As the gap between
acceptable and maximal performance widens, it will become
increasingly clear that the way to get fast applications is
to have a good guide from one to the other.<br /><br />When I say there may only be a few languages, I'm not including
domain-specific "little languages". I think such embedded languages
are a great idea, and I expect them to proliferate. But I expect
them to be written as thin enough skins that users can see
the general-purpose language underneath.<br /><br /><br /><br />Who will design the languages of the future? One of the most exciting
trends in the last ten years has been the rise of open-source
languages like Perl, Python, and Ruby.
Language design is being taken over by hackers. The results
so far are messy, but encouraging. There are some stunningly
novel ideas in Perl, for example. Many are stunningly bad, but
that's always true of ambitious efforts. At its current rate
of mutation, God knows what Perl might evolve into in a hundred
years.<br /><br />It's not true that those who can't do, teach (some of the best
hackers I know are professors), but it is true that there are a
lot of things that those who teach can't do. <a href="desres.html">Research</a> imposes
constraining caste restrictions. In any academic
field there are topics that are ok to work on and others that
aren't. Unfortunately the distinction between acceptable and
forbidden topics is usually based on how intellectual
the work sounds when described in research papers, rather than
how important it is for getting good results. The extreme case
is probably literature; people studying literature rarely
say anything that would be of the slightest use to those
producing it.<br /><br />Though the situation is better in the sciences,
the overlap between the kind of work you're allowed to do and the
kind of work that yields good languages is distressingly small.
(Olin Shivers has grumbled eloquently
about this.) For example, types seem to be an inexhaustible source
of research papers, despite the fact that static typing
seems to preclude true macros-- without which, in my opinion, no
language is worth using.<br /><br />The trend is not merely toward languages being developed
as open-source projects rather than "research", but toward
languages being designed by the application programmers who need
to use them, rather than by compiler writers. This seems a good
trend and I expect it to continue.<br /><br /><br /><br />
Unlike physics in a hundred years, which is almost necessarily
impossible to predict, I think it may be possible in principle
to design a language now that would appeal to users in a hundred
years.<br /><br />One way to design a language is to just write down the program
you'd like to be able to write, regardless of whether there
is a compiler that can translate it or hardware that can run it.
When you do this you can assume unlimited resources. It seems
like we ought to be able to imagine unlimited resources as well
today as in a hundred years.<br /><br />What program would one like to write? Whatever is least work.
Except not quite: whatever <i>would be</i> least work if your ideas about
programming weren't already influenced by the languages you're
currently used to. Such influence can be so pervasive that
it takes a great effort to overcome it. You'd think it would
be obvious to creatures as lazy as us how to express a program
with the least effort. In fact, our ideas about what's possible
tend to be so <a href="avg.html">limited</a> by whatever language we think in that
easier formulations of programs seem very surprising. They're
something you have to discover, not something you naturally
sink into.<br /><br />One helpful trick here
is to use the <a href="power.html">length</a> of the program as an approximation for
how much work it is to write. Not the length in characters,
of course, but the length in distinct syntactic elements-- basically,
the size of the parse tree. It may not be quite true that
the shortest program is the least work to write, but it's
close enough that you're better off aiming for the solid
target of brevity than the fuzzy, nearby one of least work.
Then the algorithm for language design becomes: look at a program
and ask, is there any way to write this that's shorter?<br /><br />In practice, writing programs in an imaginary hundred-year
language will work to varying degrees depending
on how close you are to the core. Sort routines you can
write now. But it would be
hard to predict now what kinds of libraries might be needed in
a hundred years. Presumably many libraries will be for domains that
don't even exist yet. If SETI@home works, for example, we'll
need libraries for communicating with aliens. Unless of course
they are sufficiently advanced that they already communicate
in XML.<br /><br />At the other extreme, I think you might be able to design the
core language today. In fact, some might argue that it was already
mostly designed in 1958.<br /><br /><br /><br />If the hundred year language were available today, would we
want to program in it? One way to answer this question is to
look back. If present-day programming languages had been available
in 1960, would anyone have wanted to use them?<br /><br />In some ways, the answer is no. Languages today assume
infrastructure that didn't exist in 1960. For example, a language
in which indentation is significant, like Python, would not
work very well on printer terminals. But putting such problems
aside-- assuming, for example, that programs were all just
written on paper-- would programmers of the 1960s have liked
writing programs in the languages we use now?<br /><br />I think so.
Some of the less imaginative ones,
who had artifacts of early languages built into their ideas of
what a program was, might have had trouble. (How can you manipulate
data without doing pointer arithmetic? How can you implement
flow charts without gotos?) But I think the smartest programmers
would have had no trouble making the most of present-day
languages, if they'd had them.<br /><br />If we had the hundred-year language now, it would at least make a
great pseudocode. What about using it to write software?
Since the hundred-year language
will need to generate fast code for some applications, presumably
it could generate code efficient enough to run acceptably well
on our hardware. We might have to give more optimization advice
than users in a hundred years, but it still might be a net win.<br /><br /><br /><br />Now we have two ideas that, if you combine them, suggest interesting
possibilities: (1) the hundred-year language could, in principle, be
designed today, and (2) such a language, if it existed, might be good to
program in today. When you see these ideas laid out like that,
it's hard not to think, why not try writing the hundred-year language
now?<br /><br />When you're working on language design, I think it is good to
have such a target and to keep it consciously in mind. When you
learn to drive, one of the principles they teach you is to
align the car not by lining up the hood with the stripes painted
on the road, but by aiming at some point in the distance. Even
if all you care about is what happens in the next ten feet, this
is the right answer. I
think we can and should do the same thing with programming languages.<br /><br /><br /><br />
<b>Notes</b><br /><br />I believe Lisp Machine Lisp was the first language to embody
the principle that declarations (except those of dynamic variables)
were merely optimization advice,
and would not change the meaning of a correct program. Common Lisp
seems to have been the first to state this explicitly.<br /><br /><b>Thanks</b> to Trevor Blackwell, Robert Morris, and Dan Giffin for
reading drafts of this, and to Guido van Rossum, Jeremy Hylton, and the
rest of the Python crew for inviting me to speak at PyCon.<br /><br /><br clear="all" /></font></td></tr></table><table border="0" cellspacing="0" cellpadding="0" width="435"><tr><td><font size="2" face="verdana"><br><br><hr>
<table width=410 cellpadding=0 cellspacing=0>
<tr><td bgcolor=#ffe799><img src="http://www.virtumundo.com/images/spacer.gif"
height=15 width=1><font size=2 face=verdana>
You'll find this essay and 14 others in
<a href="hackpaint.html"><b><i>Hackers & Painters</i></b></a>.</font>
</font>
<br><img src="http://www.virtumundo.com/images/spacer.gif" height=5 width=1></td
></tr>
</table></font></td></tr></table></td></tr></table></body>
<script type="text/javascript">
csell_env = 'ue1';
var storeCheckoutDomain = 'order.store.turbify.net';
</script>
<script type="text/javascript">
function toOSTN(node){
if(node.hasAttributes()){
for (const attr of node.attributes) {
node.setAttribute(attr.name,attr.value.replace(/(us-dc1-order|us-dc2-order|order)\.(store|stores)\.([a-z0-9-]+)\.(net|com)/g, storeCheckoutDomain));
}
}
};
document.addEventListener('readystatechange', event => {
if(typeof storeCheckoutDomain != 'undefined' && storeCheckoutDomain != "order.store.turbify.net"){
if (event.target.readyState === "interactive") {
fromOSYN = document.getElementsByTagName('form');
for (let i = 0; i < fromOSYN.length; i++) {
toOSTN(fromOSYN[i]);
}
}
}
});
</script>
<script type="text/javascript">
// Begin Store Generated Code
</script> <script type="text/javascript" src="https://s.turbifycdn.com/lq/ult/ylc_1.9.js" ></script> <script type="text/javascript" src="https://s.turbifycdn.com/ae/lib/smbiz/store/csell/beacon-a9518fc6e4.js" >
</script>
<script type="text/javascript">
// Begin Store Generated Code
csell_page_data = {}; csell_page_rec_data = []; ts='TOK_STORE_ID';
</script>
<script type="text/javascript">
// Begin Store Generated Code
function csell_GLOBAL_INIT_TAG() { var csell_token_map = {}; csell_token_map['TOK_SPACEID'] = '2022276099'; csell_token_map['TOK_URL'] = ''; csell_token_map['TOK_STORE_ID'] = 'paulgraham'; csell_token_map['TOK_ITEM_ID_LIST'] = 'hundred'; csell_token_map['TOK_ORDER_HOST'] = 'order.store.turbify.net'; csell_token_map['TOK_BEACON_TYPE'] = 'prod'; csell_token_map['TOK_RAND_KEY'] = 't'; csell_token_map['TOK_IS_ORDERABLE'] = '2'; c = csell_page_data; var x = (typeof storeCheckoutDomain == 'string')?storeCheckoutDomain:'order.store.turbify.net'; var t = csell_token_map; c['s'] = t['TOK_SPACEID']; c['url'] = t['TOK_URL']; c['si'] = t[ts]; c['ii'] = t['TOK_ITEM_ID_LIST']; c['bt'] = t['TOK_BEACON_TYPE']; c['rnd'] = t['TOK_RAND_KEY']; c['io'] = t['TOK_IS_ORDERABLE']; YStore.addItemUrl = 'http%s://'+x+'/'+t[ts]+'/ymix/MetaController.html?eventName.addEvent&cartDS.shoppingcart_ROW0_m_orderItemVector_ROW0_m_itemId=%s&cartDS.shoppingcart_ROW0_m_orderItemVector_ROW0_m_quantity=1&ysco_key_cs_item=1&sectionId=ysco.cart&ysco_key_store_id='+t[ts]; }
</script>
<script type="text/javascript">
// Begin Store Generated Code
function csell_REC_VIEW_TAG() { var env = (typeof csell_env == 'string')?csell_env:'prod'; var p = csell_page_data; var a = '/sid='+p['si']+'/io='+p['io']+'/ii='+p['ii']+'/bt='+p['bt']+'-view'+'/en='+env; var r=Math.random(); YStore.CrossSellBeacon.renderBeaconWithRecData(p['url']+'/p/s='+p['s']+'/'+p['rnd']+'='+r+a); }
</script>
<script type="text/javascript">
// Begin Store Generated Code
var csell_token_map = {}; csell_token_map['TOK_PAGE'] = 'p'; csell_token_map['TOK_CURR_SYM'] = '$'; csell_token_map['TOK_WS_URL'] = 'https://paulgraham.csell.store.turbify.net/cs/recommend?itemids=hundred&location=p'; csell_token_map['TOK_SHOW_CS_RECS'] = 'false'; var t = csell_token_map; csell_GLOBAL_INIT_TAG(); YStore.page = t['TOK_PAGE']; YStore.currencySymbol = t['TOK_CURR_SYM']; YStore.crossSellUrl = t['TOK_WS_URL']; YStore.showCSRecs = t['TOK_SHOW_CS_RECS']; </script> <script type="text/javascript" src="https://s.turbifycdn.com/ae/store/secure/recs-1.3.2.2.js" ></script> <script type="text/javascript" >
</script>
</html>
<!-- html107.prod.store.e1a.lumsb.com Wed May 27 01:42:07 PDT 2026 -->

Binary file not shown.

View File

@@ -0,0 +1,349 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
<meta name="generator" content="Adobe GoLive 5">
<title>Worse Is Better</title>
<link href="Dreamsongs.css" rel="stylesheet" type="text/css" media="all">
</head>
<body>
<div align="center">
<a href="index.html"><img src="Files/DreamsongsBannerWeb.jpg" width="800" height="95" border="0"></a>
</div>
<h1>Lisp: Good News, Bad News, How to Win Big</h1>
<h2 class="center">Richard P. Gabriel</h2>
<h3 class="center">Lucid, Inc</h3>
<p><i>This article was originally published in 1991.</i></p>
<h2>Abstract</h2>
<p>Lisp has done quite well over the last ten years: becoming nearly standardized, forming the basis of a commercial sector, achieving excellent performance, having good environments, able to deliver applications. Yet the Lisp community has failed to do as well as it could have. In this paper I look at the successes, the failures, and what to do next.</p>
<p>The Lisp world is in great shape: Ten years ago there was no standard Lisp; the most standard Lisp was InterLisp, which ran on PDP-10s and Xerox Lisp machines (some said it ran on Vaxes, but I think they exaggerated); the second most standard Lisp was MacLisp, which ran only on PDP-10s, but under the three most popular operating systems for that machine; the third most standard Lisp was Portable Standard Lisp, which ran on many machines, but very few people wanted to use it; the fourth most standard Lisp was Zetalisp, which ran on two varieties of Lisp machine; and the fifth most standard Lisp was Scheme, which ran on a few different kinds of machine, but very few people wanted to use it. By today&rsquo;s standards, each of these had poor or just barely acceptable performance, nonexistent or just barely satisfactory environments, nonexistent or poor integration with other languages and software, poor portability, poor acceptance, and poor commercial prospects.</p>
<p>Today there is Common Lisp (CL), which runs on all major machines, all major operating systems, and virtually in every country. Common Lisp is about to be standardized by ANSI, has good performance, is surrounded with good environments, and has good integration with other languages and software.</p>
<p>But, as a business, Lisp is considered to be in ill health. There are persistent and sometimes true rumors about the abandonment of Lisp as a vehicle for delivery of practical applications.</p>
<p>To some extent the problem is one of perception -- there are simply better Lisp delivery solutions than are generally believed to exist and to a disturbing extent the problem is one of unplaced or misplaced resources, of projects not undertaken, and of implementation strategies not activated.</p>
<p>Part of the problem stems from our very dear friends in the artificial intelligence (AI) business. AI has a number of good approaches to formalizing human knowledge and problem solving behavior. However, AI does not provide a panacea in any area of its applicability. Some early promoters of AI to the commercial world raised expectation levels too high. These expectations had to do with the effectiveness and deliverability of expert-system-based applications.</p>
<p>When these expectations were not met, some looked for scapegoats, which frequently were the Lisp companies, particularly when it came to deliverability. Of course, if the AI companies had any notion about what the market would eventually expect from delivered AI software, they never shared it with any Lisp companies I know about. I believe the attitude of the AI companies was that the Lisp companies will do what they need to survive, so why share customer lists and information with them?</p>
<p>Another part of the problem is the relatively bad press Lisp got, sometimes from very respectable publications. I saw an article in Forbes (October 16, 1989) entitled <i>Where Lisp Slipped</i> by Julie Pitta. However, the article was about Symbolics and its fortunes. The largest criticisms of Symbolics in the article are that Symbolics believed AI would take off and that Symbolics mistakenly pushed its view that proprietary hardware was the way to go for AI. There was nothing about Lisp in the article except the statement that it is a <i>somewhat obscure programming language used extensively in artificial intelligence</i>.</p>
<p>It seems a pity for the Lisp business to take a bump partly because Julie thought she could make a cute title for her article out of the name <i>Lisp</i>.</p>
<p>But, there are some real successes for Lisp, some problems, and some ways out of those problems.</p>
<h2>1 Lisp&rsquo;s Successes</h2>
<p>As I mentioned, Lisp is in better shape today than it ever has been. I want to review some Lisp success stories.</p>
<h3>1.1 Standardization</h3>
<p>A major success is that there is a standard Lisp -- Common Lisp. Many observers today wish there were a simpler, smaller, cleaner Lisp that could be standardized, but the Lisp that we have today that is ready for standardization is Common Lisp. This isn&rsquo;t to say that a better Lisp could not be standardized later, and certainly there should be. Furthermore, like any language, Common Lisp should be improved and changed as needs change.</p>
<p>Common Lisp started as a grassroots effort in 1981 after an ARPA-sponsored meeting held at SRI to determine the future of Lisp. At that time there were a number of Lisps in the US being defined and implemented by former MIT folks: Greenblatt (LMI), Moon and Weinreb (Symbolics), Fahlman and Steele (CMU), White (MIT), and Gabriel and Steele (LLNL). The core of the Common Lisp committee came from this group. That core was Fahlman, Gabriel, Moon, Steele, and Weinreb, and Common Lisp was a coalescence of the Lisps these people cared about.</p>
<p>There were other Lisps that could have blended into Common Lisp, but they were not so clearly in the MacLisp tradition, and their proponents declined to actively participate in the effort because they predicted success for their own dialects over any common lisp that was defined by the grassroots effort. Among these Lisps were Scheme, Interlisp, Franz Lisp, Portable Standard Lisp, and Lisp370.</p>
<p>And outside the US there were major Lisp efforts, including Cambridge Lisp and Le-Lisp. The humble US grassroots effort did not seek membership from outside the US, and one can safely regard that as a mistake. Frankly, it never occurred to the Common Lisp group that this purely American effort would be of interest outside the US, because very few of the group saw a future in AI that would extend the needs for a standard Lisp beyond North America.</p>
<p>Common Lisp was defined and a book published in 1984 called /Common Lisp: the Language/ (CLtL). And several companies sprang up to put Common Lisp on stock hardware to compete against the Lisp machine companies. Within four years, virtually every major computer company had a Common Lisp that it had either implemented itself or private-labeled from a Common Lisp company.</p>
<p>In 1986, X3J13 was formed to produce an ANSI version of Common Lisp. By then it was apparent that there were significant changes required to Common Lisp to clean up ambiguities and omissions, to add a condition system, and to define object-oriented extensions.</p>
<p>After several years it became clear that the process of standardization was not simple, even given a mature language with a good definition. The specification of the Common Lisp Object System (CLOS) alone took nearly two years and seven of the most talented members of X3J13.</p>
<p>It also became apparent that the interest in international Lisp standardization was growing. But there was no heir apparent to Common Lisp. Critics of Common Lisp, especially those outside the US, focused on Common Lisp&rsquo;s failures as a practical delivery vehicle.</p>
<p>In 1988, an international working group for the standardization of Lisp was formed. That group is called WG16. Two things are absolutely clear: The near-term standard Lisp is Common Lisp; a longer-term standard that goes beyond Common Lisp is desirable.</p>
<p>In 1988, the IEEE Scheme working group was formed to produce an IEEE and possibly an ANSI standard for Scheme. This group completed its work in 1990, and the relatively small and clean Scheme is a standard.</p>
<p>Currently, X3J13 is less than a year away from a draft standard for ANSI Common Lisp; WG16 is stalled because of international bickering; Scheme has been standardized by IEEE, but it is of limited commercial interest.</p>
<p>Common Lisp is in use internationally, and serves at least as a de facto standard until the always contentious Lisp community agrees to work together.</p>
<h3>1.2 Good Performance</h3>
<p>Common Lisp performs well. Most current implementations use modern compiler technology, in contrast to older Lisps, which used very primitive compiler techniques, even for the time. In terms of performance, anyone using a Common Lisp today on almost any computer can expect better performance than could be obtained on single-user PDP-10s or on single-user Lisp machines of mid-1980s vintage. Many Common Lisp implementations have multitasking and non-intrusive garbage collection -- both regarded as impossible features on stock hardware ten years ago.</p>
<p>In fact, Common Lisp performs well on benchmarks compared to C. The following table shows the ratio of Lisp time and code size to C time and code size for three benchmarks.</p>
<table width="376" border="1" cellspacing="2" cellpadding="0">
<tr>
<td></td>
<td>
<div align="center">
<b>CPU Time</b></div>
</td>
<td>
<div align="center">
<b>Code Size</b></div>
</td>
</tr>
<tr>
<td>Tak </td>
<td>
<div align="center">
0.90</div>
</td>
<td>
<div align="center">
1.21</div>
</td>
</tr>
<tr>
<td>Traverse</td>
<td>
<div align="center">
0.98</div>
</td>
<td>
<div align="center">
1.35</div>
</td>
</tr>
<tr>
<td>Lexer</td>
<td>
<div align="center">
1.07</div>
</td>
<td>
<div align="center">
1.48</div>
</td>
</tr>
</table>
<p>Tak is a Gabriel benchmark that measures function calling and fixnum arithmetic. Traverse is a Gabriel benchmark that measures structure creation and access. Lexer is the tokenizer of a C compiler and measures dispatching and character manipulation.</p>
<p>These benchmarks were run on a Sun 3 in 1987 using the standard Sun C compiler using full optimization. The Lisp was not running a non-intrusive garbage collector.</p>
<h3>1.3 Good Environments</h3>
<p>It is arguable that modern programming environments come from the Lisp and AI tradition. The first bit-mapped terminals (Stanford/MIT), the mouse pointing device (SRI), full-screen text editors (Stanford/MIT), and windowed environments (Xerox PARC) all came from laboratories engaged in AI research. Even today one can argue that the Symbolics programming environment represents the state of the art.</p>
<p>It is also arguable that the following development environment features originated in the Lisp world:</p>
<ul>
<li>Incremental compilation and loading
<li>Symbolic debuggers
<li>Data inspectors
<li>Source code level single stepping
<li>Help on builtin operators
<li>Window-based debugging
<li>Symbolic stack backtraces
<li>Structure editors
</ul>
<p>Today&rsquo;s Lisp environments are equal to the very best Lisp machine environments in the 1970s. Windowing, fancy editing, and good debugging are all commonplace. In some Lisp systems, significant attention has been paid to the software lifecycle through the use of source control facilities, automatic cross-referencing, and automatic testing.</p>
<h3>1.4 Good Integration</h3>
<p>Today Lisp code can coexist with C, Pascal, Fortran, etc. These languages can be invoked from Lisp and in general, these languages can then re-invoke Lisp. Such interfaces allow the programmer to pass Lisp data to foreign code, to pass foreign data to Lisp code, to manipulate foreign data from Lisp code, to manipulate Lisp data from foreign code, to dynamically load foreign programs, and to freely mix foreign and Lisp functions.</p>
<p>The facilities for this functionality are quite extensive and provide a means for mixing several different languages at once.</p>
<h3>1.5 Object-oriented Programming</h3>
<p>Lisp has the most powerful, comprehensive, and pervasively object-oriented extensions of any language. CLOS embodies features not found in any other object-oriented language. These include the following:</p>
<ul>
<li>Multiple inheritance
<li>Generic functions including multi-methods
<li>First-class classes
<li>First-class generic functions
<li>Metaclasses
<li>Method combination
<li>Initialization protocols
<li>Metaobject protocol
<li>Integration with Lisp types
</ul>
<p>It is likely that Common Lisp (with CLOS) will be the first standardized object-oriented programming language.</p>
<h3>1.6 Delivery</h3>
<p>It is possible to deliver applications written in Lisp. The currently available tools are good but are not yet ideal. These solutions include from removing unused code and data from application, building up applications using only the code and data needed, and producing .o files from Lisp code.</p>
<p>Delivery tools are commercially provided by Lucid, Franz, and Ibuki.</p>
<h2>2 Lisp&rsquo;s Apparent Failures</h2>
<p class="poetry">Too many teardrops for one heart to be crying.<br>
Too many teardrops for one heart to carry on.<br>
You&rsquo;re way on top now, since you left me,<br>
Always laughing, way down at me.<br>
<br>
<i>? &amp; The Mysterians</i></p>
<p>This happy story, though, has a sad interlude, an interlude that might be attributed to the failure of AI to soar, but which probably has some other grains of truth that we must heed. The key problem with Lisp today stems from the tension between two opposing software philosophies. The two philosophies are called <i>The Right Thing</i> and <i>Worse is Better</i>.</p>
<h3>2.1 The Rise of <i>Worse is Better</i></h3>
<p>I and just about every designer of Common Lisp and CLOS has had extreme exposure to the MIT/Stanford style of design. The essence of this style can be captured by the phrase <i>the right thing</i>. To such a designer it is important to get all of the following characteristics right:</p>
<ul>
<li>Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.
<li>Correctness -- the design must be correct in all observable aspects. Incorrectness is simply not allowed.
<li>Consistency -- the design must not be inconsistent. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.
<li>Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.
</ul>
<p>I believe most people would agree that these are good characteristics. I will call the use of this philosophy of design the <i>MIT approach</i>. Common Lisp (with CLOS) and Scheme represent the MIT approach to design and implementation.</p>
<p>The worse-is-better philosophy is only slightly different:</p>
<ul>
<li>Simplicity -- the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.
<li>Correctness -- the design must be correct in all observable aspects. It is slightly better to be simple than correct.
<li>Consistency -- the design must not be overly inconsistent. Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.
<li>Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.</ul>
<p>Early Unix and C are examples of the use of this school of design, and I will call the use of this design strategy the <i>New Jersey approach</i>. I have intentionally caricatured the worse-is-better philosophy to convince you that it is obviously a bad philosophy and that the New Jersey approach is a bad approach.</p>
<p>However, I believe that worse-is-better, even in its strawman form, has better survival characteristics than the-right-thing, and that the New Jersey approach when used for software is a better approach than the MIT approach.</p>
<p>Let me start out by retelling a story that shows that the MIT/New-Jersey distinction is valid and that proponents of each philosophy actually believe their philosophy is better.</p>
<p>Two famous people, one from MIT and another from Berkeley (but working on Unix) once met to discuss operating system issues. The person from MIT was knowledgeable about ITS (the MIT AI Lab operating system) and had been reading the Unix sources. He was interested in how Unix solved the PC loser-ing problem. The PC loser-ing problem occurs when a user program invokes a system routine to perform a lengthy operation that might have significant state, such as IO buffers. If an interrupt occurs during the operation, the state of the user program must be saved. Because the invocation of the system routine is usually a single instruction, the PC of the user program does not adequately capture the state of the process. The system routine must either back out or press forward. The right thing is to back out and restore the user program PC to the instruction that invoked the system routine so that resumption of the user program after the interrupt, for example, re-enters the system routine. It is called <i>PC loser-ing</i> because the PC is being coerced into <i>loser mode</i>, where <i>loser</i> is the affectionate name for <i>user</i> at MIT.</p>
<p>The MIT guy did not see any code that handled this case and asked the New Jersey guy how the problem was handled. The New Jersey guy said that the Unix folks were aware of the problem, but the solution was for the system routine to always finish, but sometimes an error code would be returned that signaled that the system routine had failed to complete its action. A correct user program, then, had to check the error code to determine whether to simply try the system routine again. The MIT guy did not like this solution because it was not the right thing.</p>
<p>The New Jersey guy said that the Unix solution was right because the design philosophy of Unix was simplicity and that the right thing was too complex. Besides, programmers could easily insert this extra test and loop. The MIT guy pointed out that the implementation was simple but the interface to the functionality was complex. The New Jersey guy said that the right tradeoff has been selected in Unix -- namely, implementation simplicity was more important than interface simplicity.</p>
<p>The MIT guy then muttered that sometimes it takes a tough man to make a tender chicken, but the New Jersey guy didn&rsquo;t understand (I&rsquo;m not sure I do either).</p>
<p>Now I want to argue that worse-is-better is better. C is a programming language designed for writing Unix, and it was designed using the New Jersey approach. C is therefore a language for which it is easy to write a decent compiler, and it requires the programmer to write text that is easy for the compiler to interpret. Some have called C a fancy assembly language. Both early Unix and C compilers had simple structures, are easy to port, require few machine resources to run, and provide about 50%-80% of what you want from an operating system and programming language.</p>
<p>Half the computers that exist at any point are worse than median (smaller or slower). Unix and C work fine on them. The worse-is-better philosophy means that implementation simplicity has highest priority, which means Unix and C are easy to port on such machines. Therefore, one expects that if the 50% functionality Unix and C support is satisfactory, they will start to appear everywhere. And they have, haven&rsquo;t they?</p>
<p>Unix and C are the ultimate computer viruses.</p>
<p>A further benefit of the worse-is-better philosophy is that the programmer is conditioned to sacrifice some safety, convenience, and hassle to get good performance and modest resource use. Programs written using the New Jersey approach will work well both in small machines and large ones, and the code will be portable because it is written on top of a virus.</p>
<p>It is important to remember that the initial virus has to be basically good. If so, the viral spread is assured as long as it is portable. Once the virus has spread, there will be pressure to improve it, possibly by increasing its functionality closer to 90%, but users have already been conditioned to accept worse than the right thing. Therefore, the worse-is-better software first will gain acceptance, second will condition its users to expect less, and third will be improved to a point that is almost the right thing. In concrete terms, even though Lisp compilers in 1987 were about as good as C compilers, there are many more compiler experts who want to make C compilers better than want to make Lisp compilers better.</p>
<p>The good news is that in 1995 we will have a good operating system and programming language; the bad news is that they will be Unix and C++.</p>
<p>There is a final benefit to worse-is-better. Because a New Jersey language and system are not really powerful enough to build complex monolithic software, large systems must be designed to reuse components. Therefore, a tradition of integration springs up.</p>
<p>How does the right thing stack up? There are two basic scenarios: the <i>big complex system scenario</i> and the <i>diamond-like jewel</i> scenario.</p>
<p>The <i>big complex system</i> scenario goes like this:</p>
<p>First, the right thing needs to be designed. Then its implementation needs to be designed. Finally it is implemented. Because it is the right thing, it has nearly 100% of desired functionality, and implementation simplicity was never a concern so it takes a long time to implement. It is large and complex. It requires complex tools to use properly. The last 20% takes 80% of the effort, and so the right thing takes a long time to get out, and it only runs satisfactorily on the most sophisticated hardware.</p>
<p>The <i>diamond-like jewel</i> scenario goes like this:</p>
<p>The right thing takes forever to design, but it is quite small at every point along the way. To implement it to run fast is either impossible or beyond the capabilities of most implementors.</p>
<p>The two scenarios correspond to Common Lisp and Scheme.</p>
<p>The first scenario is also the scenario for classic artificial intelligence software.</p>
<p>The right thing is frequently a monolithic piece of software, but for no reason other than that the right thing is often designed monolithically. That is, this characteristic is a happenstance.</p>
<p>The lesson to be learned from this is that it is often undesirable to go for the right thing first. It is better to get half of the right thing available so that it spreads like a virus. Once people are hooked on it, take the time to improve it to 90% of the right thing.</p>
<p>A wrong lesson is to take the parable literally and to conclude that C is the right vehicle for AI software. The 50% solution has to be basically right, and in this case it isn&rsquo;t.</p>
<p>But, one can conclude only that the Lisp community needs to seriously rethink its position on Lisp design. I will say more about this later.</p>
<h3>2.2 Good Lisp Programming is Hard</h3>
<p>Many Lisp enthusiasts believe that Lisp programming is easy. This is true up to a point. When real applications need to be delivered, the code needs to perform well. With C, programming is always difficult because the compiler requires so much description and there are so few data types. In Lisp it is very easy to write programs that perform very poorly; in C it is almost impossible to do that. The following examples of badly performing Lisp programs were all written by competent Lisp programmers while writing real applications that were intended for deployment. I find these quite sad.</p>
<h4>2.2.1 Bad Declarations</h4>
<p>This example is a mistake that is easy to make. The programmer here did not declare his arrays as fully as he could have. Therefore, each array access was about as slow as a function call when it should have been a few instructions. The original declaration was as follows:</p>
<pre>
(proclaim '(type (array fixnum *) *ar1* *ar2* *ar3*))
</pre>
<p>The three arrays happen to be of fixed size, which is reflected in the following correct declaration:</p>
<pre>
(proclaim '(type (simple-array fixnum (4)) *ar1*))
(proclaim '(type (simple-array fixnum (4 4)) *ar2*))
(proclaim '(type (simple-array fixnum (4 4 4)) *ar3*))
</pre>
<p>Altering the faulty declaration improved the performance of the entire system by 20%.</p>
<h4>2.2.2 Poor Knowledge of the Implementation</h4>
<p>The next example is where the implementation has not optimized a particular case of a general facility, and the programmer has used the general facility thinking it will be fast. Here five values are being returned in a situation where the order of side effects is critical:</p>
<pre>
(multiple-value-prog1
(values (f1 x)
(f2 y)
(f3 y)
(f4 y)
(f5 y))
(setf (aref ar1 i1) (f6 y))
(f7 x y))
</pre>
<p>The implementation happens to optimize multiple-value-prog1 for up to three return values, but the case of five values CONSes. The correct code follows:</p>
<pre>
(let ((x1 (f1 x))
(x2 (f2 y))
(x3 (f3 y))
(x4 (f4 y))
(x5 (f5 y)))
(setf (aref ar1 i1) (f6 y))
(f7 x y)
(values x1 x2 x3 x4 x5))
</pre>
<p>There is no reason that a programmer should know that this rewrite is needed. On the other hand, finding that performance was not as expected should not have led the manager of the programmer in question to conclude, as he did, that Lisp was the wrong language.</p>
<h4>2.2.3 Use of FORTRAN Idioms</h4>
<p>Some Common Lisp compilers do not optimize the same way as others. The following expression is sometimes used:</p>
<pre>
(* -1 &lt;form&gt;)
</pre>
<p>when compilers often produce better code for this variant:</p>
<pre>
(- &lt;form&gt;)
</pre>
<p>Of course, the first is the Lisp analog of the FORTRAN idiom:</p>
<pre>
- -1*&lt;form&gt;
</pre>
<h4>2.2.4 Totally Inappropriate Data Structures</h4>
<p>Some might find this example hard to believe. This really occurred in some code I&rsquo;ve seen:</p>
<pre>
(defun make-matrix (n m)
(let ((matrix ()))
(dotimes (i n matrix)
(push (make-list m) matrix))))
(defun add-matrix (m1 m2)
(let ((l1 (length m1))
(l2 (length m2)))
(let ((matrix (make-matrix l1 l2)))
(dotimes (i l1 matrix)
(dotimes (j l2)
(setf (nth i (nth j matrix))
(+ (nth i (nth j m1))
(nth i (nth j m2)))))))))
</pre>
<p>What&rsquo;s worse is that in the particular application, the matrices were all fixed size, and matrix arithmetic would have been just as fast in Lisp as in FORTRAN.</p>
<p>This example is bitterly sad: The code is absolutely beautiful, but it adds matrices slowly. Therefore it is excellent prototype code and lousy production code. You know, you cannot write production code as bad as this in C.</p>
<h3>2.3 Integration is God</h3>
<p>In the worse-is-better world, integration is linking your .o files together, freely intercalling functions, and using the same basic data representations. You don&rsquo;t have a foreign loader, you don&rsquo;t coerce types across function-call boundaries, you don&rsquo;t make one language dominant, and you don&rsquo;t make the woes of your implementation technology impact the entire system.</p>
<p>The very best Lisp foreign functionality is simply a joke when faced with the above reality. Every item on the list can be addressed in a Lisp implementation. This is just not the way Lisp implementations have been done in the right thing world.</p>
<p>The virus lives while the complex organism is stillborn. Lisp must adapt, not the other way around. The right thing and 2 shillings will get you a cup of tea.</p>
<h3>2.4 Non-Lisp Environments are Catching Up</h3>
<p>This is hard to face up to. For example, most C environments -- initially imitative of Lisp environments -- are now pretty good. Current best C environments have the following:</p>
<ul>
<li>Symbolic debuggers
<li>Data inspectors
<li>Source code level single stepping
<li>Help on builtin operators
<li>Window-based debugging
<li>Symbolic stack backtraces
<li>Structure editors
</ul>
<p>And soon they will have incremental compilation and loading. These environments are easily extendible to other languages, with multi-lingual environments not far behind.</p>
<p>Though still the best, current Lisp environments have several prominent failures. First, they tend to be window-based but not well integrated. That is, related information is not represented so as to convey the relationship. A multitude of windows does not mean integration, and neither does being implemented in the same language and running in the same image. In fact, I believe no currently available Lisp environment has any serious amount of integration.</p>
<p>Second, they are not persistent. They seemed to be defined for a single login session. Files are used to keep persistent data -- how 1960s.</p>
<p>Third, they are not multi-lingual even when foreign interfaces are available.</p>
<p>Fourth, they do not address the software lifecycle in any extensive way. Documentation, specifications, maintenance, testing, validation, modification, and customer support are all ignored.</p>
<p>Fifth, information is not brought to bear at the right times. The compiler is able to provide some information, but the environment should be able to generally know what is fully defined and what is partially defined. Performance monitoring should not be a chore.</p>
<p>Sixth, using the environment is difficult. There are too many things to know. It&rsquo;s just too hard to manage the mechanics.</p>
<p>Seventh, environments are not multi-user when almost all interesting software is now written in groups.</p>
<p>The real problem has been that almost no progress in Lisp environments has been made in the last 10 years.</p>
<h2>3 How Lisp Can Win Big</h2>
<p>When the sun comes up, I&rsquo;ll be on top.<br>
You&rsquo;re right down there looking up.<br>
On my way to come up here,<br>
I&rsquo;m gonna see you waiting there.<br>
I&rsquo;m on my way to get next to you.<br>
I know now that I&rsquo;m gonna get there.<br>
<br>
<i>? &amp; The Mysterians</i></p>
<p>The gloomy interlude can have a happy ending.</p>
<h3>3.1 Continue Standardization Progress</h3>
<p>We need to bury our differences at the ISO level and realize that there is a short term need, which must be Common Lisp, and a long term need, which must address all the issues for practical applications.</p>
<p>We&rsquo;ve seen that the right thing attitude has brought us a very large, complex-to-understand, and complex-to-implement Lisp -- Common Lisp that solves way too many problems. We need to move beyond Common Lisp for the future, but that does not imply giving up on Common Lisp now. We&rsquo;ve seen it is possible to do delivery of applications, and I think it is possible to provide tools that make it easier to write applications for deployment. A lot of work has gone into getting Common Lisp to the point of a <i>right thing</i> in many ways, and there are viable commercial implementations. But we need to solve the delivery and integration problems in spades.</p>
<p>Earlier I characterized the MIT approach as often yielding stillborn results. To stop Common Lisp standardization now is equivalent to abortion, and that is equivalent to the Lisp community giving up on Lisp. If we want to adopt the New Jersey approach, it is wrong to give up on Lisp, because C just isn&rsquo;t the right language for AI.</p>
<p>It also simply is not possible to dump Common Lisp now, work on a new standard, and then standardize in a timely fashion. Common Lisp is all we have at the moment. No other dialect is ready for standardization.</p>
<p>Scheme is a smaller Lisp, but it also suffers from the MIT approach. It is too tight and not appropriate for large-scale software. At least Common Lisp has some facilities for that.</p>
<p>I think there should be an internationally recognized standard for Common Lisp. I don&rsquo;t see what is to be gained by aborting the Common Lisp effort today just because it happens to not be the best solution to a commercial problem. For those who believe Lisp is dead or dying, what does killing off Common Lisp achieve but to convince people that the Lisp community kills its own kind? I wish less effort would go into preventing Common Lisp from becoming a standard when it cannot hurt to have several Lisp standards.</p>
<p>On the other hand, there should be a strong effort towards the next generation of Lisp. The worst thing we can do is to stand still as a community, and that is what is happening.</p>
<p>All interested parties must step forward for the longer-term effort.</p>
<h3>3.2 Retain the High Ground in Environments</h3>
<p>I think there is a mistake in following an environment path that creates monolithic environments. It should be possible to use a variety of tools in an environment, and it should be possible for those who create new tools to be able to integrate them into the environment.</p>
<p>I believe that it is possible to build a tightly integrated environment that is built on an open architecture in which all tools, including language processors, are protocol-driven. I believe it is possible to create an environment that is multi-lingual and addresses the software lifecycle problem without imposing a particular software methodology on its users.</p>
<p>Our environments should not discriminate against non-Lisp programmers the way existing environments do. Lisp is not the center of the world.</p>
<h3>3.3 Implement Correctly</h3>
<p>Even though Common Lisp is not structured as a kernel plus libraries, it can be implemented that way. The kernel and library routines can be in the form of .o files for easy linking with other, possibly non-Lisp, modules; the implementation must make it possible to write, for example, small utility programs. It is also possible to piggyback on existing compilers, especially those that use common back ends. It is also possible to implement Lisp so that standard debuggers, possibly with extensions, can be made to work on Lisp code.</p>
<p>It might take time for developers of standard tools to agree to extend their tools to Lisp, but it certainly won&rsquo;t happen until our (exceptional) language is implemented more like ordinary ones.</p>
<h3>3.4 Achieve Total Integration</h3>
<p>I believe it is possible to implement a Lisp and surrounding environment which has no discrimination for or against any other language. It is possible using multi-lingual environments, clever representations of Lisp data, conservative garbage collection, and conventional calling protocols to make a completely integrated Lisp that has no demerits.</p>
<h3>3.5 Make Lisp the Premier Prototyping Language</h3>
<p>Lisp is still the best prototyping language. We need to push this forward. A multi-lingual environment could form the basis or infrastructure for a multi-lingual prototyping system. This means doing more research to find new ways to exploit Lisp&rsquo;s strengths and to introduce new ones.</p>
<p>Prototyping is the act of producing an initial implementation of a complex system. A prototype can be easily instrumented, monitored, and altered. Prototypes are often built from disparate parts that have been adapted to a new purpose. Descriptions of the construction of a prototype often involve statements about modifying the behavioral characteristics of an existing program. For example, suppose there exists a tree traversal program. The description of a prototype using this program might start out by saying something like</p>
<pre>
let S1 be the sequence of leaf nodes visited by P on tree T1 and S2 the
leaf nodes visited by P on tree T2. Let C be a correspondence between
S1 and S2 where f: S1 ! S2 maps elements to corresponding elements.
</pre>
<p>Subsequent statements might manipulate the correspondence and use f. Once the definition of a leaf node is made explicit, this is a precise enough statement for a system to be able to modify the traversal routine to support the correspondence and f.</p>
<p>A language that describes the modification and control of an existing program can be termed a program language. Program languages be built on one or several underlying programming languages, and in fact can be implemented as part of the functionality of the prototyping environment. This view is built on the insight that an environment is a mechanism to assist a programmer in creating a working program, including preparing the source text. There is no necessary requirement that an environment be limited to working only with raw source text. As another example, some systems comprise several processes communicating through channels. The creation of this part of the system can be visual, with the final result produced by the environment being a set of source code in several languages, build scripts, link directives, and operating system calls. Because no single programming language encompasses the program language, one could call such a language an epi-language.</p>
<h3>3.6 The Next Lisp</h3>
<p>I think there will be a next Lisp. This Lisp must be carefully designed, using the principles for success we saw in worse-is-better.</p>
<p>There should be a simple, easily implementable kernel to the Lisp. That kernel should be both more than Scheme -- modules and macros -- and less than Scheme -- continuations remain an ugly stain on the otherwise clean manuscript of Scheme.</p>
<p>The kernel should emphasize implementational simplicity, but not at the expense of interface simplicity. Where one conflicts with the other, the capability should be left out of the kernel. One reason is so that the kernel can serve as an extension language for other systems, much as GNU Emacs uses a version of Lisp for defining Emacs macros.</p>
<p>Some aspects of the extreme dynamism of Common Lisp should be reexamined, or at least the tradeoffs reconsidered. For example, how often does a real program do this?</p>
<pre>
(defun f ...)
(dotimes (...)
...
(setf (symbol-function 'f) #'(lambda ...))
...)
</pre>
<p>Implementations of the next Lisp should not be influenced by previous implementations to make this operation fast, especially at the expense of poor performance of all other function calls.</p>
<p>The language should be segmented into at least four layers:</p>
<ol>
<li>The kernel language, which is small and simple to implement. In all cases, the need for dynamic redefinition should be re-examined to determine that support at this level is necessary. I believe nothing in the kernel need be dynamically redefinable.
<li>A linguistic layer for fleshing out the language. This layer may have some implementational difficulties, and it will probably have dynamic aspects that are too expensive for the kernel but too important to leave out.
<li>A library. Most of what is in Common Lisp would be in this layer.
<li>Environmentally provided epilinguistic features.
</ol>
<p>In the first layer I include conditionals, function calling, all primitive data structures, macros, single values, and very basic object-oriented support.</p>
<p>In the second layer I include multiple values and more elaborate object-oriented support. The second layer is for difficult programming constructs that are too important to leave to environments to provide, but which have sufficient semantic consequences to warrant precise definition. Some forms of redefinition capabilities might reside here.</p>
<p>In the third layer I include sequence functions, the elaborate IO functions, and anything else that is simply implemented in the first and possibly the second layers. These functions should be linkable.</p>
<p>In the fourth layer I include those capabilities that an environment can and should provide, but which must be standardized. A typical example is defmethod from CLOS. In CLOS, generic functions are made of methods, each method applicable to certain classes. The first layer has a definition form for a complete generic function -- that is, for a generic function along with all of its methods, defined in one place (which is how the layer 1 compiler wants to see it). There will also be means of associating a name with the generic function. However, while developing a system, classes will be defined in various places, and it makes sense to be able to see relevant (applicable) methods adjacent to these classes. defmethod is the construct to define methods, and defmethod forms can be placed anywhere amongst other definitional forms.</p>
<p>But methods are relevant to each class on which the method is specialized, and also to each subclass of those classes. So, where should the unique defmethod form be placed? The environment should allow the programmer to see the method definition in any or all of these places, while the real definition should be in some particular place. That place might as well be in the single generic function definition form, and it is up to the environment to show the defmethod equivalent near relevant classes when required, and to accept as input the source in the form of a defmethod (which it then places in the generic function definition).</p>
<p>We want to standardize the defmethod form, but it is a linguistic feature provided by the environment. Similarly, many uses of elaborate lambda-list syntax, such as keyword arguments, are examples of linguistic support that the environment can provide possibly by using color or other adjuncts to the text.</p>
<p>In fact, the area of function-function interfaces should be re-examined to see what sorts of argument naming schemes are needed and in which layer they need to be placed.</p>
<p>Finally, note that it might be that every layer 2 capability could be provided in a layer 1 implementation by an environment.</p>
<h3>3.7 Help Application Writers Win</h3>
<p>The Lisp community has too few application writers. The Lisp vendors need to make sure these application writers win. To do this requires that the parties involved be open about their problems and not adversarial. For example, when an expert system shell company finds problems, it should open up its source code to the Lisp vendor so that both can work towards the common goal of making a faster, smaller, more deliverable product. And the Lisp vendors should do the same.</p>
<p>The business leadership of the AI community seems to have adopted the worst caricature-like traits of business practice: secrecy, mistrust, run-up-the-score competitiveness. We are an industry that has enough common competitors without searching for them among our own ranks.</p>
<p>Sometimes the sun also rises.</p>
<h2>References</h2>
<dl>
<dt>[1] ? &amp; the Mysterians, <i>96 Tears</i>, Pa-go-go Records 1966, re-released on Cameo Records, September 1966.
</dl>
</body>
</html>

View File

@@ -0,0 +1,80 @@
<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=ISO-8859-1">
<meta name="generator" content="Adobe GoLive 5">
<title>Rise of Worse Is Better</title>
<link href="Dreamsongs.css" rel="stylesheet" type="text/css" media="all">
</head>
<body>
<div align="center">
<a href="index.html"><img src="Files/DreamsongsBannerWeb.jpg" width="800" height="95" border="0"></a>
</div>
<h1>The Rise of Worse is Better</h1>
<h2 class="center">Richard P. Gabriel</h2>
<h3 class="center">Lucid, Inc</h3>
<p>{an excerpt from &quot;Lisp: Good News, Bad News, How to Win Big.&quot; [<a href="WIB.html">html</a>]}</p>
<h3>2.1 The Rise of <i>Worse is Better</i></h3>
<p>I and just about every designer of Common Lisp and CLOS has had extreme exposure to the MIT/Stanford style of design. The essence of this style can be captured by the phrase <i>the right thing</i>. To such a designer it is important to get all of the following characteristics right:</p>
<ul>
<li>Simplicity -- the design must be simple, both in implementation and interface. It is more important for the interface to be simple than the implementation.
<li>Correctness -- the design must be correct in all observable aspects. Incorrectness is simply not allowed.
<li>Consistency -- the design must not be inconsistent. A design is allowed to be slightly less simple and less complete to avoid inconsistency. Consistency is as important as correctness.
<li>Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases must be covered. Simplicity is not allowed to overly reduce completeness.
</ul>
<p>I believe most people would agree that these are good characteristics. I will call the use of this philosophy of design the <i>MIT approach</i>. Common Lisp (with CLOS) and Scheme represent the MIT approach to design and implementation.</p>
<p>The worse-is-better philosophy is only slightly different:</p>
<ul>
<li>Simplicity -- the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.
<li>Correctness -- the design must be correct in all observable aspects. It is slightly better to be simple than correct.
<li>Consistency -- the design must not be overly inconsistent. Consistency can be sacrificed for simplicity in some cases, but it is better to drop those parts of the design that deal with less common circumstances than to introduce either implementational complexity or inconsistency.
<li>Completeness -- the design must cover as many important situations as is practical. All reasonably expected cases should be covered. Completeness can be sacrificed in favor of any other quality. In fact, completeness must be sacrificed whenever implementation simplicity is jeopardized. Consistency can be sacrificed to achieve completeness if simplicity is retained; especially worthless is consistency of interface.</ul>
<p>Early Unix and C are examples of the use of this school of design, and I will call the use of this design strategy the <i>New Jersey approach</i>. I have intentionally caricatured the worse-is-better philosophy to convince you that it is obviously a bad philosophy and that the New Jersey approach is a bad approach.</p>
<p>However, I believe that worse-is-better, even in its strawman form, has better survival characteristics than the-right-thing, and that the New Jersey approach when used for software is a better approach than the MIT approach.</p>
<p>Let me start out by retelling a story that shows that the MIT/New-Jersey distinction is valid and that proponents of each philosophy actually believe their philosophy is better.</p>
<p>Two famous people, one from MIT and another from Berkeley (but working on Unix) once met to discuss operating system issues. The person from MIT was knowledgeable about ITS (the MIT AI Lab operating system) and had been reading the Unix sources. He was interested in how Unix solved the PC loser-ing problem. The PC loser-ing problem occurs when a user program invokes a system routine to perform a lengthy operation that might have significant state, such as IO buffers. If an interrupt occurs during the operation, the state of the user program must be saved. Because the invocation of the system routine is usually a single instruction, the PC of the user program does not adequately capture the state of the process. The system routine must either back out or press forward. The right thing is to back out and restore the user program PC to the instruction that invoked the system routine so that resumption of the user program after the interrupt, for example, re-enters the system routine. It is called <i>PC loser-ing</i> because the PC is being coerced into <i>loser mode</i>, where <i>loser</i> is the affectionate name for <i>user</i> at MIT.</p>
<p>The MIT guy did not see any code that handled this case and asked the New Jersey guy how the problem was handled. The New Jersey guy said that the Unix folks were aware of the problem, but the solution was for the system routine to always finish, but sometimes an error code would be returned that signaled that the system routine had failed to complete its action. A correct user program, then, had to check the error code to determine whether to simply try the system routine again. The MIT guy did not like this solution because it was not the right thing.</p>
<p>The New Jersey guy said that the Unix solution was right because the design philosophy of Unix was simplicity and that the right thing was too complex. Besides, programmers could easily insert this extra test and loop. The MIT guy pointed out that the implementation was simple but the interface to the functionality was complex. The New Jersey guy said that the right tradeoff has been selected in Unix -- namely, implementation simplicity was more important than interface simplicity.</p>
<p>The MIT guy then muttered that sometimes it takes a tough man to make a tender chicken, but the New Jersey guy didn&rsquo;t understand (I&rsquo;m not sure I do either).</p>
<p>Now I want to argue that worse-is-better is better. C is a programming language designed for writing Unix, and it was designed using the New Jersey approach. C is therefore a language for which it is easy to write a decent compiler, and it requires the programmer to write text that is easy for the compiler to interpret. Some have called C a fancy assembly language. Both early Unix and C compilers had simple structures, are easy to port, require few machine resources to run, and provide about 50%-80% of what you want from an operating system and programming language.</p>
<p>Half the computers that exist at any point are worse than median (smaller or slower). Unix and C work fine on them. The worse-is-better philosophy means that implementation simplicity has highest priority, which means Unix and C are easy to port on such machines. Therefore, one expects that if the 50% functionality Unix and C support is satisfactory, they will start to appear everywhere. And they have, haven&rsquo;t they?</p>
<p>Unix and C are the ultimate computer viruses.</p>
<p>A further benefit of the worse-is-better philosophy is that the programmer is conditioned to sacrifice some safety, convenience, and hassle to get good performance and modest resource use. Programs written using the New Jersey approach will work well both in small machines and large ones, and the code will be portable because it is written on top of a virus.</p>
<p>It is important to remember that the initial virus has to be basically good. If so, the viral spread is assured as long as it is portable. Once the virus has spread, there will be pressure to improve it, possibly by increasing its functionality closer to 90%, but users have already been conditioned to accept worse than the right thing. Therefore, the worse-is-better software first will gain acceptance, second will condition its users to expect less, and third will be improved to a point that is almost the right thing. In concrete terms, even though Lisp compilers in 1987 were about as good as C compilers, there are many more compiler experts who want to make C compilers better than want to make Lisp compilers better.</p>
<p>The good news is that in 1995 we will have a good operating system and programming language; the bad news is that they will be Unix and C++.</p>
<p>There is a final benefit to worse-is-better. Because a New Jersey language and system are not really powerful enough to build complex monolithic software, large systems must be designed to reuse components. Therefore, a tradition of integration springs up.</p>
<p>How does the right thing stack up? There are two basic scenarios: the <i>big complex system scenario</i> and the <i>diamond-like jewel</i> scenario.</p>
<p>The <i>big complex system</i> scenario goes like this:</p>
<p>First, the right thing needs to be designed. Then its implementation needs to be designed. Finally it is implemented. Because it is the right thing, it has nearly 100% of desired functionality, and implementation simplicity was never a concern so it takes a long time to implement. It is large and complex. It requires complex tools to use properly. The last 20% takes 80% of the effort, and so the right thing takes a long time to get out, and it only runs satisfactorily on the most sophisticated hardware.</p>
<p>The <i>diamond-like jewel</i> scenario goes like this:</p>
<p>The right thing takes forever to design, but it is quite small at every point along the way. To implement it to run fast is either impossible or beyond the capabilities of most implementors.</p>
<p>The two scenarios correspond to Common Lisp and Scheme.</p>
<p>The first scenario is also the scenario for classic artificial intelligence software.</p>
<p>The right thing is frequently a monolithic piece of software, but for no reason other than that the right thing is often designed monolithically. That is, this characteristic is a happenstance.</p>
<p>The lesson to be learned from this is that it is often undesirable to go for the right thing first. It is better to get half of the right thing available so that it spreads like a virus. Once people are hooked on it, take the time to improve it to 90% of the right thing.</p>
<p>A wrong lesson is to take the parable literally and to conclude that C is the right vehicle for AI software. The 50% solution has to be basically right, and in this case it isn&rsquo;t.</p>
<p>But, one can conclude only that the Lisp community needs to seriously rethink its position on Lisp design. I will say more about this later.</p>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
<pre>
</pre>
</body>
</html>

Binary file not shown.