<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7068528325708136131</id><updated>2012-02-16T19:46:04.734-08:00</updated><category term='static scope'/><category term='linguistics'/><category term='conlanging'/><category term='lambda calculus'/><category term='politics'/><category term='religion'/><category term='memetics'/><category term='continuations'/><category term='Kernel'/><category term='monads'/><category term='programming languages'/><category term='Lisp'/><category term='fexprs'/><category term='types'/><category term='science'/><title type='text'>Structural insight</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>11</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-8925632943598308471</id><published>2012-01-27T13:49:00.000-08:00</published><updated>2012-01-28T05:44:58.297-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='continuations'/><title type='text'>Guarded continuations</title><content type='html'>&lt;blockquote&gt;Go to, let us go down, and there confound their language, that they may not understand one another's speech.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; Genesis 11:7 (King James Version)&lt;br /&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;I've been asked about &lt;a href="http://web.cs.wpi.edu/%7Ejshutt/kernel.html"&gt;Kernel&lt;/a&gt;'s &lt;i&gt;guarded continuations&lt;/i&gt;.&amp;nbsp; In writing that section of the Kernel Report, I knew it wasn't as lucid as one might like, but getting it all down while I had it clearly in mind was something of an achievement in itself.&amp;nbsp; I'm not sure I've ever seen a really lucid explanation of continuations; explaining them should probably be considered a major challenge in its own right, above and beyond figuring out how the mechanism should work.&amp;nbsp; It's high time I tried to do better, though; however many tries it takes to get the explanation to come clear, I won't get there if my number of tries never increases.&lt;br /&gt;&lt;br /&gt;On my Kernel web page I describe guarded continuations as 'Exception handling "done right"'.&amp;nbsp; For an ultra-short tag line, that may be about as good as any; but guarded continuations are more a simultaneous blend-and-improvement on Scheme continuations and Java exception handling, rather than a supposedly-optimal exception facility.&amp;nbsp; We may still be several generations of exception facilities away from getting exceptions right; but as may be, I think guarded continuations have something to add to the discussion.&lt;br /&gt;&lt;br /&gt;It's also worth saying up front that guarded continuations are lower-level than a good exception facility would be.&amp;nbsp; Kernel tries for very simple low-level facilities plus the ability to build higher-level abstractions from them.&amp;nbsp; It's an open, and fascinating, question how well Kernel's abstraction facilities will actually apply to exception handling &amp;mdash; and I hope to learn a lot from that question.&amp;nbsp; (I expect shortcomings of Kernel's abstractive facilities to be not about the facilities' power (which I maintain is extraordinary) but about the directions in which that power can be applied.&amp;nbsp; When I figure out what the missing directions are, I mean to &lt;i&gt;go &lt;b&gt;that&lt;/b&gt; way&lt;/i&gt;.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Stacks and trees&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Classically, programming languages deal with function calls using a stack.&amp;nbsp There are two kinds of stuff on the stack:&amp;nbsp; local variables (data), and return addresses (control).&amp;nbsp; The local data for a function call produces a single set of local variables; but the algorithm for that same call may produce many different return addresses, one for each point in the algorithm where it, in turn, calls a function.&amp;nbsp; In principle, one might have two stacks, one for data and one for control; but classically, all local variables and all return addresses are use-once, to be discarded in the same order they were introduced, so it may seem natural to store both on a single stack (with resultant security problems, malware accessing data as control and vice versa).&lt;br /&gt;&lt;br /&gt;First-class (lexically scoped) functions require local data to be stored, in general, as a tree rather than a stack.&amp;nbsp; When a first-class function is returned as the result of a function call (in vintage parlance, as an &lt;i&gt;upward funarg&lt;/i&gt;), lexical scoping expects that function to have access to &amp;mdash;in general&amp;mdash; the entire column of variables that were on the stack when the function was created, even though some of the function calls that created those variables have since ended.&amp;nbsp; So data that used to be popped off the stack must now, potentially, persist.&amp;nbsp; A set of local variables, which used to be the data part of a stack frame, is now an &lt;i&gt;environment&lt;/i&gt;, with a fixed set of ancestors (variables further up the column) and potentially any number of children (one for each call to any function defined in that environment).&amp;nbsp; (In Kernel, btw, environments are first-class objects; there was a lively LtU discussion on first-class environments, &lt;a href="http://lambda-the-ultimate.org/node/3861"&gt;here&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;First-class continuations do to the control stack what first-class functions did to the data stack:&amp;nbsp; they turn it into a tree.&amp;nbsp; (First-class continuations do this to the data stack too, but I'm not aware of any language that has first-class continuations without first-class functions.)&amp;nbsp; Just as first-class functions required entire columns of local variables to persist after the ends of function calls that created them, first-class continuations require entire columns of "return addresses" to persist after the ends of function calls that created them.&lt;br /&gt;&lt;br /&gt;In visualizing the tree of continuations, the actual &lt;i&gt;algorithms&lt;/i&gt; of the program hover in the areas beneath the nodes of the tree (possibly, multiple algorithms under a single node).&amp;nbsp; Each child continuation is a socket waiting for a value to be plugged into it, to be chewed on by the algorithm above that child &amp;mdash; which may, eventually, terminate and plug a value into its parent continuation.&amp;nbsp; Primitive operations hover beneath the leaves of the tree.&amp;nbsp; Kernel pretty much only needs one non-primitive operation: &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;combination evaluation&lt;/a&gt;, which spins off a subtree to evaluate the operator, spins off subtrees as appropriate to evaluate operands, and finally hands the situation over to another algorithm to make the operative call (using for the operative call its parent continuation, in properly tail-recursive fashion).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Guards&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When a function &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; calls another function &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt;, &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; gives up some of its ability to regulate the future evolution of the computation.&amp;nbsp; The programmer tends to assume that not all such power has been lost &amp;mdash; that&amp;nbsp; (1)&amp;nbsp;the call to &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt; won't terminate without control passing back through the point at which &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; called it, and&amp;nbsp; (2)&amp;nbsp;that particular call to &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt; won't return through that point &lt;i&gt;more than once&lt;/i&gt;.&amp;nbsp; In the presence of first-class continuations, though, even these weak assumptions needn't hold.&amp;nbsp; Once &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; calls &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt;, the dynamic extent of that call might be exited, and/or later reentered any number of times, in ways that bypass &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; entirely.&amp;nbsp; Perhaps &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt; opens a file, calls &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt;, and then closes the file before relinquishing control to whoever called &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt;; if &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt; terminates bypassing &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt;, the file might not be closed outside the call to &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt;, and if &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt; is reentered bypassing &lt;i&gt;&lt;b&gt;f&lt;/b&gt;&lt;/i&gt;, the file might not be open inside the call to &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Scheme addresses this sort of problem by means of &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt;, a device that causes specified actions to be performed whenever a continuation-call tries to enter or leave the dynamic extent of the call to &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt;.&amp;nbsp; In R5RS Scheme (the version Kernel primarily diverged from), there were a couple of problems with &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Although &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt; allowed something to be done every time the dynamic extent of the call to &lt;i&gt;&lt;b&gt;g&lt;/b&gt;&lt;/i&gt; was entered, and every time it was exited, these &lt;i&gt;before&lt;/i&gt; and &lt;i&gt;after&lt;/i&gt; actions were unable to observe (let alone affect) what value was being passed into or out of the dynamic extent, so failing to support context-sensitive regulation of access to/from the dynamic extent.&amp;nbsp; (In Javascript terms &amp;lt;shudder&amp;gt;, &lt;i&gt;before&lt;/i&gt; and &lt;i&gt;after&lt;/i&gt; are akin to &lt;i&gt;&lt;b&gt;finally&lt;/b&gt;&lt;/i&gt; rather than &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt;.)&lt;/li&gt;&lt;li&gt; The R5RS was explicitly baffled by what would happen if continuations were used to pass into or out of the dynamic extents of the calls to &lt;i&gt;before&lt;/i&gt; and &lt;i&gt;after&lt;/i&gt; &amp;mdash; which suggested to me that the whole thing was something of a kludge.&amp;nbsp; The correct behavior in such cases ought to follow naturally from the conceptual framework, and if it didn't follow naturally one had to wonder if the conceptual framework was altogether coherent.&lt;/li&gt;&lt;/ul&gt;Java exception handling differs from this arrangement in several ways.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Mostly obviously and trivially, it only allows exiting a dynamic extent, not reentering one.&lt;/li&gt;&lt;li&gt;An intercepting &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt; has access to the value being thrown (unlike the &lt;i&gt;after&lt;/i&gt; of &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt;).&lt;/li&gt;&lt;li&gt;A &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt; selectively intercepts throws, based on the "target" (one might even say, "destination") of the throw.&amp;nbsp; Whereas Lisp cleanly separates the target of an abnormal transfer of control from the value being transferred &amp;mdash;the continuation called, versus the value passed to it&amp;mdash; Java entangles them in a single thrown object whose type is the "target".&lt;/li&gt;&lt;li&gt;Once a Java exception is caught, that's the end of the exception unless it is explicitly rethrown &amp;mdash; in contrast to the &lt;i&gt;after&lt;/i&gt; of &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt;, which ordinarily does not disrupt the abnormal transfer of control during which it is called.&lt;/li&gt;&lt;/ul&gt;Interestingly, one fairly intricate characteristic &lt;i&gt;shared&lt;/i&gt; by both Scheme's &lt;i&gt;&lt;b&gt;dynamic-wind&lt;/b&gt;&lt;/i&gt; and Java's &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt; is that the target is a node of a tree.&amp;nbsp; This is, perhaps, all the more interesting since the trees are seemingly very different in nature.&amp;nbsp; The Java target is a type in a tree of exception types; the Scheme target is a continuation in a tree of continuations.&lt;br /&gt;&lt;br /&gt;Kernel's guarded continuations drew on both these models for inspiration.&amp;nbsp; An applicative &lt;i&gt;&lt;b&gt;guard-continuation&lt;/b&gt;&lt;/i&gt; allows the construction of a continuation with entry- and exit-guard clauses.&amp;nbsp; Exit-guard clauses selectively intercept continuation-calls from inside to outside the guarded dynamic extent (the branch of the continuation tree descending from the guarded continuation), and are therefore analogous to Java &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt; clauses, with some adjustments.&amp;nbsp; Entry-guard clauses are symmetrically designed to selectively intercept continuation-calls from outside to inside the guarded extent.&lt;br /&gt;&lt;br /&gt;Each guard clause has a &lt;i&gt;selector&lt;/i&gt; continuation.&amp;nbsp; Keep in mind that a continuation-call has two ends:&amp;nbsp; it goes from one point in the continuation-tree to another, and in this case we know that one end of the call is inside the guarded extent, while the other end is outside.&amp;nbsp; A continuation-call matches the selector of a clause just if the &lt;i&gt;outside end&lt;/i&gt; of the call lies within the tree branch descending from the selector.&amp;nbsp; For an exit-guard clause this means that the called continuation must be in the selector's branch of the tree.&amp;nbsp; For an entry-guard, the &lt;i&gt;starting point&lt;/i&gt; of the continuation-call must be within the selector's branch of the tree.&lt;br /&gt;&lt;br /&gt;Because entry guards are selected based on the &lt;i&gt;source&lt;/i&gt; of the continuation-call, a list of interceptors selected &lt;i&gt;when the continuation-call is initiated&lt;/i&gt; will be different, in general, from what one would get by stopping at some intermediate interceptor and then "rethrowing" the call (in Java &lt;i&gt;&lt;b&gt;catch&lt;/b&gt;&lt;/i&gt; style).&amp;nbsp; This suggests that normal termination of an intercepting guard should continue along the path of the original continuation-call, reserving explicit diversion for when the interceptor &lt;i&gt;doesn't&lt;/i&gt; want to follow the original path.&amp;nbsp; Secondarily, although we do want it to be convenient (as well as possible) for an interceptor to continue along the path of the original continuation-call, we &lt;i&gt;don't&lt;/i&gt; really want to give the interceptor first-class continuations for either end of the call (source or destination).&amp;nbsp; We may have built some abstract device on top of the continuation primitives, and as a result, the source/destination continuations may be internal details that really oughtn't be casually spread about.&lt;br /&gt;&lt;br /&gt;Therefore, &lt;i&gt;normal termination&lt;/i&gt; of an intercepting guard continues along the path of the continuation-call, and the interceptor when called is provided with an explicit continuation for diverting control to just outside the guarded extent (Java-style).&lt;br /&gt;&lt;br /&gt;For versatile guard selection, each guarded gateway (entry or exit for a dynamic extent) has a list of guard clauses.&amp;nbsp; When a continuation-call goes through the gate (entering or exiting), the selectors of these clauses are checked, one at a time, until one is found that matches the call, or until there are no more clauses so that no interception occurs.&amp;nbsp; No more than one clause is selected.&amp;nbsp; A root continuation is provided, which can be used as a selector that matches all possible calls.&amp;nbsp; Using the root continuation, plus the ability for an interceptor to continue along the continuation-call path, one can (for example) arrange that a clause will be selected &lt;i&gt;except&lt;/i&gt; when the call matches some narrower selector (for example, the error continuation, which is the ancestor of all evaluation-aborting error handlers).&amp;nbsp; One provides a clause that catches errors and causes them to continue along their path, followed by a clause that catches everything and does whatever it is one wants done only in non-error situations.&lt;br /&gt;&lt;br /&gt;When a continuation-call is made, a list of intercepting guard clauses can be immediately constructed, since continuation guards are fixed at the time the guarded continuation is constructed.&amp;nbsp; The list doesn't &lt;i&gt;have&lt;/i&gt; to be constructed then, of course, exactly because all the relevant parts of the continuation tree are immutable; but if it isn't constructed immediately, one will have to store the information needed to select the clauses later &amp;mdash; which includes the source of the call as well as its destination (destination to select exit guards, source to select entry guards).&lt;br /&gt;&lt;br /&gt;The Kernel Report carefully works out subtleties of the device, such that when a guard intercepts an entry/exit to dynamic extent &lt;i&gt;d&lt;/i&gt;, and then itself makes a continuation-call, that call does not select any guard on &lt;i&gt;d&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;The traditional Scheme device for acquiring a first-class continuation object is &lt;i&gt;&lt;b&gt;call/cc&lt;/b&gt;&lt;/i&gt;, which calls a procedure and passes to that procedure the continuation to which that call would normally return.&amp;nbsp; Frankly, this was always a very clumsy way to work with continuations; one might almost suspect it was devised as an "esoteric programming language" feature, akin to INTERCAL's COME FROM statement.&amp;nbsp; With guarded continuations, though, dependence on &lt;i&gt;&lt;b&gt;call/cc&lt;/b&gt;&lt;/i&gt; finally becomes untenable.&amp;nbsp; If I'm working in Java, and I want to create a new class of exception, I do that by adding a subtype to the tree of exception types; to do the same thing in Kernel, it seems I want to add a new continuation to the tree branch of continuations descending from the error continuation.&amp;nbsp; If I had to use &lt;i&gt;&lt;b&gt;call/cc&lt;/b&gt;&lt;/i&gt; to acquire continuations, I could only add a new descendant of the error continuation if I were actually &lt;i&gt;in&lt;/i&gt; in the dynamic extent of the error continuation &amp;mdash; so, to define a new "type" of error during normal computation, I'd have to first "throw" an error exception, passing through all the exit- and entry-guards to get to the point in the tree where I want to add the new continuation.&amp;nbsp; What's wanted is ability to add a child continuation to an existing continuation &lt;i&gt;without&lt;/i&gt; having to be inside the dynamic extent of the parent.&amp;nbsp; Kernel provides just that ability, with &lt;i&gt;&lt;b&gt;extend-continuation&lt;/b&gt;&lt;/i&gt; (to add some &lt;i&gt;algorithm&lt;/i&gt; between child and parent) and &lt;i&gt;&lt;b&gt;guard-continuation&lt;/b&gt;&lt;/i&gt; (to add &lt;i&gt;guards&lt;/i&gt; between child and parent).&amp;nbsp; (Interestingly, &lt;i&gt;&lt;b&gt;call/cc&lt;/b&gt;&lt;/i&gt; still has to be provided as a primitive, since it can't be derived from the other primitives.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;An illustrative example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Alas, no.&amp;nbsp; Source code for continuation guarding is generally bulky and hard to read, and attempting to illuminate the basic concepts of continuation guarding that way would more likely just create an unhelpful mess.&amp;nbsp; For me, at least, it's all best understood by visualizing the tree of nested dynamic scopes, whereas the source code only directly reveals a tree of nested static syntax; the dynamic tree then has to be deduced, and the two trees don't correspond as closely as one might think.&lt;br /&gt;&lt;br /&gt;How best to arrange for a clear illustration, I'll have to give some more thought.&amp;nbsp; Meanwhile, imagine there was an illustration here that made it all crystal clear to you.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Delimited continuations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've also been asked to discuss guarded continuations versus delimited continuations.&amp;nbsp; &amp;lt;cough&amp;gt;&amp;nbsp; That's a rather large topic.&amp;nbsp; I'd probably have to start by explaining why I think "delimited continuations" is a misnomer &amp;mdash; by my reckoning, delimited continuations aren't continuations at all.&amp;nbsp; They're functions, and functions are a completely different sort of creature than continuations.&amp;nbsp; Continuations only have one side (input), which is why it's simply meaningless to talk about composing them.&amp;nbsp; (Can you see I'm working up to a major rant, here?)&lt;br /&gt;&lt;br /&gt;So I'm going to end &lt;b&gt;this&lt;/b&gt; post here &amp;mdash;it's already the longest post I've yet written on this blog&amp;mdash; and hope to put together something on delimited continuations later.&amp;nbsp; Perhaps that post will also help to further clarify guarded continuations, but we'll see.&amp;nbsp; It's yet another item for my collection of in-development blog posts (along with &lt;i&gt;guarded environments&lt;/i&gt;, another interesting topic this has reminded me of).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-8925632943598308471?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/8925632943598308471/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2012/01/guarded-continuations.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8925632943598308471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8925632943598308471'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2012/01/guarded-continuations.html' title='Guarded continuations'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-4136939160057458680</id><published>2011-12-26T08:17:00.000-08:00</published><updated>2011-12-27T09:11:20.881-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='memetics'/><category scheme='http://www.blogger.com/atom/ns#' term='linguistics'/><category scheme='http://www.blogger.com/atom/ns#' term='conlanging'/><category scheme='http://www.blogger.com/atom/ns#' term='religion'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Preface to Homer</title><content type='html'>&lt;blockquote&gt;But of the tree of the knowledge of good and euill, thou ſhalt not eate of it: for in the day that thou eateſt thereof, thou ſhalt ſurely die.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; &lt;a href="https://en.wikisource.org/wiki/Bible_%28Authorized_Version%29/Genesis#2"&gt;Genesis 2:17 (King James Version)&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;I'm going to suggest a hypothesis on the evolution of societies, natural languages, and &lt;a href="http://fexpr.blogspot.com/2011/03/memetic-organisms.html"&gt;memetic organisms&lt;/a&gt;.&amp;nbsp; Relating human language and human thought to programming is a straightforward exercise left to the student.&lt;br /&gt;&lt;br /&gt;Eric Havelock in his magnum opus &lt;i&gt;&lt;a href="https://en.wikipedia.org/wiki/Eric_A._Havelock#Preface_to_Plato"&gt;Preface to Plato&lt;/a&gt;&lt;/i&gt; (fascinating stuff) describes two profoundly different stages in the evolution of human societies, which he calls &lt;i&gt;oral society&lt;/i&gt; and &lt;i&gt;literate society&lt;/i&gt;.&amp;nbsp; Greek society, reckons Havelock, was transforming from oral to literate around the time of Plato; the epics of Homer are characteristic of oral culture.&amp;nbsp; I suggest that there is a stage of societal evolution &lt;i&gt;before&lt;/i&gt; that of oral poetry such as Homer's &amp;mdash; and that just as Afghan culture is a surviving example of oral society, the &lt;a href="https://en.wikipedia.org/wiki/Pirahã_people"&gt;Pirahã&lt;/a&gt; culture recently studied in the Amazon is a surviving example of... &lt;i&gt;verbal&lt;/i&gt; society.&amp;nbsp; (I can't bring myself to call it "pre-oral", since language is still spoken; but it does have words, and is missing &lt;i&gt;oration&lt;/i&gt;, so "verbal" will do till something better comes along.)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://fexpr.blogspot.com/2011/03/memetic-organisms.html"&gt;Scientific organisms&lt;/a&gt; need a literate environment to survive; religious organisms don't need literacy, and were, I reckon, the giants that roamed the ideosphere in the age of orality.&amp;nbsp; But in the age &lt;i&gt;before&lt;/i&gt; Homer's, religions could not have survived either.&amp;nbsp; If ever there were an actual event that fits beautifully with the myth of Adam and Eve eating of the fruit of the Tree of Knowledge, the transition from verbal to oral society would be it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Oral thought&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In an oral society (in Havelock's vision &amp;mdash; I've also read parts of Walter Ong's &lt;i&gt;&lt;a href="https://en.wikipedia.org/wiki/Walter_J._Ong#Orality_and_Literacy_.281982.29"&gt;Orality and Literacy&lt;/a&gt;&lt;/i&gt;, which follows Havelock's paradigm), knowledge is preserved through an oral tradition.&amp;nbsp; The form of the account matters; facts are mutated as convenient to put them in a form that will be successfully replicated over many retellings.&amp;nbsp; Standard patterns are used.&amp;nbsp; Repetition is used.&amp;nbsp; A good story also always has an actor:&amp;nbsp; things don't just happen, they are &lt;i&gt;done&lt;/i&gt;, &lt;i&gt;by&lt;/i&gt; somebody, which may favor a polytheistic society, with deities personifying what we (in a literate society) would call "abstract" forces.&amp;nbsp; One might well end up with some such pattern as&lt;br /&gt;&lt;blockquote&gt;And God said, let there be &lt;i&gt;x&lt;/i&gt;.&amp;nbsp; And there was &lt;i&gt;x&lt;/i&gt;.&amp;nbsp; And God saw the &lt;i&gt;x&lt;/i&gt;, and saw that it was good.&amp;nbsp; And the morning and the evening were the &lt;i&gt;n&lt;sup&gt;th&lt;/sup&gt;&lt;/i&gt; day.&lt;br /&gt;&lt;br /&gt;And God said, let there be &lt;i&gt;y&lt;/i&gt;.&amp;nbsp; And there was &lt;i&gt;y&lt;/i&gt;.&amp;nbsp; And God saw the &lt;i&gt;y&lt;/i&gt;, and saw that it was good.&amp;nbsp; And the morning and the evening were the &lt;i&gt;n+1&lt;sup&gt;st&lt;/sup&gt;&lt;/i&gt; day.&lt;br /&gt;&lt;/blockquote&gt;(Note the repetition of each item, repetition of the pattern, and the &lt;i&gt;actor&lt;/i&gt;.)&amp;nbsp; For a more concrete example, here is the start of &lt;a href="https://en.wikisource.org/wiki/Homer%27s_Iliads_in_English"&gt;Thomas Hobbes's 1676 translation of Homer's &lt;i&gt;Iliad&lt;/i&gt;&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;O goddess sing what woe the discontent&lt;br /&gt;Of Thetis’ son brought to the Greeks; what souls&lt;br /&gt;Of heroes down to Erebus it sent,&lt;br /&gt;Leaving their bodies unto dogs and fowls;&lt;br /&gt;Whilst the two princes of the army strove,&lt;br /&gt;King Agamemnon and Achilles stout.&lt;br /&gt;&lt;/blockquote&gt;Notice that things here don't &lt;i&gt;happen&lt;/i&gt;, somebody/something &lt;i&gt;does&lt;/i&gt; them.&amp;nbsp; The goddess sings.&amp;nbsp; The discontent (of Thetis' son) brings, sends, leaves.&amp;nbsp; The two princes strive.&lt;br /&gt;&lt;br /&gt;The things that are acted on are concrete as well; nothing is abstract in our literate sense.&lt;br /&gt;&lt;br /&gt;Such oral tradition can be written down, and was written down, without disrupting the orality of the society.&amp;nbsp; Literate society is what happens when the culture itself embraces writing as a means of preserving knowledge &lt;i&gt;instead of&lt;/i&gt; an oral tradition.&amp;nbsp; Once literacy is assimilated, set patterns are no longer needed, repetition is no longer needed, pervasive &lt;i&gt;actors&lt;/i&gt; are no longer needed, and details become reliably stable in a way that simply doesn't happen in oral society &amp;mdash; the keepers of an oral tradition are apt to believe they tell a story exactly the same way each time, but only because they and their telling change as one.&amp;nbsp; When the actors go away, it becomes possible to conceive of abstract entities.&amp;nbsp; Plato, with his descriptions of shadows on a cave wall, and Ideal Forms, and such, was (Havelock reckoned) trying to explain literate abstraction in a way that might be understood by someone with an oral worldview.&lt;br /&gt;&lt;br /&gt;Note that science can't possibly survive in an oral environment.&amp;nbsp; It relies on an objectively fixed record of phenomena, against which to judge theories; and it centrally studies abstract forces.&amp;nbsp; Religion, on the other hand, is ideally suited to an oral environment.&amp;nbsp; I suggest that religious organisms were the dominant taxon of memetic organisms in oral society, and the taxon of scientific organisms evolved once literate society made it possible.&amp;nbsp; Leading to a classic Darwinian struggle for survival between the two taxa.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Verbal thought&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Those who study natural languages have a luxury not afforded to &lt;a href="https://en.wikibooks.org/wiki/Conlang/Types"&gt;artlangers&lt;/a&gt;, those who create languages artistically:&amp;nbsp; When a natural language crops up that violates the "natural" rules that linguists &lt;i&gt;thought&lt;/i&gt; they understood, new rules can be invented to fit.&amp;nbsp; But, if an artlanger creates a language that violates the rules linguists think they understand, their creation is likely to be ridiculed.&amp;nbsp; This was the observation of David J. Peterson in an essay in 2007 (he gives a "Smiley award" to a conlang each year, and does so in essays containing some brilliant deep insights into conlanging).&lt;br /&gt;&lt;blockquote&gt;What is it to a linguist if Pirahã exists? "That sounds totally fake," says the skeptic. Says the linguist, "Yeah, doesn't it?" But in a world where Pirahã doesn't exist, imagine the conlanger who created it. "I just made up a language with no temporal vocabulary or tense whatsoever, no number system, and a culture of people who have no oral history, no art, and no appreciation for storytelling. Oh, yeah, and the language can just as easily be whistled, hummed or drummed as spoken. Oh, and the men and women have different phonologies. Oh yeah, and it's spoken in an area with a dominant language, but nobody speaks it, because they think their language is the best. Oh yeah, and it's supposed to be a naturalistic language." Suddenly when someone counters and says, "That sounds totally fake," the conlanger is put on the defensive, because they do have to account for it—in other words, "Yeah, doesn't it?" isn't going to fly.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; David J. Peterson, &lt;a href="http://dedalvs.conlang.org/smileys/2007.html"&gt;The 2007 Smiley Award Winner: Teonaht&lt;/a&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;Which is interesting for a conlanger, but &lt;i&gt;fascinating&lt;/i&gt; in light of Havelock's notion of oral society.&amp;nbsp; That list of features is pretty much explicitly saying the language doesn't and can't support an oral society:&amp;nbsp; "no oral history, no art, and no appreciation for storytelling" (doesn't), "no temporal vocabulary or tense whatsoever, no number sytem" (can't).&amp;nbsp; And for a verbal society to survive in a world where the main Darwinian memetic struggle is between literacy and orality, &lt;i&gt;of course&lt;/i&gt; it would have to be an extraordinarily compelling instance of verbality &amp;mdash; "nobody speaks" the dominant language of the area, "because they think their language is the best."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;The fruit of the Tree of Knowledge&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Pirahã were studied by Daniel Everett, who originally approached them with an evangelical mission &amp;mdash; the point of such efforts is to learn an isolated people's language, then translate the teachings of Christianity into that language.&amp;nbsp; Of course this failed miserably with the Pirahã, with their compellingly verbal language and culture (J.R.R. Tolkien criticized the international auxilliary language Esperanto as sterile because it had no mythology behind it (one could argue Esperanto now &lt;i&gt;does&lt;/i&gt; have a mythology of a sort (but I digress))).&amp;nbsp; Within a few years after completing his dissertation, Everett became an atheist.&amp;nbsp; (Everett's 2008 book on his experiences with the Pirahã is &lt;i&gt;&lt;a href="https://en.wikipedia.org/wiki/Daniel_Everett#Don.27t_Sleep_There_are_Snakes:_Life_and_Language_in_the_Amazonian_Jungle"&gt;Don't Sleep There are Snakes: Life and Language in the Amazonian Jungle&lt;/a&gt;&lt;/i&gt;.)&lt;br /&gt;&lt;br /&gt;All of which goes to show that the &lt;a href="https://en.wikipedia.org/wiki/Fall_of_Man"&gt;myth of the fruit of the Tree of Knowledge&lt;/a&gt; can be handily applied to the transition from verbal to oral society.&amp;nbsp; However, as I pointed out in my &lt;a href="http://fexpr.blogspot.com/2011/03/memetic-organisms.html"&gt;earlier post on memetic organisms&lt;/a&gt;, religious teachings are &lt;i&gt;naturally selected&lt;/i&gt; for their ambiguity, their ability to be given a wide variety of different interpretations.&amp;nbsp; The plausibility of an interpretation of the myth is, therefore, pretty much meaningless &amp;mdash; the myth is a contextual chamelion, &lt;i&gt;expected&lt;/i&gt; to blend plausibly into different belief systems.&amp;nbsp; But it is interesting to consider how the myth might have evolved.&amp;nbsp; The early Judaic written tradition is evidently a written record of an originally oral tradition, and an oral tradition mutates events into a good story (i.e., a highly replicable one).&amp;nbsp; If the verbality conjecture is somewhere in the general neighborhood of the truth, there may once have been a vast cultural upheaval as orality supplanted verbality, perhaps (or perhaps not) on a par with the modern struggle between scientific and religious thinking (a major theme of current geopolitics).&amp;nbsp; Such an upheaval might be expected to make a lasting impression on the oral societies that emerged; the lasting impression would be a myth; and the myth would be shaped into the forms of orality, with concrete actors and objects.&amp;nbsp; What sort of myth do &lt;i&gt;you&lt;/i&gt; think might result?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-4136939160057458680?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/4136939160057458680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/12/preface-to-homer.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/4136939160057458680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/4136939160057458680'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/12/preface-to-homer.html' title='Preface to Homer'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-7804041610439237362</id><published>2011-12-09T10:43:00.000-08:00</published><updated>2011-12-09T10:43:16.441-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='monads'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>The trouble with monads</title><content type='html'>&lt;blockquote&gt;IT was six men of Indostan&lt;br /&gt;&amp;nbsp; &amp;nbsp; To learning much inclined,&lt;br /&gt;Who went to see the Elephant&lt;br /&gt;&amp;nbsp &amp;nbsp; (Though all of them were blind),&lt;br /&gt;That each by observation &lt;br /&gt;&amp;nbsp; &amp;nbsp; Might satisfy his mind.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; &lt;a href="https://en.wikisource.org/wiki/The_poems_of_John_Godfrey_Saxe/The_Blind_Men_and_the_Elephant"&gt;The Blind Men and the Elephant&lt;/a&gt;, John Godfrey Saxe&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Note:&amp;nbsp; So far, I've found three different ways of applying this epigraph to the following blog post.&lt;/i&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;Monadic programming is a device by which pure functional languages are able to handle impure forms of computation (side-effects).&amp;nbsp; Depending on who you ask, it's either very natural or preposterously esoteric.&lt;br /&gt;&lt;br /&gt;I submit there is a systemic problem with monadic programming in its current form.&amp;nbsp; Superficially, the problem appears technical.&amp;nbsp; Just beneath that surface, it appears to be about breaking abstraction barriers.&amp;nbsp; Below that, the abstraction barriers seem to have already been broken by the pure functional programming paradigm.&amp;nbsp; I'll suggest, broadly, an alternative approach to functional programming that might resurrect the otherwise disabled abstraction barriers.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;What monads do for pure FP&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A pure function has no side-effects.&amp;nbsp; Pure functional programming &amp;mdash;programming entirely with pure functions&amp;mdash; has some advantages for correctness proofs, which is (arguably) all very well as long as the &lt;i&gt;purpose&lt;/i&gt; of the program is to produce a final answer.&amp;nbsp; Producing a final answer is just what a pure function does.&amp;nbsp; Sometimes, though, impurities are part of the purpose of the program.&amp;nbsp; I/O is the canonical example:&amp;nbsp; if the point is to interact with the external world, a program that cannot interact with the external world certainly misses the point.&lt;br /&gt;&lt;br /&gt;If the point is to interact with the external world, and you still want to use a pure function to do it, you can write a pure function that (in essence) takes the state of the external world as a parameter, and returns its result together with a consequent state of the external world.&amp;nbsp; Other forms of impurity can be handled similarly, with a pure function that explicitly provides for the particular variety of impurity; monads are "simply" a general pattern for a broad range of such explicit provisions.&lt;br /&gt;&lt;br /&gt;Note, however, that while the monadic program is parameterized by the initial state of the external world, the monad itself is &lt;b&gt;hardcoded&lt;/b&gt; into the type signature of the pure function.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;What goes wrong&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The essential difficulty with this approach is that since the monad is hardcoded into the function's type signature, it also gets hardcoded into clients who wish to call that function.&lt;br /&gt;&lt;br /&gt;To illustrate the resulting brittleness, suppose some relatively small function &lt;i&gt;f&lt;/i&gt; is used by a large program &lt;i&gt;p&lt;/i&gt;, involving may functions, with calls to &lt;i&gt;f&lt;/i&gt; at the bottom of many layers of nesting of calls.&amp;nbsp; Suppose all the functions in &lt;i&gt;p&lt;/i&gt; are pure, but later, we decide each call to &lt;i&gt;f&lt;/i&gt; should incidentally output some diagnostic message, which makes no difference to the operation of the program but is meant to be observed by a human operator.&amp;nbsp; That's I/O, and the type signature of &lt;i&gt;f&lt;/i&gt; hadn't provided for I/O; so we have to change its type signature by wiring in a suitable I/O monad.&amp;nbsp; But then, each function that directly calls &lt;i&gt;f&lt;/i&gt; has to be changed to recognize the new signature of &lt;i&gt;f&lt;/i&gt;, and since the calling function now involves I/O, its type signature too has to change.&amp;nbsp; And type signatures change all the way up the hierarchy of nested function calls, until the main function of &lt;i&gt;p&lt;/i&gt; gets a different type signature.&lt;br /&gt;&lt;br /&gt;Every direct or indirect client of &lt;i&gt;f&lt;/i&gt; has been forced to provide for the stateful I/O behavior of &lt;i&gt;f&lt;/i&gt;.&amp;nbsp; One could ask, though, why this stateful behavior of &lt;i&gt;f&lt;/i&gt; should make any difference at all to those clients.&amp;nbsp; &lt;b&gt;They&lt;/b&gt; don't do any I/O, and if not for this type-signature business they wouldn't care that &lt;i&gt;f&lt;/i&gt; does; so why should &lt;i&gt;f&lt;/i&gt;'s I/O be any of their business?&amp;nbsp; For them to bother with it at all seems a violation of an abstraction barrier of &lt;i&gt;f&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Actually, this very real abstraction violation was not caused by the introduction of monads into pure functional programming &amp;mdash; it was &lt;i&gt;highlighted&lt;/i&gt; by that introduction.&amp;nbsp; The violation had already occurred with the imposition of pure functional programming, which denies each component function the right to practice impurities behind an abstraction barrier while merely presenting a pure appearance to its clients.&lt;br /&gt;&lt;br /&gt;The introduction of monads also created the distracting illusion that the clients were the ones responsible for violating the abstraction barrier.&amp;nbsp; On the contrary, the clients are merely where the symptoms of the violation appear.&amp;nbsp; The question should not be why the client function cares whether &lt;i&gt;f&lt;/i&gt; is internally impure (it doesn't care; its involvement was forced), but rather, who is it who &lt;i&gt;does&lt;/i&gt; care, and why?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Bigness&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Monads come from a relatively modern branch of mathematics (it's a mere half-century old) called &lt;b&gt;category theory&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;A category is a well-behaved family of &lt;b&gt;morphisms&lt;/b&gt; between &lt;b&gt;objects&lt;/b&gt; of some uniform kind.&amp;nbsp; The category provides one operation on morphisms:&amp;nbsp; &lt;b&gt;composition&lt;/b&gt;, which is defined only when one morphism ends on the same object where the next morphism starts.&amp;nbsp (Technically, a category &lt;i&gt;is&lt;/i&gt; its composition operation, in that two different categories may have the same objects and the same morphisms, and still be different if their composition operation is different.)&lt;br /&gt;&lt;br /&gt;The canonical example is category &lt;b&gt;Set&lt;/b&gt;, which is the family of mathematical functions between sets &amp;mdash; with the usual notion of function composition.&amp;nbsp; That's all possible functions, between all possible sets.&amp;nbsp; This is typical of the &lt;i&gt;scale&lt;/i&gt; at which category theory is brought to bear on computation theory:&amp;nbsp; a category represents the universe of all possible computations of interest.&amp;nbsp; The categories involved are then things like all computable pure functions, or all computable functions with a certain kind of side-effect &amp;mdash; it should be clearly understood that these categories are &lt;b&gt;big&lt;/b&gt;.&amp;nbsp; Staggeringly, cosmologically, big.&lt;br /&gt;&lt;br /&gt;Besides well-behaved families of morphisms between objects of a uniform kind, there are also well-behaved families of morphisms from objects of one uniform kind to objects of another uniform kind.&amp;nbsp; These families of heterogenous morphisms are called &lt;b&gt;adjunctions&lt;/b&gt;.&amp;nbsp; An adjunction includes, within its structure, a category of homogeneous morphisms within each of the two kinds of objects &amp;mdash; called the &lt;b&gt;domain category&lt;/b&gt; (from which) and &lt;b&gt;codomain category&lt;/b&gt; (to which the heterogeneous morphisms of the adjunction go).&amp;nbsp; The adjunction also projects objects and morphisms of each category onto the other, projects each of its own heterogeneous morphisms as a homogeneous morphism in each of the categories, and requires various relations to hold in each category between the various projections.&lt;br /&gt;&lt;br /&gt;The whole massive adjunction structure can be viewed as a morphism from the domain category to the codomain category &amp;mdash; and adjunctions viewed this way are, in fact, composable in a (what else?) very well-behaved way, so that one has a category &lt;b&gt;Adj&lt;/b&gt; whose objects are categories and whose morphisms are adjunctions.&amp;nbsp; If the categories we're interested in are whole universes of computation, and the adjunctions are massive structures relating pairs of universes, the adjunctive category &lt;b&gt;Adj&lt;/b&gt; is mind-numbingly vast.&amp;nbsp; (In its rigorous mathematical treatment, &lt;b&gt;Adj&lt;/b&gt; is a &lt;i&gt;large&lt;/i&gt; category, which means it's too big to be contained in large categories, which can themselves only contain "small" categories &amp;mdash; an arrangement that prevents large categories from containing themselves and thereby avoids &lt;a href="https://en.wikipedia.org/wiki/Russell%27s_paradox"&gt;Russell's paradox&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;A &lt;b&gt;monad&lt;/b&gt; is the result of projecting all the parts of an adjunction onto its domain category &amp;mdash; in effect, it is the "shadow" that the adjunction casts in the domain.&amp;nbsp; This allows the entire relation between the two categories to be viewed within the universe of the domain; and in the categorical view of computation, it allows various forms of impure computation to be viewed within the universe of pure computation.&amp;nbsp; This was (to my knowledge) the earliest use of monads in relation to computation:&amp;nbsp; a device for viewing impure computation within the world of pure computation.&amp;nbsp; A significant limitation in this manner of viewing impure computations is that, although adjunctions are composable, &lt;i&gt;monads in general are not&lt;/i&gt;.&amp;nbsp; Here the "shadow" metaphor works tolerably well:&amp;nbsp; two unconnected things may appear from their shadows to be connected.&amp;nbsp; Adjunctions are only composable if the domain of one is the codomain of the other &amp;mdash; which is almost certainly not true here, because all our monads have the same domain category (pure computation), while the shadows cast in pure computation all appear to coincide since the distinct codomains have all been collapsed into the domain.&lt;br /&gt;&lt;br /&gt;Who is viewing these various forms of computation, through the shadows they cast on the world of pure computation?&amp;nbsp; Evidently, the programmer &amp;mdash; in their role as Creator.&amp;nbsp; A &lt;a href="https://en.wikipedia.org/wiki/God%27s_eye_view#The_omniscient_perspective"&gt;God's eye view&lt;/a&gt;.&amp;nbsp; Viewing the totality of &lt;i&gt;p&lt;/i&gt; through the universe of pure computation is the point of the exercise; the need for all clients of &lt;i&gt;f&lt;/i&gt; to accommodate themselves to &lt;i&gt;f&lt;/i&gt;'s internal use of I/O is an artifact of the programmer's choice of view.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Rethinking the paradigm&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, here are the points we have to work with.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; A monad &lt;b&gt;represents&lt;/b&gt; the physical laws of a computational universe within which functions exist.&lt;br /&gt;&lt;li&gt; The monad itself exists &lt;b&gt;within the pure computational universe&lt;/b&gt;, rather than within the universe whose laws it represents.&amp;nbsp This is why monads are generally uncomposable:&amp;nbsp; they have forgotten which actual universes they represent, and composition of adjunctions wants that forgotten knowledge.&lt;br /&gt;&lt;li&gt; Function signatures reflect these computational laws, but serve two different purposes.&amp;nbsp; From the &lt;b&gt;client's eye view&lt;/b&gt;, a function signature is an interface abstraction; while from the &lt;b&gt;God's eye view&lt;/b&gt; (in the pure computational universe), a function signature is the laws under which the function and everything it uses must operate.&lt;br /&gt;&lt;/ul&gt;To uncouple a function's interface from its laws of computation, we need a function signature that does not take a God's eye view.&amp;nbsp; The most "purity" one can then ascribe to a function &lt;i&gt;f&lt;/i&gt;, looking at the definition of &lt;i&gt;f&lt;/i&gt; without the definitions of other functions it calls, is that &lt;i&gt;f&lt;/i&gt; uses other functions &lt;i&gt;as if&lt;/i&gt; they were pure, and doesn't itself introduce any impurities.From a God's eye view, computational laws then have to pass from function to function, either&lt;ul&gt;&lt;li&gt; by synthesis &amp;mdash; when function &lt;i&gt;f&lt;/i&gt; calls function &lt;i&gt;g&lt;/i&gt;, &lt;i&gt;g&lt;/i&gt; returns its computational laws along with its result value, and &lt;i&gt;f&lt;/i&gt; works out how to knit them all into a coherent behavior, and returns its own knit-together computational laws along with its own result value &amp;mdash; or&lt;br /&gt;&lt;li&gt; by inheritance &amp;mdash; when function &lt;i&gt;f&lt;/i&gt; calls function &lt;i&gt;g&lt;/i&gt;, &lt;i&gt;f&lt;/i&gt; passes in its computation laws along with its parameters to &lt;i&gt;g&lt;/i&gt;, and &lt;i&gt;g&lt;/i&gt; works out both how to knit them into its own computational laws internally, and how to present itself to &lt;i&gt;f&lt;/i&gt; in terms &lt;i&gt;f&lt;/i&gt; can understand.&lt;br /&gt;&lt;/ul&gt;For purposes of abstraction, inheritance ought to be the way to go, because the point of abstraction is to reduce the conceptual burden on the caller, rather than increase it.&amp;nbsp; Not surprisingly, inheritance also appears to be the more daunting strategy to figure out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-7804041610439237362?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/7804041610439237362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/12/trouble-with-monads.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7804041610439237362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7804041610439237362'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/12/trouble-with-monads.html' title='The trouble with monads'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-3299400169327933262</id><published>2011-11-30T05:39:00.000-08:00</published><updated>2011-11-30T05:39:29.917-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><title type='text'>Rhyming in US politics</title><content type='html'>&lt;blockquote&gt;&lt;i&gt;Just a small structural insight into US politics (as &lt;a href="http://fexpr.blogspot.com/2011/03/prosaic-first-post.html"&gt;advertised&lt;/a&gt;).&lt;/i&gt;&lt;/blockquote&gt;Republicans in Congress have allowed their agenda to be set by President Obama.&lt;br /&gt;&lt;br /&gt;Republicans in Congress are being obstructionist; this shouldn't be a controversial statement, since historically they haven't made a secret of it (though, in something rather like a Catch-22, the insight I'm heading for makes it natural to expect disagreement on this along party lines).&amp;nbsp; But what one ought to be asking is &lt;i&gt;why&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;It's simple, really.&amp;nbsp; When an administration comes in, the opposition usually aligns itself squarely against the central priority of the new administration.&amp;nbsp; Although this &lt;i&gt;may&lt;/i&gt; be a disagreement that predates the new administration, a sadder scenario &amp;mdash;for all parties, and for the electorate&amp;mdash; is that the opposition may be in disarray and simply not have any better focus than, well, opposing.&amp;nbsp; On secondary issues there may be all kinds of cooperation, but by default, not on that central priority.&lt;br /&gt;&lt;br /&gt;And here we have a president who was really pretty explicit, before elected, that his central priority is &lt;i&gt;cooperation&lt;/i&gt;.&amp;nbsp; It's the message that got him national attention in the first place:&amp;nbsp; just because we have disagreements doesn't mean we can't cooperate.&lt;br /&gt;&lt;br /&gt;Now, consider how one would go about opposing that priority, and compare it to the current situation.&lt;br /&gt;&lt;br /&gt;And, to see the other side of the coin, consider how one would go about &lt;i&gt;pursuing&lt;/i&gt; that priority &amp;mdash; in the face of opposition to it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-3299400169327933262?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/3299400169327933262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/11/rhyming-in-us-politics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/3299400169327933262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/3299400169327933262'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/11/rhyming-in-us-politics.html' title='Rhyming in US politics'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-6962528189910608826</id><published>2011-11-14T12:55:00.000-08:00</published><updated>2011-11-14T13:43:47.360-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='types'/><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Where do types come from?</title><content type='html'>&lt;blockquote&gt;[On the phone] There's a man here with some sort of a parasite on his arm, assimilating his flesh at a frightening speed.&amp;nbsp; I may have to get ahead of it and amputate.&amp;nbsp; No... I don't know what it is or where it came from.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; Dr. Hallen, &lt;i&gt;&lt;a href="https://en.wikiquote.org/wiki/The_Blob"&gt;The Blob&lt;/a&gt;&lt;/i&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;I took some tolerably advanced math courses in college and graduate school.&amp;nbsp; My graduate research group of choice was the Theory Umbrella Group (THUG), joint between the math and computer science departments.&amp;nbsp; But one thing I never encountered in any of those courses, nor that-I-recall even in the THUG talks, was a type.&amp;nbsp; Sets aplenty, but not types.&amp;nbsp; Types seem to arise from specifically studying computer science, mathematics proper having no native interest in them.&amp;nbsp; There are the "types" in Russell and Whitehead's &lt;i&gt;&lt;a href="https://en.wikipedia.org/wiki/Principia_Mathematica"&gt;Principia Mathematica&lt;/a&gt;&lt;/i&gt;, but those don't seem to me to have anything really to do with types as experienced in programming.&lt;br /&gt;&lt;br /&gt;Yet, over in the computer science department, we're awash in types.&amp;nbsp; They're certainly &lt;i&gt;used&lt;/i&gt; for reasoning about programs (both practically and theoreticially) &amp;mdash; but at some point our reasoning may become more about the types themselves than about the programs they apply to.&amp;nbsp; Type systems can be strikingly reminiscent of bureaucratic red tape when one is getting &lt;a href="http://lambda-the-ultimate.org/node/4400#comment-68285"&gt;tangled up in them&lt;/a&gt;.&amp;nbsp; So, if they aren't a natively mathematical concept, why are they involved in our reasoning at all?&amp;nbsp; Are they natural to what we're reasoning about (programs), or an unfortunate historical artifact?&amp;nbsp; From the other side, is &lt;a href="http://lambda-the-ultimate.org/node/4401#comment-68293"&gt;reasoning in mathematics&lt;/a&gt; simpler because it doesn't use types, or does it not need to use types because what it's reasoning about is simpler?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Representation format&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Looking back at the early history of programming, types evidently arose from the need to keep track of what format was being used by a given block of binary data.&amp;nbsp; If a storage cell was assigned a value using a floating-point numerical representation, and you're trying to treat it as a series of ASCII characters, that's probably because you've lost track of what you meant to be doing.&amp;nbsp; So we associate format information with each such cell.&amp;nbsp; Note that we are not, at this point, dealing directly with the abstract entities of mathematics, but with sequences of storage bits, typically fixed-width sequences at that.&amp;nbsp; Nor does the type even tell us about a sort of mathematical entity that is being stored, because within the &lt;a href="http://fexpr.blogspot.com/2011/11/allowing-and-disallowing.html"&gt;worldview&lt;/a&gt; presented by our programming language, we aren't storing a mathematical entity, we're representing a data value.&amp;nbsp; Data values are more abstract than bit sequences, but a lot less abstract than the creatures we'd meet in the math department.&amp;nbsp; The essential difference, I'd suggest, is that unlike their mathematical cousins, data values carry about with them some of their own representation format, in this case bit-level representation format.&lt;br /&gt;&lt;br /&gt;A typical further development in typing is user-defined (which is to say, programmer-defined) types.&amp;nbsp; Each such type is still stored in a sequence of storage bits, and still tells us how the storage is being used to represent a data value, rather than store a mathematical entity.&amp;nbsp; There is a significant difference from the earlier form of typing, in that the language will (almost certainly) support a practically infinite number of possible user-defined types, so that the types themselves have somewhat the character of mathematical abstract entities, rather than data values (let alone bit sequences).&amp;nbsp; If, in fact, mathematics gets much of its character by dealing with its abstract entities unfettered by representational issues (mathematics would deal with representation itself as just another abstract domain), a computer scientist who wants that character will prefer to reason as much as possible &lt;b&gt;about types&lt;/b&gt; rather than about data values or storage cells.&lt;br /&gt;&lt;br /&gt;Another possible development in typing, orthogonal to user-defined types, is representation-independence, so that the values constrained by types are understood as mathematical entities rather than data values.&amp;nbsp; The classic example is type &lt;i&gt;bignum&lt;/i&gt;, whose values are conceptually mathematical integers.&amp;nbsp; Emphasis on runtime efficiency tends to heighten awareness of representational issues, so one expects an inverse relation between that emphasis, and likelihood of representation-independent types.&amp;nbsp; It's not a coincidence that bignums flourish in Lisp.&amp;nbsp; Note also that a key twist in the statement of the &lt;a href="http://lambda-the-ultimate.org/node/4400"&gt;expression problem&lt;/a&gt; is the phrase "without recompiling existing code".&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Complicated type systems as crutches&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once we &lt;i&gt;have&lt;/i&gt; types, since we're accustomed to thinking about programs, we tend to want to endow our type systems with other properties we know from our programming models.&amp;nbsp; Parametric types.&amp;nbsp; Dependent types.&amp;nbsp; Ultimately, first-class types.&lt;br /&gt;&lt;br /&gt;I've felt the lure of first-class types myself, because they abandon the pretense that complicated types systems aren't treating types computationally.&amp;nbsp; There's an incomplete language design in my files wherein a type is an object with two methods, one for determining membership and one for determining sub/supertyping.&amp;nbsp; That way leads to unbounded complications &amp;mdash; the same train of thought has led me more recently to consider tampering with incompleteness of the continuum (cf. Section&amp;nbsp;8.4.2 of &lt;a href="http://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/"&gt;my dissertation&lt;/a&gt;; yet another potential blog typic).&amp;nbsp; As soon as I envisioned that type system, I could see it was opening the door to a vast world of bizarre tricks that I absolutely didn't want.&amp;nbsp; I really wanted my types to behave as mathematical &lt;i&gt;sets&lt;/i&gt;, with stable membership and transitive subtyping &amp;mdash; and if that's what you want, you probably shouldn't try to get there by first giving the methods Turing power and then backing off from it.&lt;br /&gt;&lt;br /&gt;But, from the above, I submit that these complicated type systems are incited, to begin with, when we start down the slippery slope by&lt;br /&gt;&lt;ul&gt;&lt;li&gt; tangling with data values &amp;mdash;halfway between the abstract and concrete worlds&amp;mdash; instead of abstract mathematical entities, and&lt;/li&gt;&lt;li&gt; placing undue emphasis on types, rather than the things they describe.&amp;nbsp; This we did in the first place, remember, because types were more nearly mathematical; the irony of that is fairly intense.&lt;/li&gt;&lt;/ul&gt;In contrast to the muddle of complicated typing in computer science, folks over in the math department deal mostly with sets, a lightweight concept that fades comfortably into the background and only has to be attended carefully under fairly extreme circumstances.&amp;nbsp; Indeed, contrasting types and sets, a major difference between them is that types have &lt;i&gt;object identity&lt;/i&gt; &amp;mdash; which is itself a borderline representational concept (able to come down on either side of the line), and jibes with experience that sophisticated types become data structures in their own right.&amp;nbsp; Yes, there are such things as types that don't have object identity; but somehow it seems we've already crossed the Rubicon on that one, and can no longer escape from the idea even in languages that don't endorse it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Where next?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What we need, it seems, is the &lt;i&gt;lightweight&lt;/i&gt; character of mathematical reasoning.&amp;nbsp; There's more to it than mathematical "purity"; Haskell is fairly pure, but tbh I find it appallingly heavy.&amp;nbsp; I find no sense of working with simple primitives &amp;mdash; it feels to me more like working on a scaffold over an abyss.&amp;nbsp; In mathematics, there may be several different views of things any one of which could be used as a foundation from which to build the others.&amp;nbsp; That's essentially &lt;i&gt;perfect&lt;/i&gt; abstraction, in that from any one of these levels, you not only get to ignore what's under the hood, but you can't even tell whether there &lt;i&gt;is&lt;/i&gt; anything under the hood.&amp;nbsp; Going from one level to the next leaves no residue of unhidden details:&amp;nbsp; you could build B from A, C from B, and A from C, and you've really gotten back to A, not some flawed approximation of it that's either more complicated than the original, more brittle than the original, or both.&lt;br /&gt;&lt;br /&gt;Making that happen in a language design should involve some subtle shifts in the way data is conceptualized.&amp;nbsp; That isn't a digression in a discussion of types, because the way we conceptualize data has deep, not to say insidious, effects on the nature of typing.&amp;nbsp; As for the types themselves, I suggest we abandon the whole notion of types in favor of a lightweight mathematical notion of sets &amp;mdash; and avoid using the &lt;i&gt;word&lt;/i&gt; "type" as it naturally drags us back toward the conceptual morass of type theory that we need to escape.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-6962528189910608826?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/6962528189910608826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/11/where-do-types-come-from.html#comment-form' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/6962528189910608826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/6962528189910608826'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/11/where-do-types-come-from.html' title='Where do types come from?'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-8178679517868602608</id><published>2011-11-08T06:23:00.000-08:00</published><updated>2011-11-08T06:38:09.521-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming languages'/><title type='text'>Allowing and disallowing</title><content type='html'>Here are two problems in programming language design that are often treated as if they had to be traded off against each other.&amp;nbsp; I've found it enormously productive to assume that high-level tradeoffs are accidental rather than essential; that is, to assume that if only we find the right vantage to view the problems, we'll see how to have our cake and eat it too.&amp;nbsp; A good first step toward finding a fresh vantage on a problem is to eliminate unnecessary details and assumptions from the statement of the problem.&amp;nbsp; So here are spare, general statements of these two problems.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; &lt;b&gt;Allow&lt;/b&gt; maximally versatile ways of doing things, with maximal facility.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; &lt;b&gt;Disallow&lt;/b&gt; undesirable behavior.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I've been accused of promoting unmanageable chaos because my publicly visible work (on Kernel and fexprs) focuses on the first problem with some degree of merry disregard for the second.&amp;nbsp; So here I'll explain some of my thoughts on the second problem and its relationship to the first.&lt;br /&gt;&lt;br /&gt;How difficult are these problems?&amp;nbsp; One can only guess how long it will actually take to tame a major problem; there's always the chance somebody could find a simple solution tomorrow, or next week.&amp;nbsp; But based on their history, I'd guess these problems have a half-life of at least half a century.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Why&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To clarify my view of these problems, including what I mean by them, it may help to explain why I consider them important.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Allowing&lt;/b&gt; is important because exciting, new, and in any and all senses &lt;i&gt;profitable&lt;/i&gt; innovations predictably involve doing things that hadn't been predicted.&amp;nbsp; Software technology needs to grow exponentially, which is a long-term game; in the long term, a programming language either helps programmers imagine and implement unanticipated approaches, or the language will be left in the dust by better languages.&amp;nbsp; This is a sibling to the long-term importance of basic research.&amp;nbsp; It's also a cousin to the economic phenomenon of the &lt;a href="https://en.wikipedia.org/wiki/Long_Tail"&gt;Long Tail&lt;/a&gt;, in which there's substantial total demand for all individually unpopular items in a given category — so that while it would be unprofitable for a traditional store to keep those items in stock, a business can reap profits by offering the whole range of unpopular items if it can avoid incurring overhead per item.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Disallowing&lt;/b&gt; is important because, bluntly, we want our programs to work right.&amp;nbsp; A couple of distinctions immediately arise.&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Whose version of "right" are we pursuing?&amp;nbsp; There's "right" as understood by the programmer, and "right" as understood by others.&amp;nbsp; A dramatic divergence occurs in the case of a malicious programmer.&amp;nbsp; Of course, protecting against programmer malfeasance is especially challenging to reconcile with the &lt;i&gt;allowing&lt;/i&gt; side of the equation.&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Some things we are &lt;i&gt;directly&lt;/i&gt; motivated to disallow, others &lt;i&gt;indirectly&lt;/i&gt;.&amp;nbsp; Direct motivation means that thing would in itself do something we don't want done.&amp;nbsp; Indirect motivation means that thing would make it harder to &lt;i&gt;prove&lt;/i&gt; the program doesn't do something we don't want done.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;How&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If &lt;b&gt;allowing&lt;/b&gt; were a matter of computational freedom, the solution would be to program in machine code.&amp;nbsp; It's not.&amp;nbsp; In practice, a tool isn't versatile or facile if it cannot be used at scale.&amp;nbsp; What we can imagine doing, and what we can then work out how to implement, depends on the worldview provided by the programming language, within which we work, so &lt;b&gt;allowing&lt;/b&gt; depends on this worldview.&amp;nbsp; Nor is the worldview merely a matter of crunching data — it also determines our ability to imagine and implement abstractions within the language — modulating the local worldview, within some broader metaphysics.&amp;nbsp; Hence my interest in &lt;a href="ftp://ftp.cs.wpi.edu/pub/techreports/pdf/08-01.pdf"&gt;abstractive power&lt;/a&gt; (on which I should blog eventually).&lt;br /&gt;&lt;br /&gt;How ought we to go about &lt;b&gt;disallowing&lt;/b&gt;?&amp;nbsp; Here are some dimensions of variation between strategies — keeping in mind, we are trying to sort out &lt;i&gt;possible&lt;/i&gt; strategies, rather than &lt;i&gt;existing&lt;/i&gt; strategies (so not to fall into ruts of traditional thinking).&lt;br /&gt;&lt;ul&gt;&lt;li&gt; One can approach disallowance either by choosing the &lt;b&gt;contours&lt;/b&gt; of the worldview within which the programer works, or by imposing &lt;b&gt;restrictions&lt;/b&gt; on the programmer's freedom to operate within the worldview.&amp;nbsp; The key difference is that if the programmer thinks within the worldview (which should come naturally with a well-crafted worldview), restriction-based disallowance is directly visible, while contour-based disallowance is not.&amp;nbsp; To directly see contour-based disallowance, you have to step outside the worldview.&lt;br /&gt;&lt;br /&gt;To reuse an example I've suggested elsewhere:&amp;nbsp; If a Turing Machine is disallowed from writing on a blank cell on the tape, that's a restriction (which, in this case, reduces the model's computational power to that of a linear bounded automaton).&amp;nbsp; If a Turing Machine's read/write head can move only horizontally, not vertically, that's a contour of the worldview.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Enforcement can be &lt;b&gt;hard&lt;/b&gt; vs &lt;b&gt;soft&lt;/b&gt;.&amp;nbsp; Hard enforcement means programs are rejected if they do not conform.&amp;nbsp; Soft enforcement is anything else.&amp;nbsp; One soft contour approach is the principle I've blogged about under the slogan &lt;a href="http://fexpr.blogspot.com/2011/05/dangerous-things-should-be-difficult-to.html"&gt;dangerous things should be difficult to do &lt;i&gt;by accident&lt;/i&gt;&lt;/a&gt;.&amp;nbsp; Soft restriction might, for example, take the form of a warning, or a property that could be tested for (either by the programmer or by the program).&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Timing can be &lt;b&gt;eager&lt;/b&gt; vs &lt;b&gt;lazy&lt;/b&gt;.&amp;nbsp; Traditional static typing is hard and eager; traditional dynamic typing is hard and lazy.&amp;nbsp; Note, eager–lazy is a spectrum rather than a binary choice.&amp;nbsp; Off hand, I don't see how contour-based disallowance could be lazy (i.e., I'd think laziness would always be directly visible within the worldview); but I wouldn't care to dismiss the possibility.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;All of which is pretty straightforward.&amp;nbsp; There's another dimension I'm less sure how to describe.&amp;nbsp; I'll call it &lt;i&gt;depth&lt;/i&gt;.&amp;nbsp; &lt;b&gt;Shallow&lt;/b&gt; disallowance is based on simple, locally testable criteria.&amp;nbsp; A flat type system, with a small fixed set of data types that are mutually exclusive, is very shallow.&amp;nbsp; &lt;b&gt;Deep&lt;/b&gt; disallowance is based on more sophisticated criteria that engage context.&amp;nbsp; A polymorphic function type has a bit of depth to it; a proof system that supports sophsiticated propositions about code behavior is pretty deep.&lt;br /&gt;&lt;br /&gt;Shallow vs deep tends to play off simplicity against precision.&amp;nbsp; Shallow disallowance strategies are simple, therefore easily understood, which makes them more likely to be used correctly and &amp;mdash;relatively&amp;mdash; less likely to interfere with programmers' ability to imagine new techniques (versatility/facility of allowance).&amp;nbsp; However, shallow disallowance is a blunt instrument, that cannot take out a narrow or delicately structured case of bad behavior without removing everything around it.&amp;nbsp; So some designers turn to very deep strategies —fully articulated theorem-proving, in fact— but thereby introduce conceptual complexity, and the conceptual inflexibility that tends to come with it.&lt;br /&gt;&lt;br /&gt;Recalling my earlier remark about tradeoffs, the tradeoffs we expect to be accdiental are &lt;i&gt;high-level&lt;/i&gt;.&amp;nbsp; Low-level tradeoffs are apt to be essential.&amp;nbsp; If you're calculating reaction mass of a rocket, you'd best accept the tradeoff dictated by &lt;i&gt;F=ma&lt;/i&gt;.&amp;nbsp; On the other hand, if you step back and ask what high-level task you want to perform, you may find it can be done without a rocket.&amp;nbsp; With disallowance depth, deep implies complex, and shallow implies some lack of versatility; there's no getting around those.&amp;nbsp; But does complex disallowance imply brittleness?&amp;nbsp; Does it preclude conceptual clarity?&lt;br /&gt;&lt;br /&gt;One other factor that's at play here is level of descriptive detail.&amp;nbsp; If the programming language doesn't specify something, there's no question of whether to disallow some values of it.&amp;nbsp; If you just say "sort this list", instead of specifying an algorithm for doing so, there's no question —within the language— of whether the algorithm was specified correctly.&amp;nbsp; On the other hand, at some point &lt;i&gt;someone&lt;/i&gt; specified how to sort a list, using some language or other; whatever level of detail a language starts at, you'll want to move up to a higher level later, and not keep respecifying lower-level activities.&amp;nbsp; That's abstraction again.&amp;nbsp; &lt;i&gt;Not caring&lt;/i&gt; what sort algorithm is used may entail significantly more complexity, under the hood, than requiring a fixed algorithm — and again, we're always going to be passing from one such level to another, and having to decide which details we can hide and how to hide them.&amp;nbsp; How all that interacts with disallowance depth may be critical:&amp;nbsp; can we hide complex disallowance beneath abstraction barriers, as we do other forms of complexity?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Merry disregard&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You may notice I've had far more to say about how to disallow, than about how to allow.&amp;nbsp; Allowing is so much more difficult, it's hard to know what to say about it.&amp;nbsp; Once you've chosen a worldview, you have a framework within which to ask how to exclude what you don't want; but finding new worldviews is, rather by definition, an unstructured activity.&lt;br /&gt;&lt;br /&gt;Moreover, thrashing about with specific disallowance tactics may tend to lock you in to worldviews suited to those tactics, when what's needed for truly versatile allowing may be something else entirely.&amp;nbsp; So I reckon that allowing is logically prior to disallowing.&amp;nbsp; And my publicly visible work does, indeed, focus on allowing with a certain merry disregard for the complementary problem of disallowing.&amp;nbsp; Disallowing is never too far from my thoughts; but I don't expect to be able to tackle it properly till I know what sort of allowing worldview it should apply to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-8178679517868602608?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/8178679517868602608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/11/allowing-and-disallowing.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8178679517868602608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8178679517868602608'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/11/allowing-and-disallowing.html' title='Allowing and disallowing'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-7126740766444894258</id><published>2011-06-04T08:17:00.000-07:00</published><updated>2011-06-04T08:17:01.388-07:00</updated><title type='text'>Primacy of syntax</title><content type='html'>One of the most influential papers in the history of computer science is Christopher Strachey's 1967 "Fundamental Concepts in Programming" &amp;mdash; lectures notes for the International Summer School on Computer Programming, Copenhagen.&amp;nbsp; Christopher Strachey basically created the academic subject of programming languages, and in those lecture notes you will find many core concepts laid out.&amp;nbsp; First-class objects.&amp;nbsp; Left-values and right-values.&amp;nbsp; Polymorphism.&amp;nbsp; And so on.&lt;br /&gt;&lt;br /&gt;Although Strachey did write a finished version of the lecture notes for publication in the proceedings of the summer school, those proceedings never materialized &amp;mdash; so copies of the lecture notes were passed from hand to hand.&amp;nbsp; (The modern name for such a phenomenon is "going viral", but it's surely been happening since before writing was invented.)&amp;nbsp; Finally, on the twenty-fifth anniversary of Strachey's untimely death, the finished paper was published.&lt;br /&gt;&lt;br /&gt;By that time, though, I'd spent over a decade studying my cherished copy of the raw lecture notes.&amp;nbsp; The notes consist largely of abbreviated, even cryptic, non-sentences, but their pithy phrases are often more expressive than the polished prose of the published paper &amp;mdash; and sometimes the ideas candidly expressed didn't even make it into the published paper.&amp;nbsp; A particular item from the lecture notes, that has stuck with me from the first moment I read it (about a quarter century ago, by now) is&lt;br /&gt;&lt;blockquote&gt;Basic irrelevance of syntax and primacy of semantics.&lt;br /&gt;&lt;/blockquote&gt;This seems to me to neatly capture an attitude toward syntax that became firmly rooted in the late 1960s, and has scarcely been loosened since.&amp;nbsp; My own passion, though, within the academic subject Strachey created, is &lt;b&gt;abstraction&lt;/b&gt;; and from my first explorations of abstraction in the late 1980s, it has seemed to me that abstraction defies the separation between syntax and semantics.&amp;nbsp; Sometime during the 1988/89 academic year, I opined to a professor that the artificial distinction between syntax and semantics had been retarding the development of abstraction technology for over twenty years &amp;mdash; and the professor I said it to laughed, and after a moment distractedly remarked "that's funny" as they headed off to their next appointment.&amp;nbsp; Nonplussed by that response (I was still rather in awe of professors, in those days), to myself alone I thought, &lt;i&gt;but I wasn't joking&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Abstraction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A source code element modifies the language in which it occurs.&amp;nbsp; Starting, say, with standard Java, one introduces a new class, and ends up with a different programming language &amp;mdash; almost exactly like standard Java, but not quite because it now has this additional class in it.&amp;nbsp; That is abstraction, building a new language on top of an old one.&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Abstraction&lt;/b&gt;:&amp;nbsp; Transformation of one programming language into another by means of facilities available in the former language.&lt;br /&gt;&lt;/blockquote&gt;What makes it abstraction, rather than just an arbitrary PL transformation, is that it uses the facilities of the pre-existing programming language.&amp;nbsp; (For those who prefer to trace their definitions back a few centuries, the key requirement that the new language be latent in the old &amp;mdash;that it be drawn out of the old, Latin &lt;i&gt;abstrahere&lt;/i&gt;&amp;mdash; appears in John Locke's account of abstraction in his &lt;i&gt;An Essay Concerning Human Understanding&lt;/i&gt;; the relevant passage is the epigraph at the top of Chapter&amp;nbsp;1 of &lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-4.html"&gt;the Wizard Book&lt;/a&gt; &amp;mdash; and is also the epigraph at the top of Chapter&amp;nbsp;1 of &lt;a href="http://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/"&gt;my dissertation&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;An &lt;i&gt;abstractively powerful&lt;/i&gt; programming language is, by my reckoning, a language from which one can abstract to a wide variety of other languages.&amp;nbsp; The precise formalization of that is a subtle thing; and worthy of a blog entry of its own, especially since my formal treatment of it, &lt;a href="ftp://ftp.cs.wpi.edu/pub/techreports/pdf/08-01.pdf"&gt;WPI-CS-TR-08-01&lt;/a&gt;, gets rather dense in some parts.&amp;nbsp; For the current entry, though, we don't need those details; the key point here is that the result of the abstraction is another language.&amp;nbsp; This is in contrast to the denotational approach to programming languages (which Strachey helped create, BTW, and which is visible in nascent form in the 1967 lecture notes):&amp;nbsp; denotationally, the programming language is essentially a function which, when applied to a source-code term, produces a semantic value of another sort entirely.&lt;br /&gt;&lt;br /&gt;The idea that semantic results are languages is a very powerful one.&amp;nbsp; The results of computations (and any other embellishment one wants) can be modeled by introducing additional sorts of terms that may occur in languages; the significance of each language is then fully represented by the possible sequences of terms that can follow from it.&amp;nbsp; But then, one doesn't really need the explicit semantics at all.&amp;nbsp; Only the sequences of terms matter, and one can define a programming language by a set of sequences of terms.&amp;nbsp; At that point, one could say that all semantics is being represented as syntax (which is a truism about semantics, anyway), or one could just as well say that semantics has vanished entirely to be replaced with pure syntax.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Lisp and syntax&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Lisp has been described as a language with no syntax.&amp;nbsp; There is a sense in which that's true:&amp;nbsp; if by "syntax" one means "syntax for representing programs rather than data".&amp;nbsp; In primordial S-expression Lisp, the only syntax exclusively represents data.&amp;nbsp; (The way that happened &amp;mdash;to remind&amp;mdash; was that McCarthy had originally envisioned a second kind of syntax, M-expressions, representing programs, but he'd also described an algorithm for encoding M-expressions as S-expressions.&amp;nbsp; He expected to have years in which to polish details of the language since writing a compiler was then understood to be such a colossal undertaking, but in the meantime they were hand-coding specific Lisp functions &amp;mdash; and then S.R. Russell hand-coded &lt;code&gt;&lt;i&gt;eval&lt;/i&gt;&lt;/code&gt;, and abruptly they had a working interpreter for S-expression Lisp.)&lt;br /&gt;&lt;br /&gt;I believe, by the way, this is how Lisp should be taught to novices:&amp;nbsp; Teach them S-expression syntax first, set it firmly in their minds that such expressions are data, and only after that begin to teach them about evaluation.&amp;nbsp; &lt;a href="http://web.cs.wpi.edu/~michaelg/"&gt;Mike Gennert&lt;/a&gt; and I tried this approach with a class back in the spring semester of 1999/2000.&amp;nbsp; Over the duration of the course, we led the students through writing a Scheme interpreter in Java, starting with a level-0 "REPL" loop that was missing the "E" &amp;mdash; it would read in an S-expression, and just write it out without evaluating it.&amp;nbsp; By the end of the term we'd added in proper tail recursion.&amp;nbsp; The experiment as a whole wasn't as successful as we'd hoped, because at the moment we tried it, the department's curriculum was in a state of flux, and many of the students didn't already know Java; but we didn't have the sorts of problems I've seen, or heard others describe, due to novice students failing to think in terms of evaluating S-expressions.&lt;br /&gt;&lt;br /&gt;The connection to abstraction is immediate and compelling.&amp;nbsp; Abstraction is all about specifying how syntax will be used for subsequent program code, and the design of Lisp is focused on virtuoso manipulation of the very type of data structure (S-expressions) that is effectively the syntax of program code.&amp;nbsp; The more power Lisp gives the programmer to control how syntax will be interpreted, the more abstractive power accrues.&amp;nbsp; Since &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;fexprs&lt;/a&gt; greatly expand the programmer's direct control over the interpretation-time behavior of the evaluator (short of the "throw everything out and start over" tactic of running a meta-circular evaluator &amp;mdash; a tactic that lacks &lt;a href="http://fexpr.blogspot.com/2011/05/dangerous-things-should-be-difficult-to.html"&gt;stability&lt;/a&gt;), fexprs should massively increase the (already formidable) abstractive power of Lisp.&amp;nbsp; That's why the subtitle of &lt;a href="http://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/"&gt;my dissertation&lt;/a&gt; is &lt;i&gt;&lt;code&gt;$vau&lt;/code&gt;: the ultimate abstraction&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Note: Polymorphism&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Strachey's 1967 lecture notes are most known &amp;mdash;and cited&amp;mdash; for coining the term &lt;i&gt;polymorphism&lt;/i&gt;.&amp;nbsp; Therein, he divided polymorphism into two forms:&amp;nbsp; &lt;i&gt;parametric&lt;/i&gt; polymorphism, and &lt;i&gt;ad&amp;nbsp;hoc&lt;/i&gt; polymorphism.&lt;br /&gt;&lt;br /&gt;The parametric/ad&amp;nbsp;hoc distinction struck me as a logical bipartition of polymorphism; that is, every possible form of polymorphism would necessarily be either parametric or ad&amp;nbsp;hoc.&amp;nbsp; Evidently &lt;a href="http://lucacardelli.name/Papers/OnUnderstanding.A4.pdf"&gt;Cardelli and Wegner&lt;/a&gt; did not interpret Strachey this way; their taxonomy placed "inclusion polymorphism" outside of both parametric and ad&amp;nbsp;hoc.&lt;br /&gt;&lt;br /&gt;It also strikes me that the name &lt;i&gt;ad&amp;nbsp;hoc&lt;/i&gt; reflects real disapproval.&amp;nbsp; This goes back to the "basic irrelevance of syntax" remark.&amp;nbsp; At heart, parametric polymorphism is semantic, ad&amp;nbsp;hoc is syntactic; one might be tempted to call them "semantic polymorphism" and "syntactic polymorphism", or even "good polymorphism" and "bad polymorphism".&amp;nbsp; There is a close connection between my perception that parametric/ad&amp;nbsp;hoc reflects semantic/syntactic, and my perception that parametric/ad&amp;nbsp;hoc was meant to be exhaustive.&lt;br /&gt;&lt;br /&gt;Although I expect parametric polymorphism should have greater abstractive power than ad&amp;nbsp;hoc polymorphism, I don't like biasing terminology.&amp;nbsp; I'd like to see any formal results stand on their own merits.&amp;nbsp; So, years ago, I looked for an alternative to "ad&amp;nbsp;hoc".&amp;nbsp; The best I came up with at the time:&amp;nbsp; &lt;i&gt;selection polymorphism&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-7126740766444894258?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/7126740766444894258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/06/primacy-of-syntax.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7126740766444894258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7126740766444894258'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/06/primacy-of-syntax.html' title='Primacy of syntax'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-7709944944660563407</id><published>2011-05-17T13:14:00.000-07:00</published><updated>2011-05-17T15:18:58.955-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fexprs'/><category scheme='http://www.blogger.com/atom/ns#' term='Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><category scheme='http://www.blogger.com/atom/ns#' term='static scope'/><title type='text'>Dangerous things should be difficult to do by accident</title><content type='html'>Although this is a key principle for design in general &amp;mdash;scarcely behind supporting what the system is being designed to do&amp;mdash; I'm mainly interested in it here as a principle for designing programming languages.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Bicycles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That said, the metaphor I use to ground the principle is from mechanical engineering.&lt;br /&gt;&lt;br /&gt;A once-popular bicycle design was the "penny-farthing", with a great big front wheel that the rider essentially sat on top of, and a small rear wheel.&amp;nbsp; (Why "penny farthing"?&amp;nbsp; The British penny was a large coin, and the farthing a small one.)&amp;nbsp; The pedals were directly on the front wheel, and the handlebars were directly over it, turning on a vertical axis.&amp;nbsp; What's wrong with that?&amp;nbsp; Obvious problems are that the rider is too far up for their feet to reach the ground, so it's not easy to stop safely; there's a long way to fall; the rider is so far forward that it's easy to fall forward over the front; and it's easy to get one's feet, or clothing, caught in the spokes of the front wheel, especially when turning (as this causes the spokes to move in relation to the rider).&amp;nbsp; All of which obvious problems are eliminated by the later "safety bicycle" design, which has two smaller wheels with the rider sitting between them, feet well away from the parts that turn when steering, and low enough that the rider can simply plant their feet on the ground when stopped.&lt;br /&gt;&lt;br /&gt;The safety bike design also uses a chain to multiply the turning of the pedals into a higher speed than can be achieved with the penny-farthing (and multiplying speed was the reason the front wheel of the penny-farthing was made so big in the first place).&lt;br /&gt;&lt;br /&gt;But another thing I find especially interesting about the safety bicycle design is another innovation:&amp;nbsp; its steering axis &amp;mdash;the axis along which the handle bars rotate the front wheel&amp;mdash; is well off the vertical.&amp;nbsp; This angle off the vertical (called the &lt;i&gt;caster&lt;/i&gt;) means that the force of gravity, pulling the rider down toward the ground, tends to pull the front wheel toward the straight-forward position.&amp;nbsp; In fact, the further the handle bars are turned to either side, the more gravity pushes them back out of the turn.&amp;nbsp; That's inherently stable.&amp;nbsp; (The fact that, riding at speed, both wheels act as gyroscopes doesn't hurt either.)&lt;br /&gt;&lt;br /&gt;So the significant caster of the safety bicycle actively helps the rider to limit turns to &lt;i&gt;intentional&lt;/i&gt; turns.&amp;nbsp; That's the kind of designed-in safety factor a programming language should aspire to (and it's a tough standard to live up to).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Programming languages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Douglas McIlroy, at the 1969 Extensible Languages Symposium, described opposing philosophies of programming language design as "anarchist" and "fascist".&amp;nbsp; The principle of accident avoidance illuminates both philosophies, and the relation between them.&amp;nbsp; (McIlroy was not, BTW, playing favorites to either philosophy, so if you think this terminology is harder on one side or the other that may tell you something about your politics.&amp;nbsp;:-).&lt;br /&gt;&lt;blockquote&gt;C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do it blows your whole leg off.&lt;br /&gt;&lt;blockquote&gt;&amp;mdash; Bjarne Stroustrup (&lt;a href="http://www2.research.att.com/~bs/bs_faq.html#really-say-that"&gt;attributed&lt;/a&gt;)&lt;/blockquote&gt;&lt;/blockquote&gt;The fascist approach to accident prevention is to simply prohibit dangerous behaviors &amp;mdash; which prevents accidents caused by the prohibited behaviors, at the cost of, at least,&amp;nbsp; (a)&amp;nbsp;forcing the programmer to work around the prohibition and&amp;nbsp; (b)&amp;nbsp;prohibiting whatever gainful employment, if any, might otherwise be derived by exploiting the prohibited behavior.&amp;nbsp; (There's a case claimed for the fascist approach based on ability to prove things about programs, but that's a subject for a different post; here I'm considering what may be done deliberately versus what may be done by accident, while that other post would concern what can be done versus what can be proven about it.)&amp;nbsp; Drawbacks to this arrangement accrue from both (a) and (b), as workarounds in (a) are something else to get wrong and, moreover, when the programmer wants to overcome limitations of (b), this tends to involve &lt;i&gt;subverting&lt;/i&gt; the fascist restrictions, rather than working with them, producing an inherently unstable situation (in contrast to the ideal of stability we saw with the significant caster of the safety bicycle).&lt;br /&gt;&lt;br /&gt;The anarchist philosophy makes reliance on this design principle more obvious.&amp;nbsp; You've got more opportunities to do dangerous things, so if there's something in the language design that causes you to do those things when you don't mean to &amp;mdash;or that pushes you to mean to do them routinely, multiplying opportunities to do them wrong&amp;mdash; that's going to be a highly visible problem with the language.&lt;br /&gt;&lt;br /&gt;Most Lisps are pretty anarchic, and certainly my &lt;a href="http://web.cs.wpi.edu/~jshutt/kernel.html"&gt;Kernel&lt;/a&gt; programming language is, supporting &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;fexprs&lt;/a&gt; as it does.&amp;nbsp; Dangerous things are allowed on general principle; and the whole language is, among other things, an exercise in strongly principled language design, so some explicit principle was clearly needed to keep the anarchy sane.&amp;nbsp; &lt;b&gt;Dangerous things should be difficult to do by accident&lt;/b&gt; was crafted for that sanity.&lt;br /&gt;&lt;br /&gt;Which brings me back to something I said I'd post separately (in my &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;earlier post about fexprs&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Hygiene in Kernel&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Kernel is statically scoped, which is key to making fexprs manageable.&lt;br /&gt;&lt;br /&gt;The &lt;i&gt;static environment&lt;/i&gt; of a combiner is the environment of symbol-value bindings in effect at the point (in source code, and in time) where the combiner is defined.&amp;nbsp; The &lt;i&gt;dynamic environment&lt;/i&gt; of a call to a combiner is the environment of symbol-value bindings in effect at the point (in source code and in time) from which the combiner is called.&amp;nbsp; The &lt;i&gt;local environment&lt;/i&gt; of a combiner call is the environment of symbol-value bindings that are used, for that call, to interpret the body of the combiner.&amp;nbsp; The local environment has some call-specific bindings, of the combiner's formal parameters to arguments (or operands) passed to the call; but then, for other symbols, the local environment refers to a parent environment.&amp;nbsp; In a statically scoped combiner, the parent is the static environment; in a dynamically scoped combiner, the parent is the dynamic environment.&lt;br /&gt;&lt;br /&gt;When a programmer writes a symbol into source code, their understanding of what that symbol refers to tends to be based on what else is declared in the same region of source code.&amp;nbsp; For the actual meaning of the symbol to coincide with the programmer's expectation, most programming languages use statically scoped applicatives (&lt;i&gt;applicatives&lt;/i&gt; meaning, as explained in my &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;earlier post&lt;/a&gt;, that the operands are evaluated in the dynamic environment, and the resulting arguments are passed to the underlying combiner).&amp;nbsp; This behavior &amp;mdash;operands interpreted in the dynamic environment, combiner body interpreted in a local child of the static environment&amp;mdash; is commonly called &lt;i&gt;good hygiene&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Early Lisp was dynamically scoped.&amp;nbsp; (How and why that happened, and then for a couple of decades got worse instead of better, are explored in Section&amp;nbsp;3.3 of my &lt;a href="http://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/"&gt;dissertation&lt;/a&gt;.)&amp;nbsp; Under dynamic scope, when one writes a combiner, one doesn't generally know anything about what it will do when called:&amp;nbsp; none of the non-local symbols have any fixed meaning that can be determined when-and-where the combiner is defined.&amp;nbsp; Sometimes one actually wants this sort of dynamic behavior; but good hygiene is the "straight forward" behavior that anarchic Kernel gravitates toward as a stable state.&lt;br /&gt;&lt;br /&gt;So, what does Kernel do to allow hygiene violations while maintaining a steady stabilizing gravity toward good hygiene?&lt;br /&gt;&lt;br /&gt;The primitive constructor of compound operatives, &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt;, is statically scoped; in addition to a formal parameter tree that matches the operands of the call, there is an extra &lt;i&gt;environment parameter&lt;/i&gt;, a symbol that is bound in the local environment to the dynamic environment of the call.&amp;nbsp; That makes it possible to violate hygiene &amp;mdash; although it is actually commonly used to &lt;i&gt;maintain&lt;/i&gt; hygiene, as will be shown.&amp;nbsp; If you don't want to use the dynamic environment, you can use a special Kernel value, &lt;code&gt;#ignore&lt;/code&gt;, in place of the environment parameter to prevent any local binding to the dynamic environment, so it's then impossible to accidentally invoke the dynamic environment.&lt;br /&gt;&lt;br /&gt;The usual constructor for compound applicatives, &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt;, can be defined as follows; it simply transforms a combination&amp;nbsp; &lt;code&gt;(&lt;i&gt;$lambda&lt;/i&gt; &lt;i&gt;formals&lt;/i&gt; . &lt;i&gt;body&lt;/i&gt;)&lt;/code&gt;&amp;nbsp; into&amp;nbsp; &lt;code&gt;(&lt;i&gt;wrap&lt;/i&gt; (&lt;i&gt;$vau&lt;/i&gt; &lt;i&gt;formals&lt;/i&gt; #ignore . &lt;i&gt;body&lt;/i&gt;))&lt;/code&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;($define! $lambda&lt;br /&gt;&amp;nbsp; &amp;nbsp;($vau (formals . body) env&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (wrap (eval (list* $vau formals #ignore body)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; env))))&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;The very existence of &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt; is the first and simplest way Kernel pushes the programmer toward good hygiene:&amp;nbsp; because &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt; is easier to use than &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt; &amp;mdash;and because they can't readily be mistaken for each other&amp;mdash; the programmer will naturally use &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt; for most purposes, turning out hygienic combiners as a matter of course.&amp;nbsp; Constructing an operative takes more work.&amp;nbsp; Constructing an applicative that doesn't ignore its dynamic environment is even more laborious, requiring a composition of &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt; with &lt;code&gt;&lt;i&gt;wrap&lt;/i&gt;&lt;/code&gt;, as in the standard derivation of &lt;code&gt;&lt;i&gt;get-current-environment&lt;/i&gt;&lt;/code&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;($define! get-current-environment&lt;br /&gt;&amp;nbsp; &amp;nbsp;(wrap ($vau () e e)))&lt;/code&gt;&lt;/blockquote&gt;So good hygiene just takes less work than bad hygiene.&lt;br /&gt;&lt;br /&gt;Once the programmer has decided to use &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt;, gravitating toward good hygiene gets subtler.&amp;nbsp; The above derivation of &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt; exemplifies the main tactics.&amp;nbsp; In order to evaluate the operands in any environment at all, you typically use &lt;code&gt;&lt;i&gt;eval&lt;/i&gt;&lt;/code&gt; &amp;mdash; and &lt;code&gt;&lt;i&gt;eval&lt;/i&gt;&lt;/code&gt; requires an explicit second argument specifying the environment in which to do the evaluation.&amp;nbsp; And the most immediately available environment that can be specified is the one for which a local binding has been explicitly provided:&amp;nbsp; the dynamic environment of the call.&lt;br /&gt;&lt;br /&gt;A nuance here is that the expression to be evaluated will typically be cobbled together within the combiner, using some parts of the operand tree together with other elements introduced from elsewhere.&amp;nbsp; This is the case for our derivation of &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt;, where the target expression has four elements &amp;mdash; two parts of the operand tree, &lt;code&gt;&lt;i&gt;formals&lt;/i&gt;&lt;/code&gt; and &lt;code&gt;&lt;i&gt;body&lt;/i&gt;&lt;/code&gt;; literal constant &lt;code&gt;#ignore&lt;/code&gt;; and &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt;.&amp;nbsp; For these cases, a key stabilizing factor is that the construction is conducted using applicative combinations, in which the parts are specified using symbols.&amp;nbsp; Since the constructing combinations are applicative, those symbols are evaluated in the local environment during construction &amp;mdash; so by the time the constructed expression is evaluated, all dependencies on local or static bindings have already been disposed of.&amp;nbsp; The additional elements typically introduced this way are, in fact, combiners (and occasional constants), such as in this case &lt;code&gt;&lt;i&gt;$vau&lt;/i&gt;&lt;/code&gt;; and these elements are atomic, evaluating to themselves, so they behave hygienically when the constructed expression is later evaluated (as I noted in my &lt;a href="http://fexpr.blogspot.com/2011/04/fexpr.html"&gt;earlier post&lt;/a&gt; under the subheading "fluently doing nothing").&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-7709944944660563407?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/7709944944660563407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/05/dangerous-things-should-be-difficult-to.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7709944944660563407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/7709944944660563407'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/05/dangerous-things-should-be-difficult-to.html' title='Dangerous things should be difficult to do&amp;nbsp;&lt;i&gt;by accident&lt;/i&gt;'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-5281845608965594408</id><published>2011-04-06T13:28:00.000-07:00</published><updated>2011-10-03T13:32:47.616-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fexprs'/><category scheme='http://www.blogger.com/atom/ns#' term='lambda calculus'/><category scheme='http://www.blogger.com/atom/ns#' term='Lisp'/><title type='text'>Fexpr</title><content type='html'>&lt;i&gt;Fexpr&lt;/i&gt; is a noun.&amp;nbsp; It's pronounced &lt;i&gt;FEKSper&lt;/i&gt;.&amp;nbsp; A fexpr is a procedure that acts on the syntax of its operands, rather than on the values determined by that syntax.&lt;br /&gt;&lt;br /&gt;This is only in the world of Lisp programming languages — not that only Lisps happen to have fexprs, but that having fexprs (and having the related characteristics that make them a really interesting feature) seemingly &lt;i&gt;causes&lt;/i&gt; a programming language to be, at some deep level, a dialect of Lisp.&amp;nbsp; That's a clue to something:&amp;nbsp; although this acting-on-syntax business sounds superficial, it's a gateway to the deepest nature of the Lisp programming-language model.&amp;nbsp; Fexprs are at the heart of the rhyming scheme of Lisp.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Data as programs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When Lisp reads a syntax (i.e., source code) expression, it immediately represents the expression as a data structure; or at least, in theory it does.&amp;nbsp; For fexprs to even make sense, this would have to be true:&amp;nbsp; a procedure in a program acts on data, so if you're passing the operand syntax expressions to a procedure, those expressions have to be data.&amp;nbsp; The Lisp evaluator then interprets the syntax expression in data form, and that's the whole of Lisp:&amp;nbsp; read an expression and evaluate it, read another and evaluate it, and so on.&lt;br /&gt;&lt;br /&gt;But Lisp was designed, from the start, specifically for manipulating an especially simple and general kind of data structures, essentially &lt;i&gt;trees&lt;/i&gt; (though they can also be viewed as nested lists, hence the name of the language, short for &lt;b&gt;LIS&lt;/b&gt;t &lt;b&gt;P&lt;/b&gt;rocessing).&amp;nbsp; And syntax expressions are represented as these same trees that are already Lisp's native data structure.&amp;nbsp; &lt;i&gt;And&lt;/i&gt;, the Lisp evaluator algorithm isn't limited to data that started life as a representation of syntax:&amp;nbsp; any data value can, in principle, be evaluated.&amp;nbsp; Which means that a fexpr doesn't have to act on syntax.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;The theory of fexprs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;One reason it matters that fexprs can act on non-syntax, is because of a notorious theoretical result about fexprs.&amp;nbsp; Proving programs correct usually makes heavy use of determining whether any two source expressions are interchangeable.&amp;nbsp; When two source expressions may be operands to a fexpr, though, they won't be interchangeable in general unless they're syntactically identical.&amp;nbsp; So with fexprs in the language, no two distinct operands are ever universally interchangeable.&amp;nbsp;  This was famously observed by Mitch Wand in a journal article back in 1998, &lt;a href="http://www.ccs.neu.edu/home/wand/pubs.html#Wand98"&gt;The Theory of Fexprs is Trivial&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;But while a fexpr can analyze any syntactic operand down to the operand's component atoms, computed operands are a different matter.&amp;nbsp; It's almost incidental that some computed data structures are encapsulated, so can't be fully analyzed by fexprs.&amp;nbsp; The more important point is, even if the structure resulting from computation can be fully analyzed, the process by which it was computed is not subject to analysis.&amp;nbsp; If a fexpr is given an operand &lt;code&gt;42&lt;/code&gt;, the fexpr can't tell how that operand was arrived at; it might have been specified in source code, or computed by multiplying &lt;code&gt;6&lt;/code&gt; times &lt;code&gt;7&lt;/code&gt;, or computed in any of infinitely many &lt;a href="https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Answer_to_the_Ultimate_Question_of_Life.2C_the_Universe.2C_and_Everything_.2842.29"&gt;other possible ways&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So, suppose one sets up a computational calculus, something like lambda-calculus, for describing computation in a Lisp with fexprs.&amp;nbsp; Source expressions are terms in the calculus, and no two of them are contextually equivalent (i.e., interchangeable as subterms of all larger terms).&amp;nbsp; But —unless the calculus is constructed pathologically— there are still very many terms in the calculus, representing intermediate states of subcomputations, that are contextually equivalent.&lt;br /&gt;&lt;br /&gt;I've developed a calculus like that, by the way.&amp;nbsp; It's called &lt;i&gt;vau-calculus&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Deep fexprs&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We're about to need much better terminology.&amp;nbsp; The word &lt;i&gt;fexpr&lt;/i&gt; is a legacy from the earliest days of Lisp, and &lt;i&gt;procedure&lt;/i&gt; is used in the Lisp world with several different meanings.&amp;nbsp; Here's more systematic terminology, that I expanded from Scheme for use with the &lt;a href="http://web.cs.wpi.edu/%7Ejshutt/kernel.html"&gt;Kernel programming language&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;A list to be evaluated is a &lt;i&gt;combination&lt;/i&gt;; its first element is the &lt;i&gt;operator&lt;/i&gt;, and the rest of its elements are &lt;i&gt;operands&lt;/i&gt;.&amp;nbsp; The action designated by the operator is a &lt;i&gt;combiner&lt;/i&gt;.&amp;nbsp; A combiner that acts directly on its operands is an &lt;i&gt;operative&lt;/i&gt;.&amp;nbsp; (Legacy terms: an operative that is a data value is a &lt;i&gt;fexpr&lt;/i&gt;, an operative that is not a data value is a &lt;i&gt;special form&lt;/i&gt;.)&amp;nbsp; A combiner that isn't operative is &lt;i&gt;applicative&lt;/i&gt;; in that case, the operands are all evaluated, the results of these evaluations are called &lt;i&gt;arguments&lt;/i&gt;, and the action is performed on the arguments instead of on the operands.&lt;/blockquote&gt;It might seem that applicative combinations would be more common, and far more varied, than operative combinations.&amp;nbsp; Explicitly visible operatives in a Lisp program are largely limited to a small set, used to define symbols (in Kernel, mainly &lt;code&gt;&lt;i&gt;$define!&lt;/i&gt;&lt;/code&gt;&amp;thinsp; and &lt;code&gt;&lt;i&gt;$let&lt;/i&gt;&lt;/code&gt;), construct applicatives (&lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt;), and do logical branching (&lt;code&gt;&lt;i&gt;$if&lt;/i&gt;&lt;/code&gt;&amp;thinsp; and &lt;code&gt;&lt;i&gt;$cond&lt;/i&gt;&lt;/code&gt;) &amp;mdash; about half a dozen operatives, used over and over again.&amp;nbsp; The riotous variety of programmer-defined combiners are almost all applicative.&lt;br /&gt;&lt;br /&gt;But looking closely at the above definition of &lt;i&gt;applicative&lt;/i&gt;, it implies that every applicative has an operative hiding inside it.&amp;nbsp; Once an argument list has been computed, it's just another list of data values — and those values are then acted on directly with no further processing, which is what one does when calling an operative!&amp;nbsp; Applicative &lt;code&gt;&lt;i&gt;+&lt;/i&gt;&lt;/code&gt;, which evaluates its operands to arguments and then adds the arguments, has an underlying operative that just adds its operands; and so on.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Vau-calculus&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In a computational calculus for fexprs, it's a big advantage to represent each applicative explicitly as a wrapper (to indicate the operands are to be evaluated) around another underlying combiner.&amp;nbsp; That way, the calculus can formally reason about argument evaluation separately from reasoning about the underlying actions.&amp;nbsp; Vau-calculus works that way.&amp;nbsp; The whole calculus turns out to have three parts.&amp;nbsp; There's one part that only represents tree/list structures, and no computation takes place purely within that part.&amp;nbsp; There's one part that only deals with computations via fexprs.&amp;nbsp; And then, linking those two, there's the machinery of evaluation, which is where the wrapper-to-induce-operand-evaluation comes in.&lt;br /&gt;&lt;br /&gt;Fascinatingly, of these three parts of vau-calculus, the one that deals only with computations involving fexprs is (give or take) &lt;i&gt;lambda-calculus&lt;/i&gt;.&amp;nbsp; One could reasonably claim —without contradicting Mitch Wand's perfectly valid result, but certainly &lt;i&gt;contrasting&lt;/i&gt; with it— that the theory of fexprs is lambda-calculus.&lt;br /&gt;&lt;br /&gt;(Vau-calculus seems a likely topic for a future blog entry here.&amp;nbsp; Meanwhile, if you're really feeling ambitious, the place to look is &lt;a href="http://www.wpi.edu/Pubs/ETD/Available/etd-090110-124904/"&gt;my dissertation&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Kernel&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What works for a computational calculus also works for a Lisp language:&amp;nbsp; represent each applicative as a wrapper around an underlying combiner.&amp;nbsp; The Kernel programming language does this.&amp;nbsp; An applicative &lt;code&gt;&lt;i&gt;unwrap&lt;/i&gt;&lt;/code&gt;&amp;thinsp; takes an applicative argument and returns the underlying combiner of that argument; and an applicative &lt;code&gt;&lt;i&gt;wrap&lt;/i&gt;&lt;/code&gt;&amp;thinsp; takes any combiner at all as an argument, and returns an applicative whose underlying combiner is that argument.&lt;br /&gt;&lt;br /&gt;This makes Kernel a powerful tool for programmers to fluently manipulate the operand-evaluation process, just as the analogous device in vau-calculus allows reasoning about operand-evaluation separately from reasoning about the underlying lambda-calculus computations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Kernel (evaluator)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Here's the central logic of the Kernel evaluator (coded in Kernel, then put in words).&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;($define! eval&lt;br /&gt;&amp;nbsp; &amp;nbsp;($lambda (expr env)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ($cond ((symbol? expr)&amp;nbsp; (lookup expr env))&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;((pair? expr)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (combine (eval (car expr) env)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(cdr expr)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;env))&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(#t&amp;nbsp; expr))))&lt;br /&gt;&lt;br /&gt;($define! combine&lt;br /&gt;&amp;nbsp; &amp;nbsp;($lambda (combiner operands env)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ($if (operative? combiner)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(operate combiner operands env)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;(combine (unwrap combiner)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (map-eval operands env)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; env))))&lt;/code&gt;&lt;/blockquote&gt;To evaluate an expression in an environment:&amp;nbsp; If it's a symbol, look it up in the environment.&amp;nbsp; If it's a pair (which is the more general case of a list), evaluate the operator in the environment, and &lt;code&gt;&lt;i&gt;combine&lt;/i&gt;&lt;/code&gt;&amp;thinsp; the resulting combiner with the operands in the environment.  &lt;b&gt;If it's neither a symbol nor a pair, it evaluates to itself&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;To combine a combiner with an operands-object:&amp;nbsp; If the combiner is operative, cause it to act on the operands-object (and give it the environment, too, since some operatives need that).&amp;nbsp; If the combiner is applicative, evaluate all the operands in the environment, and &lt;b&gt;recursively call &lt;code&gt;&lt;i&gt;combine&lt;/i&gt;&lt;/code&gt;&lt;/b&gt;&amp;thinsp; with the underlying combiner of the applicative, and the list of arguments.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Kernel (fluently doing nothing)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When evaluating syntax read directly from a source file, the default case of evaluation —the one explained in &lt;b&gt;boldface&lt;/b&gt;— is why a literal constant, such as an integer, evaluates to itself.&amp;nbsp; What makes it worth boldfacing, though, is that when evaluating computed expressions, that case helps keep environments from bleeding into each other (in Lisp terminology, it helps avoid accidental &lt;i&gt;bad hygiene&lt;/i&gt;).&amp;nbsp; Here's a basic example.&lt;br /&gt;&lt;br /&gt;Lisp &lt;code&gt;&lt;i&gt;apply&lt;/i&gt;&lt;/code&gt;&amp;thinsp; overrides the usual rule for calling an applicative, by allowing a single arbitrary computation-result to be used in place of the usual list of arguments.&amp;nbsp; The first argument to &lt;code&gt;&lt;i&gt;apply&lt;/i&gt;&lt;/code&gt;&amp;thinsp; is the applicative, and its second argument is the value to be used instead of a list of arguments.&amp;nbsp; In Kernel, and then in words:&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;($define! apply&lt;br /&gt;&amp;nbsp; &amp;nbsp;($lambda (appv args)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; (eval (cons (unwrap appv) args)&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (make-environment))))&lt;/code&gt;&lt;/blockquote&gt;To apply an applicative to an args-object, construct a combination whose operator is the underlying combiner of the applicative, and whose operands-object is the args-object; and then evaluate the constructed combination in a freshly created empty environment.&amp;nbsp; When the constructed combination is evaluated, its operator evaluates to itself because it's a combiner.&amp;nbsp; This defaulting operator evaluation doesn't need anything from the environment where the arguments to &lt;code&gt;&lt;i&gt;apply&lt;/i&gt;&lt;/code&gt;&amp;thinsp; were evaluated, so the constructed combination can be evaluated in an empty environment &amp;mdash; and the environment of the call to &lt;code&gt;&lt;i&gt;apply&lt;/i&gt;&lt;/code&gt;&amp;thinsp; doesn't bleed into the call to the constructed combination.&lt;br /&gt;&lt;br /&gt;In a standard Kernel environment, &lt;code&gt;(apply&amp;nbsp;list&amp;nbsp;2)&lt;/code&gt; evaluates to &lt;code&gt;2&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;A more impressive illustration is the way &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt;&amp;thinsp; can be defined hygienically in Kernel using more primitive elements of the language.&amp;nbsp; I should make that a separate post, though.&amp;nbsp; The earlier parts of this post deliberately didn't assume Lisp-specific knowledge at all, and in the later parts I've tried to ease into Lisp somewhat gently — but &lt;code&gt;&lt;i&gt;$lambda&lt;/i&gt;&lt;/code&gt;&amp;thinsp; gets into a whole nother level of Lisp sophistication (which is what makes it a worthwhile example), so it just feels logically separate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-5281845608965594408?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/5281845608965594408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/04/fexpr.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/5281845608965594408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/5281845608965594408'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/04/fexpr.html' title='Fexpr'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-8354322251190659854</id><published>2011-03-30T06:48:00.000-07:00</published><updated>2011-03-30T06:48:47.039-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='memetics'/><category scheme='http://www.blogger.com/atom/ns#' term='religion'/><category scheme='http://www.blogger.com/atom/ns#' term='science'/><title type='text'>Memetic organisms</title><content type='html'>When Richard Dawkins coined the word &lt;i&gt;meme&lt;/i&gt; (back in 1976, in &lt;i&gt;The Selfish Gene&lt;/i&gt; — a must read), I suggest he made one understandable mistake, an oversight that, as far as I can tell, has lingered ever since.&amp;nbsp; It might even explain why memetics hasn't become a viable field of scientific research.&lt;br /&gt;&lt;br /&gt;A &lt;i&gt;meme&lt;/i&gt; is roughly an idea that makes copies of itself, which compete with copies of other memes for available resources (basically, human hosts).&amp;nbsp; When a class of things self-copy and compete, they evolve; Dawkins used the general term &lt;i&gt;replicators&lt;/i&gt; for any such things.&amp;nbsp; Genes are replicators, and he used memes as a second example of replicators, showing that the concept has some generality to it.&amp;nbsp; All good so far, but he also wrote that this second kind of replicator was "still in its infancy, still driving clumsily about in its primeval soup".&lt;br /&gt;&lt;br /&gt;Um, no.&amp;nbsp; It's very easy to think that, because the world that memes inhabit —the &lt;i&gt;ideosphere&lt;/i&gt;— isn't directly visible to our senses.&amp;nbsp; Ask yourself, if the memetic equivalent of a tyrannosaurus were (metaphorically) standing right next to you, how would you know?&lt;br /&gt;&lt;br /&gt;Memes are, I suggest, nowhere near the primeval-soup stage.&amp;nbsp; For thousands of years, memetic organisms have roamed the earth, with reproduction (as opposed to replication), death of individual organisms, inactive memes, and something like differentiated organs.&amp;nbsp; You are surrounded, at this moment, by memetic organisms. &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;What's an organism?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Some large groups of memes get copied together; the name &lt;i&gt;memeplex&lt;/i&gt;&amp;nbsp; has been been suggested for such groups.&amp;nbsp; Astrology, say, or algebra.&amp;nbsp; But a biological organism isn't just a set of genes — it is, as Dawkins put it, a vehicle for genes.&amp;nbsp; The replicators have evolved the trick of building these vehicles for themselves.&amp;nbsp; Here are some things to expect of any kind of organisms.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Each organism carries a reasonably stable set of replicators, some of which influence the organism's fitness.&lt;/li&gt;&lt;li&gt;Organisms reproduce.&amp;nbsp; A child is created by a process involving one or more parents, from which the child inherits many (most?) of the replicators it carries.&lt;/li&gt;&lt;li&gt;Organisms die.&amp;nbsp; When they do, some of the replicators they carried may be carried on by their descendants.&lt;/li&gt;&lt;li&gt;Replicators with the potential to induce certain organism traits may be carried by organisms that don't exhibit those traits.&amp;nbsp; (Both recessive genes and junk genes spring to mind.)&lt;/li&gt;&lt;/ul&gt;So, when looking for memetic organisms, we want a class of entities that carry sets of memes; that exhibit reproduction and death, inheriting from their parent(s) and so preserving memes from deceased ancestors; and that carry along some memes across generations in some sort of "inactive" form.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Seeing a memetic organism&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In 1994, there was much fanfare about the twenty fifth anniversary of the first moonwalk.&amp;nbsp; Footage of astronauts on the moon was replayed on television.&amp;nbsp; In one of these clips, an astronaut stood on the moon and did the classic experiment of dropping a light object and a heavy object to see if the heavy object fell faster.&amp;nbsp; (A feather and a wrench, I think they were.)&amp;nbsp; It wasn't well controlled; the point was evidently public education about science, for which it was preceded by a verbal explanation of the experiment — so it taught about scientific method as well as about universal gravitation.&amp;nbsp; Great stuff.&lt;br /&gt;&lt;br /&gt;What left my jaw hanging was that the explanation started with (iirc) "Aristotle said".&amp;nbsp; Nobody was supposed to believe Aristotle's theory about falling objects, but this guy on the moon was deliberately teaching the general public about what they weren't supposed to believe.&amp;nbsp; Inherited memes systematically preserved in a sort of "inactive" form.&lt;br /&gt;&lt;br /&gt;Thomas Kuhn described some aspects of this species of memetic organisms in 1962, in &lt;i&gt;The Structure of Scientific Revolutions&lt;/i&gt; (another must read).&amp;nbsp; Notably, he described its reproductive process, which is what he called a &lt;i&gt;scientific revolution&lt;/i&gt;.&amp;nbsp; Here's a rough portrait of a &lt;i&gt;paradigm scientific field&lt;/i&gt; as a memetic organism.&lt;br /&gt;&lt;br /&gt;The meme set carried by the organism includes a mass of theories, some of which contradict each other.&amp;nbsp; At the center of this mass is a nucleus of theories that are supposed to be believed (part of what Kuhn called a &lt;i&gt;paradigm&lt;/i&gt;).&amp;nbsp; Surrounding the nucleus are theories that are meant to be contrasted with the paradigm and rejected, together with memes about how to conduct the contrast; one might call this surrounding material the &lt;i&gt;co-nucleus&lt;/i&gt;.&amp;nbsp; While the organism thrives, the contrast with the co-nucleus strengthens belief in the nucleus, thus recruiting and retaining members of the organism's scientific community.&amp;nbsp; When the organism falters (the scientific community loses faith in the paradigm), eventually a new paradigm emerges, forming the nucleus of a new organism, while the new co-nucleus may contain both some nuclear and some co-nuclear material from the parent(s).&lt;br /&gt;&lt;br /&gt;During reproduction, fragments may be drawn for the new nucleus (as "inspiration") from pretty much anywhere, even from non-sciences.&amp;nbsp; It seems that a thriving science may deliberately surround itself with a sort of third ring of memes, outside the co-nucleus and perhaps somewhat loosely coupled with the science itself (symbiotic?), that provide raw material for new co-nuclear or nuclear formations.&amp;nbsp; This third ring may include alternative, pseudo-, and fringe science; and science fiction, which can provide a venue for scientists within the community to explore new ideas without the ridicule or ostracism that would result if they prematurely proposed the same ideas in a scientific forum.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Second example&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Religion seems to be a second species (or genus, or some taxon anyway) of memetic organisms.&amp;nbsp; I may do even more poorly here, as I'm practically unread on comparative religion, but I'll take a stab at it anyway; hopefully, it will suffice to make the taxon plausible, even if my specific suggestions don't hold up at all.&lt;br /&gt;&lt;br /&gt;The best fit for an organism seems to be below the scale usually called a &lt;i&gt;sect&lt;/i&gt;, though conceivably somewhat above the scale of a &lt;i&gt;congregation&lt;/i&gt;.&amp;nbsp; Part of the carried memetic material is a large mass I'll call a &lt;i&gt;religious tradition&lt;/i&gt;, which may be written or oral.&amp;nbsp; The tradition is augmented by further memes, which I'll call an &lt;i&gt;interpretation&lt;/i&gt;, determining what different parts of the tradition are supposed to mean.&amp;nbsp; The tradition and interpretation should be able to recruit and retain followers.&amp;nbsp; When changing societal environment makes those memes less effective, it becomes increasingly likely that the community will either splinter, or adjust its carried meme set, creating a new organism with perhaps some deletions or even additions to the tradition, but especially, changes to the interpretation that make it work better in the societal environment.&lt;br /&gt;&lt;br /&gt;What makes for a successful religious organism?&amp;nbsp; A successful scientific organism features highly persuasive contrast between nucleus and co-nucleus, and there is presumably some of that in the religious case too, practices of other religions preserved as persuasive examples of what not to do; likely the scientific species is partly descended from the religious.&amp;nbsp; But there is also an interesting implication from the suggested religious model, that over many generations, a religious tradition will evolve to be amenable to a very wide range of interpretations, as this will allow the tradition to facilitate successful reproduction in a wide variety of societal environments.&amp;nbsp; A successful tradition would therefore be an ambiguous one.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Can memetics become a normal science?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There seem to be two problems with memetic research that have held it back.&lt;br /&gt;&lt;br /&gt;One is that efforts in memetics have been dominated for decades by attempts to define what a meme is.&amp;nbsp; The definition of &lt;i&gt;gene&lt;/i&gt; was arrived at after extensive study of biological organisms; so presumably, one should expect extensive study of memetic organisms to be a prerequisite for arriving at a really good definition of &lt;i&gt;meme&lt;/i&gt;.&amp;nbsp; Identifying the organisms is a start.&lt;br /&gt;&lt;br /&gt;The other has to do with what Kuhn called normal scientific research.&amp;nbsp; This is the sort of research that takes place within a paradigm scientific field (a thriving scientific organism, that is).&amp;nbsp; The paradigm usefully constrains the sorts of questions scientists are to ask and the sorts of answers they are to give (a nuance I didn't even try to capture in my rough portrait of scientific organisms, above).&amp;nbsp; Kuhn describes such research as "puzzle solving", and its narrow focus is its strength, allowing a very great deal of focused work to be done so that, eventually, flaws lurking in the paradigm become impossible to ignore and a reproductive event is triggered &amp;mdash; a scientific revolution, shifting things to another paradigm better describing reality.&lt;br /&gt;&lt;br /&gt;But memetics hasn't provided that sort of structure.&lt;br /&gt;&lt;br /&gt;There seems to be some potential, in the ideas I've proposed here, to define how memetic organisms are to be identified and analyzed, sufficiently that researchers might proceed methodically to find and study organisms.&amp;nbsp; In other words, these suggestions might be developed into a functioning paradigm that could guide normal scientific research.&lt;br /&gt;&lt;br /&gt;Maybe.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-8354322251190659854?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/8354322251190659854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/03/memetic-organisms.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8354322251190659854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/8354322251190659854'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/03/memetic-organisms.html' title='Memetic organisms'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7068528325708136131.post-3282487221573372432</id><published>2011-03-25T15:21:00.000-07:00</published><updated>2011-03-26T09:03:54.160-07:00</updated><title type='text'>Prosaic first post</title><content type='html'>A favorite quote of mine is "History doesn't repeat itself, but it rhymes."&amp;nbsp; Attributed to Mark Twain, though I see &lt;a href="https://secure.wikimedia.org/wikiquote/en/wiki/Main_Page"&gt;Wikiquote&lt;/a&gt; says "Twain scholars agree that it sounds like something he would say, but  they have been unable to find the actual quote in his writing."&amp;nbsp; Quote attributions are like that: them as has, gets.&lt;br /&gt;&lt;br /&gt;The thing is, it doesn't just work for history.&amp;nbsp; It [works] for pretty much everything — if you're familiar enough with it to recognize the rhyming scheme.&amp;nbsp; For example, I've enough smattering of past and present physics to recognize when science fiction has an especially good, or bad, sense of its rhyming scheme.&amp;nbsp; Vernor Vinge's &lt;i&gt;A Fire Upon the Deep&lt;/i&gt; has the most elegantly rhymed fictional physics I've ever encountered; and I've read SFF authors with no ear for physics at all, though I'll not name names.&amp;nbsp; On the non-fiction side of the same effect, I've long sensed that Albert Einstein's dissatisfaction with quantum mechanics was, at its most primordial, dislike of its rhyme (not to in any way disparage his more specific metaphysical writings on the subject).&lt;br /&gt;&lt;br /&gt;So I gradually accumulate evidence, fodder for my intuition, and over years and even decades my intuition slowly learns to recognize rhymes, and starts answering me back with insights — into the rhyming structure of the various subjects of study, hence the blog title.&amp;nbsp; And the insights more or less gather dust, in my files or even just in my head.&amp;nbsp; I'm starting a blog to put those insights out in the open where, with luck, maybe one way or another some will be useful to someone besides me.&amp;nbsp; (If folks find them laughable, well, laughter is good exercise, so that's useful too.)&lt;br /&gt;&lt;br /&gt;What have I been studying, that I can blog about?&amp;nbsp; Well, there's linguistics; both programming languages (within which is my academic  expertise), natural and constructed languages, and connections between  all three.&amp;nbsp; Mathematical physics.&amp;nbsp; A dash of magic.&amp;nbsp; Memetics, with both religion and science as subs under it.&amp;nbsp; Politics and economics.&amp;nbsp; And whatever else I'm forgetting (or haven't thought of yet).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7068528325708136131-3282487221573372432?l=fexpr.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fexpr.blogspot.com/feeds/3282487221573372432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://fexpr.blogspot.com/2011/03/prosaic-first-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/3282487221573372432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7068528325708136131/posts/default/3282487221573372432'/><link rel='alternate' type='text/html' href='http://fexpr.blogspot.com/2011/03/prosaic-first-post.html' title='Prosaic first post'/><author><name>John Shutt</name><uri>http://www.blogger.com/profile/00041398073010099077</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
