08 4 / 2013

Structural Editing Apocrypha

Here are some things from the Internet to whet your structural editing appetite.

The Interlisp Experience

The 1984 book Interactive Programming Environments, a collection of surveys of programming environments of the time, features this piece by Erik Sandewall detailing the development experience in an Interlisp environment.

UNIX and MIT Lisp Machines are also featured and discussed by their respective creators, but IMO pale in comparison.

Intentional Programming

Charles Simonyi has a vision for computing he calls “Intentional Programming” that’s pretty awesome.  Check out this database-backed structural editor for an Algol-like language.

Other Advancements

  • PEDIT was a structural editor for Prolog (which is homoiconic, btw)
  • Nokolisp was a Lisp environment written for minicomputers in the late 70s that features an impressive structural editor.

Are you aware of any structural program editing software or tools I don’t list here?

08 4 / 2013

Structural Editing Revisited

It’s been a little over three years since I first stumbled on the idea of a structural Lisp editor, and over a year since I last blogged about the idea.

Well, I have good news: Micha Niskin and I have overcome the technical challenges that I was unable to solo, and work toward a realtime structural Clojure editor suitable for our own professional use is underway.  We call it “stoke”, and I posted a short demo of our prototype on YouTube:

The editor consists of these main pieces:

  • reader: For code reading purposes, Clojure’s native reader does too much.  For instance, scalars like “+1.0e3” are read as a Double and later print as “100.0”.  Unordered collection types like sets and maps behave similarly, and the result is a mismatch between read and printed representations.  Our reader deals in only two types, symbols and sequences, and preserves enough information (using metadata) to print appropriately.
  • printer: We were able to extend Brandon Bloom’s excellent Fast Idiomatic Pretty Printer to print Clojure code idiomatically.  FIPP’s intermediate representation, the “document”, gives us a data representation of the formatted code that doesn’t necessarily need to be printed character-wise, and opens the door to interesting alternative views of code.
  • meta-zip: This is less a piece and more an abstraction that we have found crucial, and zippers will be the editor’s primary extension point.  Zipper navigation and manipulation of our symbol/sequence representation is trivial.  Meta-zip is a “zipper of zippers” that lets us cleanly model tree undo/redo.

Our immediate goal was to have a terminal-based structural editor with paredit commands, REPL, and file interaction, and as of this writing we are just about done with it.  Next up are a Swing frontend, network/multi-user editing, API cleanup, and possibly a public release.

However, if we stopped here we’d fail to take advantage of one of the greatest things about having our own structural editor: files are no longer essential.  What does this mean?  I think the implications are vast, incredible, and since the death of Interlisp have been largely unrealized.

We’re used to working in and around files and filesystems, and much of our programming tooling is file-oriented - package systems, revision control systems, editors, versioning idioms.  I think that collectively these systems represent an attempt to turn filesystems into the databases we wished they were, and I think that by storing Clojure code in Datomic we can throw most of them out.

I want to live in a world where code is stored in a temporal database and I build new programs with the combination of query and structural edit, and this is where we ultimately want to take stoke.  You can follow our progress at http://tailrecursion.com.

image

*update 4/8/13*

Beyond a code database, other implications of the symbols+sequences intermediate representation (and zipper navigation model) include:

*update 4/11/13*

Posted Clojure Structural Editor, Take 2 to YouTube

26 2 / 2013

A bad year, a good year. A little retrospective.

This past year has been simultaneously my most difficult and my most exciting, and I include previous years spent deployed to Iraq in that calculation.

The end of my marriage was the event that sent me into a tail spin just over a year ago.  Having now experienced both, I can testify that what they say is true: the end of a marriage is no less painful than the death of a loved one, and its effects at least as lasting and treacherous.

Fortunately the world is not complete shit, all the time.  With the help - for which I am forever grateful - of my family and friends, I kept on professionally, and completed an amazing two-year tenure with Relevance to join the also-incredible crew at LonoCloud.  My affiliation with Splat Space and its outreach initiatives continued to be a source of stability, inspiration, and happiness.

Somewhere in the middle I rekindled a connection with the physical and in November completed a GORUCK Challenge.  I encourage anyone with the means and a need to prove something to themselves to do the same.

