<!DOCTYPE html>
<script>var __pbpa = true;</script><script>var translated_warning_string = 'Warning: Never enter your Tumblr password unless \u201chttps://www.tumblr.com/login\u201d\x0ais the address in your web browser.\x0a\x0aYou should also see a green \u201cTumblr, Inc.\u201d identification in the address bar.\x0a\x0aSpammers and other bad guys use fake forms to steal passwords.\x0a\x0aTumblr will never ask you to log in from a user\u2019s blog.\x0a\x0aAre you absolutely sure you want to continue?';</script><script type="text/javascript" language="javascript" src="http://assets.tumblr.com/assets/scripts/pre_tumblelog.js?d9f4c92b186c422f85b52215bfcb76af"></script>
<!DOCTYPE html>
<html>
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# blog: http://ogp.me/ns/blog#">
<meta charset="UTF-8">
<title>Structural Editing Redux - alan dipert</title>
<link rel="shortcut icon" href="http://24.media.tumblr.com/avatar_4ae064934cfd_16.png">
<link rel="alternate" type="application/rss+xml" href="http://alan.dipert.org/rss">
<meta name="description" content="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..." />
<meta name="if:Show notes" content="1">
<meta name="text:Disqus Shortname" content="" />
<meta name="color:Post Background" content="#F2F2F2" />
<link rel="stylesheet" href="http://static.tumblr.com/26l8vc7/ej3lr0jwd/style.css">
<style type="text/css">
.post{background: #F2F2F2;}
</style>
<script type="text/javascript" src="http://shjs.sourceforge.net/sh_main.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_css.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_html.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_java.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_sh.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_c.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_scala.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_cpp.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_php.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_ruby.min.js">
</script>
<script type="text/javascript"
src="http://shjs.sourceforge.net/lang/sh_javascript.min.js">
</script>
<link type="text/css" rel="stylesheet" href="http://shjs.sourceforge.net/sh_style.css">
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-965358-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
<!-- BEGIN TUMBLR FACEBOOK OPENGRAPH TAGS -->
<!-- If you'd like to specify your own Open Graph tags, define the og:url and og:title tags in your theme's HTML. -->
<!-- Read more: http://ogp.me/ -->
<meta property="fb:app_id" content="48119224995" />
<meta property="og:title" content="Structural Editing Redux" />
<meta property="og:url" content="http://alan.dipert.org/post/17375691572/structural-editing-redux" />
<meta property="og:description" content="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..." />
<meta property="og:type" content="tumblr-feed:entry" />
<!-- END TUMBLR FACEBOOK OPENGRAPH TAGS -->
<!-- TWITTER TAGS -->
<meta charset="utf-8">
<meta name="twitter:card" content="summary" />
<meta name="twitter:description" content="I gave a quick lightning talk at the most recent TriClojure about structure editing. Structural editing is an idea I can&#8217;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&#8217;m using doesn&#8217;t handle vectors or hash maps gracefully. I&#8217;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&#8217;ve never been able to find it. I&#8217;ve investigated what it would take for a real-time structure editor, and I think it&#8217;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 &#8220;uncompiling&#8221; 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.
" />
<meta name="twitter:title" content="Structural Editing Redux" />
<meta name="twitter:url" content="http://alan.dipert.org/post/17375691572/structural-editing-redux" />
<meta name="twitter:site" content="tumblr" />
<meta name="twitter:app:name:iphone" content="Tumblr" />
<meta name="twitter:app:name:ipad" content="Tumblr" />
<meta name="twitter:app:name:googleplay" content="Tumblr" />
<meta name="twitter:app:id:iphone" content="305343404" />
<meta name="twitter:app:id:ipad" content="305343404" />
<meta name="twitter:app:id:googleplay" content="com.tumblr" />
<meta name="twitter:app:url:iphone" content="tumblr://x-callback-url/blog?blogName=alandipert&postID=17375691572&referrer=twitter-cards" />
<meta name="twitter:app:url:ipad" content="tumblr://x-callback-url/blog?blogName=alandipert&postID=17375691572&referrer=twitter-cards" />
<meta name="twitter:app:url:googleplay" content="tumblr://x-callback-url/blog?blogName=alandipert&postID=17375691572&referrer=twitter-cards" />
<script type="text/javascript" language="javascript" src="http://assets.tumblr.com/assets/scripts/tumblelog.js?b32c40067ef5fa460dd9a1eda92ee368"></script><meta http-equiv="x-dns-prefetch-control" content="off"/></head>
<body>
<div id="wrapper">
<div id="header" role="banner">
<h1><a href="/">alan dipert</a></h1>
<div id="description">
<p><p><a href = "http://twitter.com/alandipert/">twitter</a> <a href = "http://github.com/alandipert/">github</a> <a href = "mailto:adipert@acm.org">email</a></p></p>
</div>
</div>
<div id="content" role="main">
<div class="post text">
<div class="date">
<p><span class="day">10</span> 2 / 2012</p>
</div>
<div class="content">
<h2>Structural Editing Redux</h2>
<p>I gave a quick lightning talk at the most recent <a href="http://www.meetup.com/TriClojure/">TriClojure</a> 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.</p>
<p>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:</p>
<p><span>The <a href="http://web.archive.org/web/20100919114103/http://bywicket.com/users/mikel/weblog/126a4/Bard.html">blog post that originally got me thinking</a> caused me to write </span><span><a href="http://alan.dipert.org/post/445462664/the-s-expression-editor">my own blog post</a>, and a little while later I <a href="https://gist.github.com/1167234">published a gist</a> of a simple structural editor for Clojure using zippers.</span><br/><br/><span>The code in the gist has a lot of bugs. In particular, the zipper function I’m </span><span>using doesn’t handle vectors or hash maps gracefully. I’ve thought </span><span>about tightening the REPL loop so that every key press instantly </span><span>triggers zipper movement.</span></p>
<p><span>The whole structure editor thing has also </span><span>turned me on to the idea of touch/tablet IDE for Lisps - form bubbles </span><span>that can be nested, similar to the <a href="http://fidelvanegas.net/wordpress/wp-content/uploads/2010/05/Screenshot-ScratchPongGame1.png">Scratch project</a> (but data). I </span><span>think this might ultimately be a better way to represent structure and sequence </span><span>than characters and parentheses.</span></p>
<p><span>Once I found out about <a href="http://larry.masinter.net/interlisp-ieee.pdf">Interlisp</a> (pdf), I went nuts, but information and </span><span>screenshots are hard to come by. Rich Hickey told me once that there is a video </span><span>floating around somewhere of the Interlisp-D UI in action, but I’ve </span><span>never been able to find it.</span><br/><br/><span>I’ve investigated what it would take for a real-time structure editor, </span><span>and I think it’s a very hard problem. Synchronizing data structures </span><span>with their pretty-printed representation on a character display is no </span><span>small feat. Bernard Greenberg (pictured below) documents some approaches in his </span><span><a href="http://www.multicians.org/mepap.html">history of the implementation of Emacs</a>.</span><br/><br/><span>More recently, <a href="http://blog.fogus.me/">Michael Fogus</a> pointed me at <a href="http://www.youtube.com/watch?v=HB6HvhOw_MY">Nokolisp</a>, an old Lisp </span><span>for DOS that features an interesting-looking structure editor, among </span><span>other features (like “uncompiling” functions!)</span></p>
<p><span>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.</span></p>
<p>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.</p>
<p><span>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.</span></p>
<p><span><img alt="Bernard Greenberg teaching Lisp" height="653" src="http://tailrecursion.com/~alan/pix/bsg-lisp-big.jpg" width="504"/><br/></span></p>
</div>
<div class="info">
<p><a href="http://alan.dipert.org/post/17375691572/structural-editing-redux">Permalink</a> <span style="float: right;"><a class="dsq-comment-count" href="http://alan.dipert.org/post/17375691572/structural-editing-redux#disqus_thread"></a></span></p>
</div>
</div>
<div class="notecontainer">
<div id="disqus_thread"></div>
<script type="text/javascript" src="http://disqus.com/forums/alandipert/embed.js"></script>
<noscript><a href="http://alandipert.disqus.com/?url=ref">View the discussion thread</a></noscript>
</div>
<div id="pagination" role="navigation">
<p>
<a href="http://alan.dipert.org/post/18947900609" class="newer">Next post »</a>
<a href="http://alan.dipert.org/post/7193534410" class="older">« Previous post</a>
</p>
</div>
</div>
</div>
<div id="footer">
<div class="wrapper">
<ul class="links" role="navigation">
<li><a href="/archive">Archive</a></li>
<li><a href="http://alan.dipert.org/rss">RSS</a></li>
</ul>
<p class="info-theme" role="contentinfo">Powered by <a href="http://www.tumblr.com">Tumblr</a> and designed by <a href="http://kcmr.tumblr.com">Kcmr</a>.</p>
</div>
</div>
<script type="text/javascript">
//<![CDATA[
(function() {
var links = document.getElementsByTagName('a');
var query = '?';
for(var i = 0; i < links.length; i++) {
if(links[i].href.indexOf('#disqus_thread') >= 0) {
query += 'url' + i + '=' + encodeURIComponent(links[i].href) + '&';
}
}
document.write('<script charset="utf-8" type="text/javascript" src="http://disqus.com/forums/alandipert/get_num_replies.js' + query + '"></' + 'script>');
})();
//]]>
</script>
<!-- BEGIN TUMBLR CODE -->
<iframe src="http://assets.tumblr.com/iframe.html?9f9b05bc6d86a119a5f73c15523c270b&src=http%3A%2F%2Falan.dipert.org%2Fpost%2F17375691572%2Fstructural-editing-redux&pid=17375691572&rk=0nCFU7Et&lang=en_US&name=alandipert&brag=false&avatar=http%3A%2F%2F24.media.tumblr.com%2Favatar_4ae064934cfd_40.png&title=alan+dipert&url=http%3A%2F%2Falan.dipert.org%2F" width="330" height="25" scrolling="no" frameborder="0" style="position:absolute; z-index:2147483647; top:0px; right:0px; border:0px; background-color:transparent; overflow:hidden;" id="tumblr_controls"></iframe>
<!--[if IE]><script type="text/javascript">document.getElementById('tumblr_controls').allowTransparency=true;</script><![endif]-->
<script type="text/javascript">var s=new Image(1,1);s.src=((r='http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoiYmxvZyIsImJsb2dpZCI6IjQzOTQ2OCIsInVybCI6Imh0dHA6XC9cL2FsYW4uZGlwZXJ0Lm9yZ1wvcG9zdFwvMTczNzU2OTE1NzJcL3N0cnVjdHVyYWwtZWRpdGluZy1yZWR1eCIsInJlcXR5cGUiOjB9&U=GOHODKFMEM&K=8a9831192a675b5f60d47867c384fd22099e2199aad54ac191b479234668d524&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10'.replace(/&R=[^&$]*/,'')) + ('&R='+escape(document.referrer)).substr(0, 2000-r.length).replace(/%.?.?$/,''));</script><noscript><img style="position:absolute;z-index:-3334;top:0px;left:0px;visibility:hidden;" src="http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoiYmxvZyIsImJsb2dpZCI6IjQzOTQ2OCIsInVybCI6Imh0dHA6XC9cL2FsYW4uZGlwZXJ0Lm9yZ1wvcG9zdFwvMTczNzU2OTE1NzJcL3N0cnVjdHVyYWwtZWRpdGluZy1yZWR1eCIsInJlcXR5cGUiOjAsIm5vc2NyaXB0IjoxfQ==&U=GOHODKFMEM&K=7084266fc7e25dcb9d2255d6d2fae4c5fa481af889ea995793e677d8a1f0d8fb&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10"></noscript> <!-- END TUMBLR CODE -->
<iframe src="http://assets.tumblr.com/analytics.html?dcba2423e6f5653ee72915980432c1c3" scrolling="no" width="1" height="1" frameborder="0" style="background-color:transparent; overflow:hidden; position:absolute; top:0; left:0 z-index:9999;" id="ga_target"></iframe>
<script>
var COMSCORE = true;
window.setTimeout(function() {
var analytics_frame = document.getElementById('ga_target');
analytics_frame.contentWindow.postMessage('enable_comscore', analytics_frame.src.split('/analytics.html')[0]);
}, 1000);
</script>
<script type="text/javascript">
var _qevents = _qevents || [];
(function() {
var elem = document.createElement('script');
elem.src = (document.location.protocol == "https:" ? "https://secure" : "http://edge") + ".quantserve.com/quant.js";
elem.async = true;
elem.type = "text/javascript";
var scpt = document.getElementsByTagName('script')[0];
scpt.parentNode.insertBefore(elem, scpt);
})();
</script>
<script type="text/javascript">
_qevents.push( { qacct: 'p-19UtqE8ngoZbM' } );
</script>
<noscript>
<div style="display: none;"><img src="//pixel.quantserve.com/pixel/'p-19UtqE8ngoZbM'.gif" height="1" width="1" alt="Quantcast"/></div>
</noscript>
<script type="text/javascript">var s=new Image(1,1);s.src=((r='http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoidXJsIiwidXJsIjoiaHR0cDpcL1wvYWxhbi5kaXBlcnQub3JnXC9wb3N0XC8xNzM3NTY5MTU3Mlwvc3RydWN0dXJhbC1lZGl0aW5nLXJlZHV4IiwicmVxdHlwZSI6MH0=&U=GADFDHANOE&K=a962037a80503baa1e731b041f1bdbfe9c7ddfc69df37f07819dfd7262d5fe4d&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10'.replace(/&R=[^&$]*/,'')) + ('&R='+escape(document.referrer)).substr(0, 2000-r.length).replace(/%.?.?$/,''));</script><noscript><img style="position:absolute;z-index:-3334;top:0px;left:0px;visibility:hidden;" src="http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoidXJsIiwidXJsIjoiaHR0cDpcL1wvYWxhbi5kaXBlcnQub3JnXC9wb3N0XC8xNzM3NTY5MTU3Mlwvc3RydWN0dXJhbC1lZGl0aW5nLXJlZHV4IiwicmVxdHlwZSI6MCwibm9zY3JpcHQiOjF9&U=GADFDHANOE&K=ced0783de95bb6934d0911b1ff8ebf3142cb99e1d13f9356fc5fb338c4d7d54e&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10"></noscript><script type="text/javascript">var s=new Image(1,1);s.src=((r='http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoicG9zdCIsInVybCI6Imh0dHA6XC9cL2FsYW4uZGlwZXJ0Lm9yZ1wvcG9zdFwvMTczNzU2OTE1NzJcL3N0cnVjdHVyYWwtZWRpdGluZy1yZWR1eCIsInJlcXR5cGUiOjAsInBvc3RzIjpbeyJwb3N0aWQiOiIxNzM3NTY5MTU3MiIsImJsb2dpZCI6IjQzOTQ2OCIsInNvdXJjZSI6MzN9XX0=&U=KOGCOOFMPG&K=57b40f8974a968b67fdd36fb0d4fbcadd16ac8c328d708f19139c26510885e96&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10'.replace(/&R=[^&$]*/,'')) + ('&R='+escape(document.referrer)).substr(0, 2000-r.length).replace(/%.?.?$/,''));</script><noscript><img style="position:absolute;z-index:-3334;top:0px;left:0px;visibility:hidden;" src="http://www.tumblr.com/impixu?T=1367908653&J=eyJ0eXBlIjoicG9zdCIsInVybCI6Imh0dHA6XC9cL2FsYW4uZGlwZXJ0Lm9yZ1wvcG9zdFwvMTczNzU2OTE1NzJcL3N0cnVjdHVyYWwtZWRpdGluZy1yZWR1eCIsInJlcXR5cGUiOjAsInBvc3RzIjpbeyJwb3N0aWQiOiIxNzM3NTY5MTU3MiIsImJsb2dpZCI6IjQzOTQ2OCIsInNvdXJjZSI6MzN9XSwibm9zY3JpcHQiOjF9&U=KOGCOOFMPG&K=5827f7739f2dbccbd230c105c0b4cc0a32eac3ce1012edfdd4c77d323b23fd24&R=http%3A%2F%2Falan.dipert.org%2Fpost%2F47444634908%2Fstructural-editing-revisited%3Fa50cdc10"></noscript></body>
</html>