A great story of lispy discovery

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.

There is no behind your back on the Internet

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.

Why type systems are right

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.

Self and value slots

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.

C type system

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!

Why type systems are wrong

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?


Notes

*See Ontology is Overrated: Categories, Links, and Tags for a decent exposition on this topic.

Rewriting

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.

On Class Modeling

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.

Haskell Types and Goedel’s Incompleteness Theorem

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

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

Why I switched to Clojure

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.