I now look to the future with renewed and expanded senses.  Of how horrifying and dark life can be.  Of how important and meaningful family and friendship are.  Of how lucky I am.  Of my own ability to dropkick adversity in the face and kick it while its down.

I begin this next and enlightened chapter at The Fresh Diet, a company with an ambitious plan to revolutionize their business using Clojure, ClojureScript, and Datomic.  I invite you to join me and The Fresh Diet team at tailrecursion.com, where we hope to catalog our open source contributions as we go.  We have big plans, and it’s going to be an amazing year.

image

Permalink 1 note

08 3 / 2012

A Sigh of Datomic

Over a year ago I had the great pleasure of working with the Datomic team through my wonderful employer, Relevance, while the project was still secret.  Datomic, which was released on Monday, is a new kind of database with a unique and powerful set of properties.

I believe Datomic makes new kinds of applications possible and old kinds of applications easier, and I encourage you to try it out.

My experience working on and around Datomic was incredibly formative technically and professionally.  The only downside has been the agony of waiting to talk with people about it and to apply it to public projects and products.  I’m excited and relieved that Datomic is now in the open.

As a technical influence, Datomic solidified a perspective on computing that I was first exposed to through Clojure, also designed by Rich Hickey.  I have found this perspective - which might be loosely characterized as emphasizing simplicity, immutability, and the importance of data - a powerful tool by itself, irrespective of either Clojure or Datomic.  It is this perspective that Rich elaborates on in his Strange Loop 2011 keynote, Simple Made Easy.

Simplicity, immutability, and data are powerful ideas to think about software in terms of, whether you are creating something new or assessing something that already exists.

As a software consultant at Relevance, I divide my time between creating solutions and choosing existing solutions in order to solve problems.  Combined with deliberate thought, research, and discussion with colleagues and clients, these ideas have helped me do both things better, to the extent that it sometimes feels like cheating.

Professionally, my involvement with the Datomic team taught me many things, the most influential of which was perhaps the importance of questions to problem solving.

I work in a totally intangible world of software, trade-offs, conceptions, and domains that has technical, social, and financial dimensions.  This world disappears when I try to imagine it all at once, which is my first instinct when I try to solve a problem within it.

Specific questions and their answers are a tool for considering this intangible world one piece at a time in the context of a particular problem.  If you ask and answer enough of them for yourself, you can build a practical mental model of the intangible.  This model allows you to make sensible decisions and form grounded opinions.  Questions are a big piece of the problem solving approach Rich discusses in his “Hammock-driven development” keynote at Clojure Conj 2010.

It’s not always easy to ask questions, especially if you know it will be hard to find the answer, or if the answer might be unfavorable.  But, unless you value your ego over your ability to solve problems, you should never hesitate.

Rich Hickey, Stu Halloway, Justin Gehtland, and the rest of the Datomic team did not hesitate, and now the world has a new database of singular vision and capability.

Permalink 1 note

10 2 / 2012

Structural Editing Redux

I gave a quick lightning talk at the most recent TriClojure about structure editing.  Structural editing is an idea I can’t seem to shake, and my efforts to wrap my head around its implications continue.

After the meeting, I followed up with a few interested parties about my discoveries, and thought to post them here for the benefit of the wider Internets:

The blog post that originally got me thinking caused me to write my own blog post, and a little while later I published a gist of a simple structural editor for Clojure using zippers.

The code in the gist has a lot of bugs.  In particular, the zipper function I’m using doesn’t handle vectors or hash maps gracefully.  I’ve thought about tightening the REPL loop so that every key press instantly triggers zipper movement.

The whole structure editor thing has also turned me on to the idea of touch/tablet IDE for Lisps - form bubbles that can be nested, similar to the Scratch project (but data).  I think this might ultimately be a better way to represent structure and sequence than characters and parentheses.

Once I found out about Interlisp (pdf), I went nuts, but information and screenshots are hard to come by.  Rich Hickey told me once that there is a video floating around somewhere of the Interlisp-D UI in action, but I’ve never been able to find it.

I’ve investigated what it would take for a real-time structure editor, and I think it’s a very hard problem.  Synchronizing data structures with their pretty-printed representation on a character display is no small feat.  Bernard Greenberg (pictured below) documents some approaches in his history of the implementation of Emacs.

