Not Lisp again . . .
I’m always searching for a good way to explain what you can do
with Lisp that you can’t do with most other languages. Joe
Marshall has a compelling story, from a skeptic’s point of view,
for what makes functional programming different. There are
multiple parts that trace his way through a course at MIT and
toward a love of lisp.
From the post:
I was floored. Here we take the simple, straightforward definition of the derivative of a function. Type it in with essentially no modification (we’re a little cavalier about dropping the limit and just defining dx to be a ‘reasonably small number’) and suddenly the computer knew how to do calculus! This was serious magic. I had never seen anything like it before.
Good stuff. It made me
revisit Structure
and Interpretation of Computer Programs, an
all-time classic.
February 28, 2009 – 6:00 am
Why is it that people unfailingly want to put words in my mouth on
the Internet?
I suppose it happens all the time in everyday speech. Or behind
my back. But on the Internet, everything you say is visible to
all. There is no behind your back. And seeing it in writing,
permanently attached to your site, that just sucks. It is one of
the main reasons I have disabled comments*.
I (often) write what I believe. I have written articles I am not
proud of. Either because I did not do enough research or I wrote
what I thought others wanted to hear. But you catch the same
flack for regretable articles as you do for the really personal
ones. But the personal pieces–the ones that express my views,
whether right or wrong–at least meant something to me when I
wrote them. They might actually lend themselves to communication
on a deeper level. But, invariably, those are the ones people
call “flame bait”.
I guess that means I should just keep writing what I want. It is
more enjoyable, anyway.
Notes
*I have gotten many
enlightening comments as well as intolerable idiocy. It was not
an easy decision.
February 28, 2009 – 6:00 am
Type systems are right because they impose a rigid view of a
domain (otherwise known as a model) that can then be reasoned
about in a structured and reliable way. Well defined types define
an ordered space in which the programmer can solve a problem.
Outside of that space lies chaos.
February 28, 2009 – 6:00 am
In Programming as an Experience: The Inspiration
for
Self,
the authors discuss successes and failures in bringing uniformity
and minimalism to the language. One such failure is that data
slots and method slots have different semantics.
They discuss different options for unifying method semantics. All
of the options they mentioned were disagreeable with the authors,
since they require methods to be treated fundamentally differently
from data. Any attempt to make a method (that is, runnable code)
act like data (that is, values) breaks the unity.
What is weird to me is that they do not discuss making data act
like code. Why do they not make all slots act like method
slots?* That is the idea of getter and setter methods. It
is so simple and uniform and solves the problem. Why did they not
try this? Or did they?
I wonder what a Self programmer thinks of this.
Notes
*See the id object system for an example of creating a
prototype-based language with unified semantics for data and
methods.
February 28, 2009 – 6:00 am
C’s type system has been criticized for being flawed. It
certainly is not as logical as Haskell’s. I am not going to argue
with that. But C’s type system has (at least) one redeeming
quality: an escape hatch.
When the Creators brought C into existence, they endowed it with a
few datatypes and a way to make some new ones. But by letting any
pointer be cast to (void *), they blessed C with the unifying
principle that makes it so useful*. That principle is eloquently stated in three
words:
Bits is bits.
And its universality brings beauty to the language.
Notes
*And so annoyingly
dangerous!
February 27, 2009 – 6:00 am
Type systems are wrong because the world cannot be put into a tree
structure of categories*. Only a small,
controlled subset of the universe can be modeled by a given tree
structure. Far from making a system extensible and maintainable,
type systems often lead to their own inflexibility. Upon adding
type after type, a question inevitably emerges: where in the tree
do I put this new type?
February 27, 2009 – 6:00 am
Brittle class hierarchies serve a purpose. They let you model
your domain. In a sense, you are creating a language about the
problem. It is brittle because you want to know when it breaks so
you can fix the problem. But sometimes, if you are adding and
adding classes, legitimate stuff stops fitting in so neatly. You
kind of have to force it, because the model you chose did not
accomodate everything*.
There are many work-arounds. They will work in the short run.
Eventually, you will have to rewrite. Reorganize your class tree
to be more elegant. Because problems are best solved through
grace, simplicity, and order. Every time you fudge in a
new type, it will come back to haunt you. So take the time to
find an elegant solution.
In short, you should keep your program brief and to the point.
And rewrite it often.
Notes
*It is impossible to accomodate
everything. So don’t try.
February 27, 2009 – 6:00 am
I have always favored composition over inheritance. It seems like
the best way to reuse functionality. I reserve inheritance for
truly polymorphic types. Code reuse when inheriting is merely a
convenience. Inheritance should never be used just to reuse code.
Classes are like the fixed points in your code. They define
undeniable assumptions for your program. The world does not have
“classes”. Human minds impose them on themselves as shortcuts to
understanding the world.
You can always look at a thing to a greater level of detail. You
can think “this is a table” or “this is an object made of five
parts: a top and four legs” or “this is a coherent collection of
cellulose molecules interspersed with other types of molecules”.
It is a question of class modeling versus composition.
Your classes define your atoms–your units of composition. Your
classes determine what level of detail you are going to stop at.
And you should make sure all of your classes are at the same level
of detail. It would be difficult to describe the interactions
between a table and an atom*.
So, when modeling, you must choose powerful, general units of
composition. They will be fewer in number, but more expressive.
You will often have to rewrite old, clumsy class hierarchies at a
new level of detail. Such is the art of software.
Notes
*But is should be possible to
define the interaction between a table leg and a collection of
table parts.
February 27, 2009 – 6:00 am
Haskell’s type system disallows two broad classes of typing
problems. It does not allow what it can prove to be incorrect
(for example assigning a String value to
a Number variable). That makes sense. It also does not
allow anything that it cannot prove correct. That also makes
sense, though it is somewhat annoying when you can see that it
could be correct. This problem comes down to the issue of
provability.
Haskell has a restricted inference engine to deduce the type of
values. It is restricted to reasoning somewhere below first order
logic. There are definitely things you cannot prove without at
least first order logic*. So Haskell’s type engine cannot prove
every type inference I can know is correct. So it just blatantly
limits what you can say.
If it had a more powerful inference engine, one that was at least
as powerful as first order logic, it would not even know what it
could not prove. Such is the problem with powerful
logics*. That
means that there are typed expressions you could state that
Haskell would not be able to prove correct (or incorrect). And what is worse,
Haskell would not even know that it could not prove them. So
Haskell must be restricted to a lower-order logic.
At least, that’s what the type theorists say. Haskell will do
lots of type inference work for you, as long as you restrict your
type usage to a very limited range. And I choose not to
live with that restriction.
Addendum
2009-02-28
Thanks goes to Don Stewart for correcting a blatant error of mine
and revealing once again my near total ignorance.
I said above that Haskell’s type inference was hovering below
first-order logic, when in fact, according to Don Stewart, it is
equivalent to second order logic. I stand corrected.
Notes
*For example, the famous example
argument: Socrates is a man. All men are mortal. Therefore,
Socrates is mortal
*Google Goedel’s Incompleteness Theorem
February 20, 2009 – 6:00 am
Common Lisp is a dead end.
Clojure is a fresh start on the JVM. The JVM has a future and
inroads into just about everything.
And Clojure scratches my functional programming itch.
I want to be a part of Clojure’s bright future.