Depth and Innate Judgements
I moved this essay here from the Grogix Blog.
Which mental faculties are involved in programming? If we knew more about them, could we invent programming languages that were both easier to use and more powerful?
This is not a well-studied area, and very few aspects of programming languages, old or new, are evaluated formally for the quality of their "human factors" or "user experience". For example, among the features of artificial languages, there has been no attempt to separate experimentally those features that are cultural artifacts, from those that reflect our innate, genetically-endowed mental capacities.
Clearly, much of the mental functionality required to program is shared by our faculty of language, a statement that appears to be also true of our capacity for symbolic manipulation within mathematics and music. To find out more than this, however, we need to construct some investigative theory.
Linguists, in order to investigate a native speaker's unconscious knowledge of language, will construct experiments that use the speaker's unconscious judgment. For example, a speaker (who could be the linguist) is presented one sentence, and asked whether or not it is grammatical. The subject doesn't usually know why, but only knows that it either is grammatical, or isn't, to some degree. In another case, the speaker may be presented two sentences and asked if they mean the same thing.
Throughout our daily lives, we make judgments about quality. Sometimes we judge something "by itself" for "some quality", perhaps relative to our experience, perhaps with our innate judgment. Sometimes we compare things to each other, as in visual preference surveys, to determine whether one has "more" of "some quality" than another.
We also rank things: and I'd like to differentiate these temporarily into two additional categories, because it points to an abstraction:
1) A rank relative to some quality
2) A rank relative to a sense of order, or form
One can imagine a linguistic study of the construction of a line in a poem, where two words are compared with each other to see which is "more profound", say, or "more juicy". This substantive judgment is of type (1). One can also imagine a question like: "is it better to put the first part of the sentence in front of the second, or to reverse them?" This is an appeal to an innate judgment about order, and so would seem to fall into category (2), however, it is also a comparison between two sentences, or possibly among multiple lists of items, and so, really, falls into category (1), using "good order" or "good form" as a judgment quality. This judgment is suspiciously grammatical in nature, even though it could easily apply to order outside the realm of human language, say, for the order of the steps in building a table -- a point we'll return to later.
The action in (2) gives us an inductive procedure to build something larger, in pairs, lists, forms, etc. It sound like Aristotle's use of a hierarchy of forms, or formal cause, to resolve the question of whether the "Ship of Theseus", whose boards are all gradually replaced, is still the same ship. Aristotle's answer was that the form is all that is actually important ... although we have a constitutional habit of stopping the subdivision of form at certain 'substances'. If you believe that you are the same person you were ten years ago, then you agree with Aristotle, because your body's materials are completely replaced in that time.
For reasons I won't go into right here, (1) is also really (2). All judgment is a judgment of form. Let's accept this Aristotelian position for a moment. This allows Christopher Alexander to comes into our discussion of evaluation procedures, which we'll need to discover better forms of programming languages.
In A Pattern Language, which inspired the Design Patterns movement among programmers, Alexander puts patterns into a natural order, and also marks each pattern's quality, according to its level of profundity. In the first book published in the same series, The Oregon Experiment, he also made maps of the University of Oregon campus to determine which areas worked best. At the time, he was simply using intuition, feeling and group agreement to determine these qualities. But he was pursuing more.
He was pursuing a procedure of innate judgment, an experimental procedure, and a creative tool, that would allow someone to pursue greater depth of quality in form.
Published over 20 years after A Pattern Language, Alexander explained his findings at length in the series The Nature of Order.
He describes 'depth of quality' in many ways, and, humans being linguistic communicators, these descriptions are themselves part of the teaching the method of finding increasing depth. To boil down his descriptions: things that are truly good have a living quality which the possess because they unfolded through an ordered, stepwise differentiation, producing a field of strong centers (itself a center) that are ordered and mutually reinforcing.
Clearly, biological organisms fit this description. And human artifacts can too, if people follow a natural process to create something complex, coherent and full of life.
The use of feeling as an evaluation procedure has the effect, Alexander finds, of eliciting profound work. Most human creative work of a high caliber already uses this procedure. He believes it produces certain identifiable properties in the results (see The 15 Properties in the first volume).
In the fourth volume, called The Luminous Ground, he goes even further to describe levels of identification with centers, which act as evaluation procedures that will produce increasing depth of quality:
1) I find it pleasing.
2) I feel related to it.
3) I feel this relationship in me.
4) It touches the core of me.
5) I begin to identify with it.
6) Its spirit and mine are intertwined.
7) Its spirit and mine are of one substance.
8) I am in it, and it is in me.
9) I am it, and it is me.
10) We are, together, part of the universal I.
(Note that these are my quick summaries of Alexander's work, but he and I worked together for a few years, so I don't think I'm too far off. Still, I highly recommend studying the original books, whose nuance is quite important.)
The point here is to obtain some descriptive adequacy of the phenomena of "comparative quality" used by people. I have not begun to explain it, and so there is no explicit theory here with any explanatory adequacy. One does not need to, for example, "believe" in the "universal I" to understand that there are innate human capacities revealed by these procedures.
Alexander uses these evaluation procedures not just for good design, but to create good tools for good design. His primary tool in the past few decades is the sequence, a set of ordered steps which one follows in order to design something good -- if the sequence is good. Each step applies to everything in the design that is appropriate, and so the sequences tend to elicit critical boundaries and large structures first, followed by steps that create increasingly small detail.
Each step takes a lot of work to get right: it needs to make sense in itself, it needs to relate to the steps around it in the sequence, and it needs to be in the right place in the sequence. It must be evocative, inspiring, but not overwhelming. It must be declarative, rather than instructive: "There are beautiful, alternating spaces in the fence" rather than "put alternating spaces in the fence". Most importantly, the sequences need to be tried and debugged, until they produce wonderful results.
In this paper, I tried to use this application of evaluation procedures on the smooth unfolding of a single program, working on it over and over, until I had some consistent satisfaction that the unfolding of the sequence, for this one program, was good.
But this doesn't easily or immediately help the actual writing of programs. It is instructive to build a program-unfolding sequence, and I built a tool that makes these sequences easier to write, test and edit. It's a useful collaboration and research exercise, similar to analysis by design patterns. Unfortunately, it is one step removed from the necessary engineering. One writes a program to unfold a program, rather than my preference: to simply program using some kind of sequence that actually defines a system, and re-writing it until one's evaluation procedures are satisfied, and the system works properly.
I needed a new kind of programming language for that.
Now, programming languages are human artifacts. We make them. Some are better in some respects than others. For some qualitative comparisons among them, there is near universal agreement. Since we already make qualitative comparisons about artificial languages, and since our use of artificial languages is only possible because of our use of unexamined human faculties, I believe there may be some advantage to using Alexander's procedures of quality evaluation to create a better artificial language.
Earlier, I said that my goal is to bridge the gap between the expressive power of the genetic code, and the expressive power of the best modern programming languages. The chasm is vast. And it is not clear that it can be bridged: there is no reason to accept an a priori dogma that such a powerful notation "must" exist. We are not ribosomes ... and ribosomes are not human. The 3 billion ordered base pairs (essentially bits) that become a human being are not necessarily structured in a way that will be useful to our comprehension of complex systems. But, it's a little early to give up. After all, the problem has barely been recognized.
Also, the gap between the expressive power of genetic and man-made formalisms, is best characterized by the gap in the resulting complexity and coherence. These are exactly those qualities that characterized the challenge Alexander faced in the design of cities and living spaces, complex problems that I believe he has tackled with increasing success.
When I loosen my mind and open my heart, in order to use Alexander's evaluation procedures, I begin to whittle down my basic questions about programming languages, further and further. I first discard all of my thoughts about axiomatic reduction, logical consistency, derivation and denotation. I simply look for the natural geometry that underlies all good programming, something that keeps it all coherent, keeps it all together, and gives it life. At the end of my whittling, I have one question: what organization of symbols, in any system, gives me the most expressive power?
The symbolic system needs self-reference: that is, recursion or feedback. It needs to reflect the ordered unfolding of living organisms. It needs to stay coherent no matter how complex it becomes. It needs unity, and wholeness.
The answer that came to me seemed strange at first: a formal grammar. My internal critic pointed out that grammars are great for pattern-matching and transformation, but that's a kind of parsing, really, and not exactly fully expressive of all computation. Right? Well, my internal response was that we really don't know what grammars are ... sets of pattern-transform-action rules are only the major use of grammars in computer science today. There may be others. In Noam Chomsky's half-century of study, syntactic structures are in the middle, mediating all expression of thought, giving form to the connections among memory, innate ideas, and the sensorimotor interfaces. Aristotle also says that form is everything. So, maybe my result from the use of the evaluation procedure is correct. Anyone going through the same process should be able to corroborate this, if the evaluation procedure itself is effective. My conclusion is that any good program must be a kind of grammar. And like any program, the 'meaning' of these grammar-like structures would then be identical with their mechanical function, as we make use of them in the outside world.
Given the idea of a grammar-program, my follow-up question in October of 2009 was: how do I do this? L-systems of productions create a static structure, and I'd used this idea here to generate code, but I didn't really know how to make a grammar do anything besides parse, re-write, and map actions to patterns ...
Then I looked at the original point of the generator I'd built before, for a kind of wiki, and thought, wait, there's a hierarchically unfolding structure in the function of this program. It does very simple things to start, and then the increasingly complex things it does are built of the earlier simpler things it does. It's basically a grammar augmented by a secondary state machine, that is, it does real-time evaluation of productions, which are selected depending upon the state.
The formal grammar acts as a kind of "pump". The system flows through the core grammar. You could think of the productions a being like functions, but a group of functions rarely conveys a sense of a whole, in the way that a single grammar does.
Outside of the grammar are interfaces to the world. In the case of this first working program, the grammar passes HTML pages to the interface, which passes them to the outside world, which in turn passes responses back to the interface and the grammar. Parts of the grammar are used at different times based on states and needs, but they are part of one grammar representing the whole system.
Since they helped me to uncover a good primary organizing principle for 'blooming logic', I should use these Alexandrian evaluation procedures to develop good secondary features in the language. I'm not completely satisfied with the ones I developed rapidly in order to make the primary idea work. But I'll use the procedures to repair and improve the situation, and to create simpler interfaces, so that the power of the grammar is increasingly clear to whichever human faculties are involved in expressing thought, and expressing desired functionality, with this notation.