More recently, Michael Fogus pointed me at Nokolisp, an old Lisp for DOS that features an interesting-looking structure editor, among other features (like “uncompiling” functions!)

My current thinking on the implications of a structural editor goes beyond convenience of representation and into the idea of programs constructed by query.  I imagine a world where code is stored and shared structurally instead of with text.  Programming with available libraries then becomes querying instead of explicitly programming.

As the programmer types, their editor might search these libraries in real-time and do things like suggest improvements using probability heuristics, or suggest substitution of their code with available library code that is a structural match.  This is an extension into a networked world of some of the ideas built into Interlisp.

Code as truly data also abolishes the need for git or other text-based source revision tools, as source would be stored at the granularity of expression - not the character or line.

Bernard Greenberg teaching Lisp

03 7 / 2011

Discover Lisp in Your Web Browser with Javascript

This post is available as a PDF

Many ideas introduced originally in Lisp, such as conditional execution (the if-then-else construct), garbage collection, and first-class functions1, can be found in modern non-Lisp programming languages.

Other ideas pioneered by Lisp, like the idea that programs can be composed solely of expressions, and homoiconicity, or the idea that a program can be written in its own data structures, are rarer.

Learning a Lisp dialect, whether it’s Clojure, Scheme, or Common Lisp, is a great way to see for yourself how powerful all of these ideas can be when combined.

An even better way to understand the ideas is to implement your own Lisp23.

After we explore some fundamental concepts, we’ll look at how a language like Javascript works.

Then, we’ll build our own small Lisp to Javascript compiler on top of Javascript in about 32 lines of Javascript code.

Expression vs. Statement

Programs in languages like Javascript are composed of two things:

  • statements
  • expressions

Lisp programs are composed only of expressions.

Both statements and expressions are, in some sense, instructions for the computer to do some piece of work. The difference between them is that a statement does not return a value, but an expression does.

Consider Javascript’s if-then-else statement:

if (x > 10) {
  alert("x was bigger than 10!");
} else {
  alert("x was not bigger than 10!")
}

We call alert inside both the then and else bodies of the expression because if does not return a value. If it did, we could pass it directly to a single alert call, as this wishful pseudo-Javascript demonstrates:

alert(if (x > 10) {
  return "x was bigger than 10!"
} else {
  return "x was not bigger than 10!"
});

If we eliminate statements from our wishful pseudo-Javascript entirely, there’s no longer a need for the return operator. It’s assumed that values “return” themselves:

alert(if (x > 10) {
   "x was bigger than 10!"
} else {
   "x was not bigger than 10!"
});

Javascript actually provides an if-then-else construct that returns a value, the ternary operator4, but it is seldom used and often discouraged5.

With expressions, it’s possible to write code in the imperative style the first example demonstrated. The opposite, writing expressions in terms of statements, is not.

If we agree that “power” means “possibility”, then languages like Lisp, which are based on expressions instead of statements, might be considered powerful.

Homoiconicity

Homoiconicity is a property of a programming language’s syntax, and means that programs in a language are expressed using that language’s own data structures. The property of homoiconicity is key to the way Lisp empowers the programmer to fabricate and manipulate syntax.

Homoiconicity might be understood by exploring the properties of source code and interpretation of that source code in a non-homoiconic language first.

Javascript, while influenced by Lisp in other ways6, is not homoiconic, and its popularity, availability, and conventional syntax make it a candidate for exploration.

Implementing Javascript

How a Javascript Interpreter Works

Consider this fragment of Javascript code, which passes the sum of 1 and the product of 2 and 3 to a web browser’s alert function:

alert(1 + 2 * 3);

When a browser passes this code, or data, as a string to its Javascript interpreter, something like the following happens:

  • The interpreter lexically analyzes7 the string, turning it into a stream of tokens. Tokens are objects in source code upon which other constructs are defined, such as function names, operators, and literals like numbers or strings. The tokens in the above fragment might be:
    • alert
    • (
    • 1
    • +
    • 2
    • *
    • 3
    • )
    • ;
  • The interpreter parses the token stream, attempting, recursively, to match the pattern of tokens to known language constructs. For instance, when the interpreter sees the function name alert followed by (, it knows to expect zero or more tokens that must be succeeded by a closing ).
  • The interpreter evaluates the constructs it found from the inside out:
    • 2 * 3 happens first, because, * has higher precedence than + and because the interpreter knows it needs a value or identifier to pass to alert.
    • The product, 6, is returned.
    • 1 + 6 is evaluated, returning 7.
    • Finally, alert(7) is evaluated, and a message is displayed.

If you were to write your own Javascript interpreter or compiler, you would need to implement a lexical analyzer, a parser, and an evaluator in order to complete the above steps.

Even if you were to implement your interpreter in Javascript, you’d have a long way to go, because none of these functions are provided by Javascript interpreters to Javascript programmers.

Javascript provides the eval function, but it accepts only strings, and you need to create source code strings yourself. Creating source code strings to pass to eval is effectively compilation, and done correctly could be as difficult as writing a compiler.

The task is not as daunting if we take the Lisp approach and build our programs in a data format richer than strings. Let’s meet the problem half way, and invent a Javascript syntax based on Javascript data.

A Homoiconic Javascript Subset: JSONScript

S-expressions

Consider this alternative representation of the code fragment, in a language we just invented, JSONScript:

['alert', ['+', 1, ['*', 2, 3]]]

Unlike the earlier example, which was a string that required multiple phases of analysis to understand and run, the above code is written using data structures native to Javascript: string, number, and array.

JSON, which stands for “Javascript Object Notation”, is a notation for expressing data in terms of Javascript data structures. JSON is expressive enough for us to use it to represent code for a simple programming language.

We could easily write a function called compile_jsonjs that converted this representation into a string that could be passed to eval, because:

  • We don’t need to write a lexical analyzer or parser: our code is already rich enough to express how it should be evaluated.
  • compile_jsonjs doesn’t need to know about operator precedence because we’re using s-expressions.

S-expressions, short for “symbolic expressions”, are a convention for writing code that allows us to represent a function call with an array. This convention is also known as prefix notation. The first element of the array is the function, and subsequent elements are arguments to that function that are evaluated first.

S-expressions leave no ambiguity about the order in which functions must be applied. In the original example, the expression 1 + 2 * 3 evaluated to 7 because it’s in the Javascript specificaton that * must evaluate before +.

In JSONScript, we express our intent to multiply first by making ['*', 2, 3] an argument to +.

S-expressions don’t have to be arrays. 42 and "hamster dance" are also s-expressions, because they also evaluate, but to themselves.

Lisp uses lists instead of arrays as s-expressions, but the idea is the same.

Some Implementation Details

There are at least two implementation details we face in implementing compile_jsonjs:

  • In JSONScript, as in Lisp, there is no distinction between function and operator. Functions, whether they are alert or *, must only appear as a string and as the first element of an array.
    • compile_jsonjs needs to recognize functions that Javascript considers to be operators, and return the correct syntax for them.
  • In Javascript, functions are identified by symbols, not strings. For instance, this syntax is not correct: 'alert'(7).
    • compile_jsonjs must return function names as symbols.
    • Conflating symbol and string is necessary but has unfortunate implications. For instance, it will be impossible to pass a function name as an argument to a function in JSONScript.

    • Adding the ability to pass function names as arguments equires us to go beyond JSON as our source data format, because JSON permits symbol literals only as an object field names.

Building the Compiler

We’re now equipped to reason about how compile_jsonjs will work.

  • First, we check if the input is an array.
  • If it is an array, we:
    • Compile the arguments
    • Check if the first element is an operator like * or +
      • If it is an operator, interpose the compiled arguments with the operator, and concatenate everything into a single string. compile_jsonjs(['+', 1, 2]) should return "1+2".
      • If it’s not an operator, like alert, we return a function call. compile_jsonjs(['alert', 'hello']) should return "alert('hello')"
  • If it isn’t an array, we return it as a string. compile_jsonjs(42) should return "42".

The Implementation

Next, we can translate our plan into code. We know that compile_jsonjs will need helper functions for:

  • Testing if an object is an array: This is how we’ll determine at the beginning of compile_jsonjs whether we’re compiling a function call or a literal. Literals are data that evaluate to themselves, like numbers or strings.
  • Testing if an array contains a particular object: We’ll need to make a list of functions that are Javascript operators, because we must emit different Javascript syntax for them.

The first helper function we need, isArray(), isn’t available on some browsers, and is actually difficult to write in a widely compatible way.

So, we can borrow it from the underscore.js8 library:

var isArray = function (obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

Next, we need a function for testing if an object is in an array. Such a function is also not available in some browsers, but we can implement it like so:

var inArray = function(array, item) {
  for(var i = 0; i < array.length; i++)
    if (array[i] === item) return true;
  return false;
}

With these functions in place, we can finally write our compiler:

var compile_jsonjs = function(expression) {

  var operators = ['*', '+'];

  if (isArray(expression)) {

    var func_name = expression[0];
    var func_args = expression.slice(1);

    var compiled_args = [];
    for (var i = 0; i < func_args.length; i++)
      compiled_args.push(compile_jsonjs(func_args[i]));

    if(inArray(operators, func_name)) {
      return compiled_args.join(func_name);
    } else {
      return func_name + "(" + compiled_args.join(',') + ")";
    }

  } else {
    return expression.toString()
  }
}

The full source listing, which you can copy and paste into a web browser’s Javascript console, follows:

var isArray = function (obj) {
  return Object.prototype.toString.call(obj) === '[object Array]';
}

var inArray = function(array, item) {
  for(var i = 0; i < array.length; i++)
    if (array[i] === item) return true;
  return false;
}

var compile_jsonjs = function(expression) {

  var operators = ['*', '+'];

  if (isArray(expression)) {

    var func_name = expression[0];
    var func_args = expression.slice(1);

    var compiled_args = [];
    for (var i = 0; i < func_args.length; i++)
      compiled_args.push(compile_jsonjs(func_args[i]));

    if(inArray(operators, func_name)) {
      return compiled_args.join(func_name);
    } else {
      return func_name + "(" + compiled_args.join(',') + ")";
    }

  } else {
    return expression.toString()
  }
}

Trying it Out

We can test our compiler by seeing what code it generates with our JSONScript fragment:

compile_jsonjs(['alert', ['+', 1, ['*', 2, 3]]]);

And we can evaluate our compiled code by passing that result to eval:

eval(compile_jsonjs(['alert', ['+', 1, ['*', 2, 3]]]));

Going Further

JSONScript probably isn’t a language you would want to use for your next programming project, but hopefully you now have a better understanding of what Lisp is and why it is different.

Further extending JSONScript will help you understand Lisp even more.

You can begin by adding support for other Javascript operators.

Next, you might implement lambda and quote. These will allow you to define functions in JSONScript, and to pass arrays to functions without evaluating them.

Once you have lambda and quote, you can implement other special forms, using Paul Graham’s The Roots of Lisp as a guide9.

If you’re feeling particularly ambitious, you might consider adding support for one of Lisp’s most famous and unique features - macros, or functions that:

  • are run before evaluation
  • do not evaluate their arguments
  • return JSONScript code

  1. What Made Lisp Different by Paul Graham

  2. The Roots of Lisp by Paul Graham

  3. Lisp in Small Pieces

  4. Wikipedia: Ternary operation (Javascript)

  5. jQuery Core Style Guide: Blocks

  6. Popularity by Brendan Eich

  7. Wikipedia: Lexical analysis

  8. _.isArray in underscore.js

  9. The Roots of Lisp by Paul Graham

Permalink 8 notes

17 11 / 2010

An XML Rant

This rant is brought to you by my reaction to Daniel Lemire’s post, “You probably misunderstand XML”

In school I took a class called “Data Interchange” or something, that taught primarily XML and the ecosystem around it.  We learned about XSD, RELAX NG, XSLT, XPath, JAXB, SOAP, and lots of other things I thought to be loads of horrendous bullshit at the time.  I hated that class.

I made a special effort to go, though.  I was on a personal mission to point out every counterexample to, failing of, and argument against XML that I could.  ”It’s the illegitimate half-brother of the holiest representation of all time, the S-expression, and it’s slower than shit to boot!” I cried.

I’ve learned a lot since then.  The biggest thing I’ve learned is that it’s easy to dismiss any technology with cultural baggage on religious terms.  It’s also easy to conflate your hatred of some technology, like SOAP, with some other technology, like XML, that is only loosely or incidentally related.  Without assessing pragmatically to yourself whether SOAP sucks because it uses XML, or SOAP just plain sucks, you have not adequately justified your hatred.

The more you work without asking yourself these questions, the more likely you are to commit the cardinal sin of anyone in the computing profession who gives a shit about what they do - use the wrong tool for the job.

What’s much harder, and much more useful, is to take a pragmatic approach to determining a technology’s deficiencies and capabilities.  I still don’t do this enough.  This was one of the themes of Rich Hickey’s “Hammock Time” talk at the first Clojure Conj.

But it’s not what led me to later realize the legitimate use cases for XML.  I digress.

What I later realized about XML as I programmed more is that the intrinsic structure, semi-structure, or non-structure of the data you are working with is only part of the question, and only leads you to a conclusion - well, opinion, mostly - on how to best represent it.  The more complicated the domain, the more complicated your opinion, and the hairier the ultimate representation.

As you bang out your implementation, the less intuitive but really insidious part of the question lurks: “Will people in the future working with this thing I created be able to use it and modify it for their own needs?  Will they know my intent well enough to improve upon it, or determine if some variant of it is “valid” in the sense that it is true to my original opinion, on which other consumers of this thing may depend?”

For domains that are simple in the ontological sense, it seems really dumb to use XML, because that question doesn’t seem worth addressing.

That’s because you’re confident other people could sit down, read a few your examples, and be comfortable adapting and extending your stuff.  JSON and YAML are great for applications that fit this scenario, especially when you don’t have to worry about transport to or from places outside of your control.  Like on a web app, when you’re doing Ajax stuff with your own backend.

Sometimes though, you need to transfer data between applications - applications that are coded by different people, who might have different perspectives of the underlying domain that the data being transported is derived from.  And that’s when you need to look into XML, because of all the formats out there, it has the most tooling and documentation around writing schemas.  XML schemas let you express your understanding of the domain, and how you chose to interpret pieces of it, declaratively, in an almost human readable format.  More readable than BNF in my opinion, anyway.

It’s easy to know when you’re doing it wrong.  Is your code littered with assertions about the structure of data coming from some outside source?  Are there failure cases for your application that can be triggered by malformed data sneaking in?  Do you have tons of unit tests around this?

If you do, you might be comfortable.  You might feel good.  But what about the other guys?  If you have multiple developers working multiple code bases, all of which depend on some common interchange format, then the data on Bob’s box running application Q actually depends on the unit tests running on Sally’s box running application Z.  You can commit another cardinal sin and duplicate the tests, version and integration-test all of these apps together, or you can suck it up and investigate a transfer format that supports schemas.  Depending on your transport and other requirements, this might be XML, or it might be something like Thrift.

Schemas are not the answer to every question, and, like any tool, they can be the wrong one for the job.  But in my limited experience, there’s a place for XML and it is easy to overlook because of your own cultural bias.

16 11 / 2010

Sending Small Secrets with Perl

Suppose you’d like to send a short message, like an account number, to a friend, but have no secure way to transfer it and can’t hand the number off in person.

If there’s something that only you and your friend know, and this something in text is at least as long as the secret you’d like to send, you’re in luck.

Using your shared secret, Perl, Base64, and the XOR cipher, you can communicate small secrets securely.

An Example

Alice needs to send a 7 digit account number, like 9876543, to her friend Bob over e-mail.  Alice knows that Bob’s first phone number was 555-4241 .  To encode the account number using this shared secret, she can Base64 encode the result of XORing “5554241” and “9876543”.

On her computer, she runs this small Perl script:

perl -MMIME::Base64 -e 'print encode_base64("5554241"^"9876543")'

which returns the string “DA0CAgcAAg==”

Next, she composes an e-mail to Bob:

Hey Bob, here is that account number. Run the following command, substituting the asterisks for your first phone number, no area code, and without the dash: perl -MMIME::Base64 -e ‘print “*******”^decode_base64(“DA0CAgcAAg==”)’

When Bob gets the message, he runs the command on his machine:

perl -MMIME::Base64 -e 'print "5554241"^decode_base64("DA0CAgcAAg==")'

which prints 9876543.

13 3 / 2010

The S-expression Editor

The other week I was reading about Bard, a new Lisp dialect, and ran into this:

“Historically, and in most other Lisp dialects, source code is explicitly or implicitly not text; it is s-expressions. Text is just a print representation of the s-expressions.

Emphasis added.  This got me thinking.

for lisp, text editors are overkill

Good text editors like vim and Emacs are really good at everything having to do with text editing.  In fact, they’re so good at such a wide variety of things, that their features wildly exceed the sort of operations one really needs to do when working on Lisp programs.

For instance, even the idea of a “newline” (or any other character the average Reader considers whitespace) doesn’t really have any meaning in s-expression land outside of quoted strings.  Everything in the editor about them needn’t be accessible to the programmer.

So, what if instead of accepting text as our source editing medium, we operated directly on data structures?  That is, what if key strokes performed some operation directly on the program’s data, and the editor simply pretty printed a nicely formatted representation of the current program following edits?

This is my idea, and I’m not sure it hasn’t been done before.

some pros

  • Plugins: Plugin functions don’t have to worry at all about dealing with or parsing text.  They’re handed the data structure representing the current program (or arbitrary s-expression), along with a function representing the “point” or cursor location.  They transform it somehow, and return the new data structure.  The point might be stored as a zipper partial.
  • Visualization: By separating editing from representation, it becomes simpler to develop alternative visualizations.  I think there might be a lot of interesting work to be done here, with things like contours, bubbles, and snippets.  For some cool ideas along these lines, check out Michael Weber’s Emacs hackery page.
  • Universal formatting: Since the programmer is no longer dealing directly with shareable, revisionable text, the text visualizer would serve also as the exporter when it came to source control and storage.  In the case of Clojure, this would effectively make the *code-dispatch* dispatch table for clojure.contrib.pprint the gofmt of the language.
  • Evaluation: SLIME-like evaluation for Clojure would be trivial, assuming this editor was written in Clojure.

some cons

  • Comments: Comments, and anything else in source code normally stripped by the Reader, would be completely lost.  This means that any such data would have to be metadata, something which seems cumbersome at best.  Maybe not.
  • Another editor?: Both vim and Emacs, and particularly Emacs with Paredit, have served me exceptionally well when it comes to editing Clojure.  I’m not sure a new editor is warranted; but the idea of an editor written in Clojure that takes advantage of STM (for undo) and zippers (for commands and plugins) sounds pretty appealing.

status

I’ve started playing with SWT in an effort to build a prototype.  I’ll github it soon.  In the meantime, does anyone know if this has this been done before?  Are there unsurmountable pitfalls that make the idea pointless?  Thanks in advance!

*update*

I learned recently that the INTERLISP programming environment featured just such a structural editor.  Code was data, all the way down, and this was the late 1960s.  Screen display and output files were pretty-printed serializations.  Based on what I’ve read, this capability took INTERLISP the IDE to a level of capability that blows away anything we have today.

The wisdom of the ancients…

08 3 / 2010

NCSA Mosaic on Github

NCSA Mosaic 2.7 viewing GitHub.com

In 1994, when I was in fourth grade, my dad brought me along with him to see a friend of his in the CS department at the University of Buffalo.  My dad’s friend, Bill Rapaport, was running NCSA Mosaic on a Sun workstation.  I vividly remember the moment he brought up the Louvre’s website and a beautiful full color image of the Mona Lisa was magically beamed across the ocean from Paris, and onto the screen.

My dad had shown me gopher before, but nothing was ever in color.  In fact, everything I’d seen about computers up to that point seemed pretty boring.

The moment I saw the Mona Lisa in full color on a computer monitor was one of only a handful of moments that led me to where I am now, which is a state of continual curiosity and wonder about these things, these machines, these computers.

Thanks in great part to the work of others, I was able to pretty easily get Mosaic to compile and run on my machine, and to relive for a moment my childhood renaissance.

What is the Mosaic, the Mona Lisa, that we can show children today?

If you’re on GNU/Linux-Ubuntu (or something else, and you know your way around your package manager) you can compile and run NCSA Mosaic yourself: http://github.com/alandipert/ncsa-mosaic