<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CUcERHY6eCp7ImA9WhVTGU0.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218</id><updated>2012-03-04T18:16:45.810-05:00</updated><category term="subject reduction" /><category term="standard ml" /><category term="structural operational semantics" /><category term="imperative programming" /><category term="static analysis" /><category term="parallel evaluation" /><category term="predicate abstraction" /><category term="holey data" /><category term="navel-gazing" /><category term="weighted logic programming" /><category term="type inference" /><category term="youtube" /><category term="normalization" /><category term="note to self" /><category term="zippers" /><category term="termination" /><category term="complexity" /><category term="related work" /><category term="preservation" /><category term="Agda" /><category term="dart" /><category term="alms" /><category term="exception handling" /><category term="trees" /><category term="haskell" /><category term="f-pop" /><category term="posters" /><category term="approximation" /><category term="sums" /><category term="hole abstraction" /><category term="papers" /><category term="association of computational machinery" /><category term="language design" /><category term="generic programming" /><category term="difference lists" /><category term="Ada" /><category term="focusing" /><category term="synthetic rules" /><category term="shell scripting" /><category term="law" /><category term="logic" /><category term="patterns" /><category term="tcs stack exchange" /><category term="polarity" /><category term="storytelling" /><category term="politics" /><category term="icfp" /><category term="HLF" /><category term="structural induction" /><category term="author-izer" /><category term="clowns and jokers" /><category term="american association of publishers" /><category term="classical logic" /><category term="one-hole contexts" /><category term="sequent calculus" /><category term="natural deduction" /><category term="links" /><category term="state" /><category term="request for typestate" /><category term="variant record update" /><category term="folds" /><category term="unions" /><category term="linearml" /><category term="publishing" /><category term="total functional programming" /><category term="logic programming" /><category term="c0" /><category term="difference queues" /><category term="typestate" /><category term="off-topic" /><category term="msfp" /><category term="association for computing machinery" /><category term="hacks" /><category term="forward-chaining" /><category term="call-by-push-value" /><category term="functional programming" /><category term="affine types" /><category term="concertrg" /><category term="search" /><category term="modal logic" /><category term="minml" /><category term="subordination" /><category term="judgmental reconstruction" /><category term="Twelf" /><category term="maps" /><category term="constructive provability logic" /><category term="logical frameworks" /><category term="progress" /><category term="linear logic" /><category term="levy" /><category term="binding" /><title>Request for Logic</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://requestforlogic.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/RequestForLogic" /><feedburner:info uri="requestforlogic" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;DUQMRnk_fip7ImA9WhRVE0o.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-2650610403512749701</id><published>2012-01-12T08:46:00.001-05:00</published><updated>2012-01-12T09:09:47.746-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-12T09:09:47.746-05:00</app:edited><title>Structural focalization updated</title><content type="html">&lt;p&gt;I've uploaded to both &lt;a href="http://arxiv.org/abs/1109.6273v2"&gt;ArXiV&lt;/a&gt; and &lt;a href="http://www.cs.cmu.edu/~rjsimmon/drafts/focus.pdf"&gt;my webpage&lt;/a&gt; a significantly revised draft of the paper &lt;i&gt;Structural focalization&lt;/i&gt;, which I've &lt;a href="http://requestforlogic.blogspot.com/2011/09/my-new-focalization-technique-is.html"&gt;spoken about here before&lt;/a&gt;. Feedback is welcome!&lt;/p&gt;

&lt;p&gt;One of the points I make about the structural focalization technique is that, because it is all so nicely structurally inductive, it can be &lt;a href="http://twelf.org/wiki/Focusing"&gt;formalized in Twelf&lt;/a&gt;. As part of a separate project, I've now also repeated the whole structural focalization development in Agda! The code is &lt;a href="https://github.com/robsimmons/agda-lib/tree/focalization"&gt;available from GitHub&lt;/a&gt;. While a structural focalization proof has some more moving parts than a simple cut-and-identity proof, it also has one significant advantage over every Agda proof of cut admissibility that I'm aware of: it requires no extra structural metrics beyond normal structural induction! (My favorite structural metric is the &lt;a href="http://requestforlogic.blogspot.com/2010/11/totally-nameless-representation.html"&gt;totally nameless representation&lt;/a&gt;, but there are other ways of threading that needle, including, presumably, these "sized types" that everyone seems to talk about.)&lt;/p&gt;

&lt;p&gt;In regular, natural-deduction substitution, you can get away without structural metrics by proving the statement that if \(\Gamma \vdash A\) and \(\Gamma, A, \Gamma' \vdash C\) then \(\Gamma, \Gamma' \vdash C\); the extra "slack" given by \(\Gamma'\) means that you operate by structural induction on the second given derivation without ever needing to apply weakening or exchange. Most cut-elimination proofs are structured in such a way that you have to apply left commutative and right commutative cuts on &lt;i&gt;both&lt;/i&gt; of the given derivations, making this process tricky at the best; I've never gotten it to work at all, but you might be able to do something like "if \(\Gamma, \Gamma' \longrightarrow A\) and \(\Gamma, A, \Gamma'' \longrightarrow C\) then \(\Gamma, \Gamma', \Gamma'' \longrightarrow C\)." If someone can make this work let me know!&lt;/p&gt;

&lt;p&gt;A focused sequent calculus, on the other hand, has three separate phases of substitution. The first phase is principal substitution, where the type gets smaller and you can do whatever you want to the derivations, including weakening them. The second phase is rightist substitution, which acts much like natural-deduction substitution, and where you can similarly get away with adding "slack" to the second derivation. The third phase is leftist substitution, and you can get by in this phase by adding "slack" to the first derivation: the leftist cases read something like "if \(\Gamma, \Gamma' \longrightarrow A\) and \(\Gamma, A \longrightarrow C\) then \(\Gamma, \Gamma' \longrightarrow C\)."&lt;/p&gt;

&lt;p&gt;In &lt;i&gt;Structural focalization&lt;/i&gt;, I note that the structural focalization technique could be seen as a really freaking complicated way of proving the cut and identity for an unfocused sequent calculus. But in Agda, there's a reason you might actually want to do things the "long way" - not only do you have something better when you finish (a focalization result), but you get cut and identity without needing an annoying structural metric.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-2650610403512749701?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/mOvBmmaXfc4" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/2650610403512749701/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2012/01/structural-focalization-updated.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2650610403512749701?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2650610403512749701?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/mOvBmmaXfc4/structural-focalization-updated.html" title="Structural focalization updated" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2012/01/structural-focalization-updated.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQHRnozfCp7ImA9WhRWGEU.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-2466149283293609221</id><published>2012-01-06T13:27:00.000-05:00</published><updated>2012-01-06T16:12:17.484-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-06T16:12:17.484-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="author-izer" /><category scheme="http://www.blogger.com/atom/ns#" term="association of computational machinery" /><category scheme="http://www.blogger.com/atom/ns#" term="law" /><category scheme="http://www.blogger.com/atom/ns#" term="american association of publishers" /><category scheme="http://www.blogger.com/atom/ns#" term="publishing" /><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><title>Response from ACM's Scott Delman</title><content type="html">&lt;p&gt;In the comments to my last post (&lt;a href="http://requestforlogic.blogspot.com/2012/01/why-does-acm-act-against-interests-of.html"&gt;"Why does the ACM act against the interests of scholars?"&lt;/a&gt;) ACM's Director of Group Publishing, Scott Delman, left a multiple-comment response. It's a response both to the views I expressed and to the views of others that I summarized. He agreed to have his comments posted as a post here; I'll leave my own thoughts for a separate post or the comments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ok, here's the other side of this, which I feel compelled to throw out there after reading Rob's post and a few of the related comments.&lt;/p&gt;

&lt;p&gt;Like most things in life, things are not always as black and white as some would lead us to believe. In this case, I think there is a basic misunderstanding of the ACM and the AAP (which is incidentally an organization that does a great deal of good work on behalf of both publishers and the scientific community).&lt;/p&gt;

&lt;p&gt;Let's start with the ACM....which is a non-profit organization founded in 1947 by members of the computing community with the primary mission of advancing the field of computing. The Association is organized as a 501(c)3 corporation with daily operations run by a small staff of approximately 75 individuals who ultimately take their direction from a volunteer leadership of hundreds of dedicated scientists, scholars, educators, practitioners, and students who graciously donate a significant amount of their time to direct the Association forward in a way that benefits the computing community as a whole. It is important to point this out, because there is an implication in the original post that the ACM is an entity that is in some way acting against the scholarly community, when in fact the ACM is an organization that is literally run by the scholarly community. &lt;/p&gt;

&lt;p&gt;Keeping this in mind, we are either left with a situation in which the scholarly community is either acting against itself by the policies it sets and supports (such as ACM's copyright policy and ACM's subscription model) or something else is going on here. Since it doesn't seem logical or even practical that the top-decision makers at ACM (such as the ACM Publications Board of Volunteers or the ACM Executive Committee of Volunteers, who oversee all major strategic decisions of the Association) would support policies that actively work against the interests of their own community, I think it is more reasonable to suggest that what is going on here is that the issues are not as cut and dry or as simplified as some advocates of "immediate and unrestricted" open access to all scholarly literature would lead us to believe.&lt;/p&gt;

&lt;p&gt;Whenever I discuss the topic of open access with colleagues and friends, I think it is useful to try to imagine what the world would look like if the US Federal Government or other Foreign Governments decided to pass legislation that required all scholarly material that is in some way supported by public funding be made instantly open and freely available to the world without any paywalls of any sort. Well, as ACM's publisher and someone who is intimately aware of the tangible costs of publishing and disseminating high quality scholarly literature, I can tell you without a shadow of a doubt that the end result of this sort of legislation would be catastrophic for the scientific community and scholarly publishers alike. If in a blink of an eye, organizations like ACM were required to simply open up our archive of articles (the ACM DL) without the ability to recoup the costs of publishing and disseminating those articles (or all of the technically sophisticated services built around that content inside the ACM DL), ACM would cease to be the sustainable organization it is today and would eventually shutter its doors at some point in the future, instead of continuing to be the sustainable force for good that it is today. If this sounds like PR-dribble, I apologize, but I really do believe this!&lt;/p&gt;

&lt;p&gt;What's more, the senior volunteers who are most familiar with ACM's activities and who sit on ACM's various committees and boards recognize and understand the tradeoffs that are necessary to maintain a sustainable organization. Over the past few years, I have participated in meetings with our Publications Board, which is the governing body for publications related strategy and decisions at ACM, where the issues of open access and alternative business models have been repeatedly discussed, and when all of the facts have been taken into consideration it has been overwhelmingly clear to these members of the community that ACM's approach is in the best longterm interests of the scholarly community. In fact, the ACM Author-Izer service, which is written about in the above post, was conceptualized at one of these meetings as the result of an in-depth discussion about how to balance the legitimate need of our authors to make the "archival versions" of their articles openly available while at the same time preserving the revenue stream that ACM relies heavily on to do its good work. ACM's pre-existing copyright policy already addressed the issue of posting "accepted versions" of an author's work, but ACM's volunteers decided that it was even more beneficial for the community if the "archival versions" could be made available from the author's site using the "Author-Izer" perpetual link. In general, while Author-Izer is still relatively new, the initial responses have been extremely positive and there is widespread recognition (including Rob's above) that this is a step in the right direction....&lt;/p&gt;

&lt;p&gt;Let me briefly address the "opposing views" raised in Rob's post. First, in an instance where an author graduates, moves, or retires, it is always possible for the initial link to be replaced by a more up-to-date link. The ability to manage the URL that hosts the link is in the hands of the author, so I don't see a significant issue here and at the very least the effort on behalf of the author is no greater (and perhaps significantly less) than it would be to move their vitae or "pre-published" articles to a new website. What's more, ACM has simplified this process for authors and eliminated the confusion that is caused by having "multiple versions" of articles available on multiple websites by creating a centralized place (their ACM Author's Page, which includes all of their ACM and non-ACM publications) from which authors can update their Author-Izer links. By hosting the archival version of the article on a single and "sustainable" site, we strongly believe this is a better solution for the community.&lt;/p&gt;

&lt;p&gt;In relation to argument from Russell O'Connor, I reject the plausibility or even the possibility that the ACM might "go evil" for the reasons I've outlined above. Since ACM ultimately carries out the well thought out wishes of the community itself since the decision makers are the very members of the community who are impacted by those decisions, it is just not possible for such a scenario to occur. Bankrupt is another story, since it is always impossible to predict how an organization's finances will be managed in the future, even though for the record it is exactly the kind of decision making I've mentioned above that currently keeps the ACM is a very strong position. Nevertheless, contingencies are in place for this unlikely scenario, as it relates to ACM's publications and all articles in the ACM Digital Library. Several years ago, ACM established partnerships with two very well established organizations (CLOCKSS &amp; Portico) to ensure that ACM's publications would be preserved and made available to the scientific community (at no cost) in the unlikely event that ACM ceased to exist. &lt;i&gt;[Rob's note: &lt;a href="http://librarians.acm.org/acm-announces-initiative-long-term-preservation-content-its-digital-library-computing-resources"&gt;here's a press release about that&lt;/a&gt;.]&lt;/i&gt; Both organizations take different approaches to longterm digital preservation, but both are non-profits that exist for the sole purpose of maintaining a longterm perpetual archive for the scholarly community and nearly all major scientific publishers participate in one or both of these initiatives. ACM participates in both to provide an even higher level of redundancy than most other publishers. So, it is not clear what would happen to Author-Izer in the event of this doom-day scenario, but what is for certain is that ACM's archive would be made available to the scholarly community in any event.&lt;/p&gt;

&lt;p&gt;Lastly, it is worth noting that the AAP is one of the publishing industries' primary advocates and they do an enormous amount of good work. Rather than deriding this organization that supports and protects the interests of over 300 well established publishers, including ACM, I would suggest that we focus on the spirit of what the Research Works Act represents, which is to limit the ability of the federal government to mandate decisions that would almost certainly have a longterm catastrophic impact on an industry that partners with and supports (and in our case is one and the same) the scientific community.&lt;/p&gt;

&lt;p&gt;Respectfully,&lt;/p&gt;

&lt;p&gt;Scott Delman&lt;br/&gt;
Director of Group Publishing&lt;br/&gt;
Assoc. Computing Machinery&lt;/p&gt;
&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-2466149283293609221?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/uuIk1ehuNXw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/2466149283293609221/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2012/01/response-from-acms-scott-delman.html#comment-form" title="16 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2466149283293609221?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2466149283293609221?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/uuIk1ehuNXw/response-from-acms-scott-delman.html" title="Response from ACM's Scott Delman" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>16</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2012/01/response-from-acms-scott-delman.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4CSX09eCp7ImA9WhRWGUo.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-4369666245410172409</id><published>2012-01-05T13:08:00.000-05:00</published><updated>2012-01-07T17:56:08.360-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-07T17:56:08.360-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="author-izer" /><category scheme="http://www.blogger.com/atom/ns#" term="law" /><category scheme="http://www.blogger.com/atom/ns#" term="association for computing machinery" /><category scheme="http://www.blogger.com/atom/ns#" term="american association of publishers" /><category scheme="http://www.blogger.com/atom/ns#" term="publishing" /><category scheme="http://www.blogger.com/atom/ns#" term="politics" /><title>Why does the ACM act against the interests of scholars?</title><content type="html">&lt;p&gt;&lt;b&gt;[Updated Jan 6, Jan 7]&lt;/b&gt; Some stuff has been happening! I'm delighted by two developments. First, ACM's Director of Group Publishing, Scott Delman, wrote a series of comments that is now one big post: &lt;a href="http://requestforlogic.blogspot.com/2012/01/response-from-acms-scott-delman.html"&gt;Response from ACM's Scott Delman&lt;/a&gt;. Second, I've observed that many other people came to the same conclusion I did - that it's time for our professional organizations to leave the Association of American Publishers. The reason I brought up ACM Author-izer was to argue that Author-izer makes sense only insofar as the CS community trusts their professional organization; I remain of the view that membership in the AAP is &lt;i&gt;incompatible with this trust&lt;/i&gt;. Here's &lt;a href="http://cameronneylon.net/blog/update-on-publishers-and-sopa-time-for-scholarly-publishers-to-disavow-the-aap/"&gt;Cameron Neylon saying that a bit more forcefully&lt;/a&gt;, and &lt;a href="http://scienceblogs.com/confessions/2012/01/scholarly_societies_its_time_t.php"&gt;here's John Dupuis&lt;/a&gt;, who is also compiling a list of &lt;a href="http://scienceblogs.com/confessions/2012/01/around_the_web_some_posts_on_t_1.php"&gt;all the things related to RWA&lt;/a&gt;. (Did I mention the &lt;a href="http://judiciary.house.gov/issues/Rogue%20Websites/List%20of%20SOPA%20Supporters.pdf"&gt;AAP also supports SOPA&lt;/a&gt;? Yep, &lt;i&gt;awesome.&lt;/i&gt;)&lt;/p&gt;

&lt;hr/&gt;

&lt;p&gt;&lt;i&gt;I've got two logic posts queued up in the To Do list. But, dear the internet, we need to talk about the ACM. TL;DR is bold and italics at the bottom.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;My friend Glenn Willen tweeted something about the &lt;a href="http://www.publishers.org/press/56/"&gt;Research Works Act&lt;/a&gt; last night. [Update: you can read the very short bill &lt;a href="http://thomas.loc.gov/cgi-bin/query/z?c112:H.R.3699:"&gt;here&lt;/a&gt;] Basically, it would (among other things) require that the government can't demand that publishers of federally-funded research make their research available to the public. You should really read the press release; it just a wonderful example of the "dripping in PR" genre of literature.&lt;/p&gt;

&lt;p&gt;This is not shocking. Awful legislation gets introduced all the time with names ("Research Works Act") that do the opposite of what their title suggests (preventing research from working and acting, wildly attempting to maintain an ultimately unsustainable status quo). Frankly, I expect publishers to behave this way, and I expect there to be the usual variety of opinions about it. But then I ran through the members of the Association of American Publishers, the group which is cheering this legislation that the (presumably) they wrote, hoping against hope. I was unsurprised but a bit sickened by what I saw: the Association for Computing Machinery is a &lt;a href="http://publishers.org/members/"&gt;member of the AAP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I like the ACM, I am proud of my membership in the ACM and ACM SIGPLAN, the &lt;b&gt;S&lt;/b&gt;pecial &lt;b&gt;I&lt;/b&gt;nterest &lt;b&gt;G&lt;/b&gt;roup on &lt;b&gt;P&lt;/b&gt;rogramming &lt;b&gt;Lan&lt;/b&gt;guages. I personally think that the ACM's republication policies have been pretty reasonable during the time I've inhabited this academic world. I'm also proud of my involvement with ACM through their &lt;a href="http://xrds.acm.org/"&gt;student magazine, XRDS&lt;/a&gt;. I write profiles of fascinating people, all of which are available &lt;a href="http://www.cs.cmu.edu/~rjsimmon/xrds.html"&gt;on my personal webpage&lt;/a&gt;, for free, through the ACM Author-izer service. &lt;/p&gt;

&lt;h3&gt;Let's talk about that Author-izer&lt;/h3&gt;

&lt;p&gt;When I publish anything through the ACM, they own the copyright. This is totally fine-by-me for things I write for XRDS (when I worked for the &lt;a href="http://www.dailyprincetonian.com/"&gt;Daily Princetonian&lt;/a&gt; in college they owned copyright on my work for them as well). In my mind, it's a little more complicated when I publish stuff I wrote in an ACM conference proceedings. I want to make sure people have access to that research-ey material - my reputation and career opportunities depend on people finding, reading, and liking my work, but in ACM's Digital Library it's behind a "paywall," accessible only to ACM members and people on university networks. The ACM (unlike IEEE) provides a couple of different-sized hoops that you can jump through to provide free access to your work from your personal home page; Author-izer is the newest of these.&lt;/p&gt;

&lt;p&gt;On a technical level, ACM Author-izer lets you, the author of a work that the ACM now has copyright to, bless a particular URL on the internet (presumably your personal home page). The ACM then gives you a special link to their Digital Library - if you're coming from the blessed URL to the special link, you get access to the research. It sounds a little goofy but it works for me in practice and I'm cautiously pleased with it. (Here's &lt;a href="https://freedom-to-tinker.com/blog/appel/acm-opens-another-hole-paywall"&gt;Andrew Appel talking about Author-izer&lt;/a&gt; if you'd like a concurring opinion.)&lt;/p&gt;

&lt;p&gt;But there's &lt;a href="http://www.researchwithoutwalls.org/About.aspx"&gt;another view&lt;/a&gt; that Author-izer is a step backwards - because moving a web page (upon graduation or retirement) breaks the functionality of Author-izer links, ACM gets, in the long run, more exclusive content than if people were posting semi-definitive versions of papers on their web page. This is not a crazy concern, but I feel like lots of universities archive alumni's pages in-place, so I also don't feel too worried about it.&lt;/p&gt;

&lt;p&gt;There's another argument I've read (UPDATE: &lt;a href="http://r6.ca/blog/20110930T012533Z.html"&gt;from Russell O’Connor&lt;/a&gt;, I'd forgotten the link but Joshua Dunfeld reminded me in the comments). It's plausible, more insidious, and more long-term. The ACM might "go evil" in some way, sure, but even positing that the ACM is and will remain reasonably virtuous, what if the ACM goes bankrupt? In the bankruptcy proceedings, some copyright trolls get the rights to everything in the digital library, immediately shut down Author-izer, and start wreaking havoc on academia (threatening lawsuits and demanding money who posted ACM-published works to their webpage) because they're copyright trolls and that's how they roll. A lot of people are violating the letter of their agreements when they post work to their web pages - you're not allowed to post the ACM's PDF, and in fact my reading of the agreement is that you have to change the ACM copyright notice in your version of the paper to a specific other thing; most people don't do this. Of course the ACM-provided LaTeX class doesn't support this, so you have to go diddling around with .cls flies to produce a PDF that looks like &lt;a href="http://www.cs.cmu.edu/~rjsimmon/papers/simmons09linlogapx.pdf"&gt;this&lt;/a&gt; - see the lower-left-hand corner of the first page. Because people are less likely to jump (correctly) through the "author's version" hoop, instead relying on Author-izer, in this hypothetical narrative the ACM's policies have, indeed, worked against the interests of ACM's members.&lt;/p&gt;

&lt;h3&gt;What does this have to do with the "Research Works Act" breaking research?&lt;/h3&gt;

&lt;p&gt;My view of Author-izer is that it requires a high level of trust: trust that the ACM will continue supporting authors, and that we'll be able to continue supporting the ACM (since if we don't or can't support the ACM, it will go bankrupt and be taken over by copyright trolls). I can overlook little things where the ACM is not acting in the interest of its members (why doesn't the standard .cls make it easy to make an authors version?) because the world isn't perfect.&lt;/p&gt; 

&lt;p&gt;Furthermore, with experiments like Author-izer, I believe that ACM has demonstrated that it's trying to do the right thing, as opposed to IEEE, which doesn't give authors hoops to jump through to legally post their work to their webpages. (You should read IEEE's hilariously awful responses to &lt;a href="http://www.crypto.com/blog/copywrongs/"&gt;Matt Blaze&lt;/a&gt; on this issue. Blaze, I should add, sees much less difference between ACM and IEEE than I do.)&lt;/p&gt;

&lt;p&gt;However, the "Research Works Act" makes it clear that ACM's membership in the Association of American Publishers is an &lt;i&gt;egregious and unacceptable&lt;/i&gt; instance of working against the interest of scholars and ACM members. &lt;b&gt;&lt;i&gt;We should be thinking about how to demand that our professional organization, the Association for Computing Machinery, do two things: 1) withdraw from the Association of American Publishers 2) take the clear position that the so-called "Research Works Act" is an unacceptable piece of legislation that is not supported by the computer science community.&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;We should do this even though (I suspect) the primary target of this ridiculous act is medical science. (At the present time, the NIH admirably puts a higher priority on open dissemination of research than the NSF.)&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;&lt;i&gt;P.S. added January 7: The title of this post is intentionally re-asking the question Blaze asks in his aforementioned post, "Why do IEEE and ACM act against the interests of scholars?" I am focusing on the ACM simply because I care more about the ACM. The IEEE is also a member organization of the AAP.&lt;/i&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-4369666245410172409?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/Lws-7F32mPM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/4369666245410172409/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2012/01/why-does-acm-act-against-interests-of.html#comment-form" title="12 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4369666245410172409?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4369666245410172409?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/Lws-7F32mPM/why-does-acm-act-against-interests-of.html" title="Why does the ACM act against the interests of scholars?" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>12</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2012/01/why-does-acm-act-against-interests-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MBSHoyeCp7ImA9WhRXE00.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-3284389650562688481</id><published>2011-12-17T20:14:00.000-05:00</published><updated>2011-12-19T08:30:59.490-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-19T08:30:59.490-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="focusing" /><category scheme="http://www.blogger.com/atom/ns#" term="classical logic" /><category scheme="http://www.blogger.com/atom/ns#" term="note to self" /><category scheme="http://www.blogger.com/atom/ns#" term="polarity" /><title>Notes on classical sequent calculi (1/2)</title><content type="html">&lt;p&gt;These are some notes I made to try to help me understand Noam's focused presentation of classical logic in &lt;a href="http://www.pps.jussieu.fr/~noam/papers/polpol.pdf"&gt;Polarity and the Logic of Delimited Continuations&lt;/a&gt;. I hope these notes coud be useful to others.&lt;/p&gt;

&lt;h2&gt;Sequent presentations of classical logic&lt;/h2&gt;

&lt;p&gt;I write, inevitably, from the perspective of an intuitionistic proof theorist, so let's start there. In intuitionistic logics, sequents have the form \(\Gamma \vdash A~\mathit{true}\), where the hypothetical context \(\Gamma\) has the form \(A_1~\mathit{true}, \ldots, A_n~\mathit{true}\). The whole sequent \(\Gamma \vdash A~\mathit{true}\) is read as "assuming the truth of all the things in \(\Gamma\), we know \(A~\mathit{true}\)." Let's look at a couple of ways of presenting sequent calculi for &lt;i&gt;classical&lt;/i&gt; logic.&lt;/p&gt;

&lt;h3&gt;Two-sided judgmental classical sequent calculi&lt;/h3&gt;

&lt;p&gt;One way of presenting a classical sequent calculus is to give a two-sided sequent, \(\Gamma \vdash \Delta\). As before, \(\Gamma\) has the form \(A_1~\mathit{true}, \ldots, A_n~\mathit{true}\), but \(\Delta\) has the form \(B_1~\mathit{false}, \ldots, A_m~\mathit{false}\), and the whole sequent is read as "taken together, if all the things judged true in \(\Gamma\) are true and all the things judged false in \(\Delta\) are false, then there is a contradiction."&lt;/p&gt;

&lt;p&gt;The language of propositions is \(A ::= P \mid \neg A \mid A \wedge B \mid A \vee B\) - uninterpreted atomic propositions \(P\), negation, conjunction ("and"), and disjunction ("or"). I'm leaving out truth \(\top\) and falsehood \(\bot\) because they're boring. The rules for these two-sided classical sequent calculi look like this:&lt;/p&gt;

\[
\infer
{\Gamma, ~ P~\mathit{true} \vdash \Delta, ~ P~\mathit{false}}
{}
\]

\[
\infer
{\Gamma \vdash \Delta, ~ \neg A~\mathit{false}}
{\Gamma, ~ A~\mathit{true} \vdash \Delta}
\qquad
\infer
{\Gamma, ~ \neg A~\mathit{true} \vdash \Delta}
{\Gamma \vdash \Delta, ~ A~\mathit{false}}
\]

\[
\infer
{\Gamma \vdash \Delta, ~ A \wedge B~\mathit{false}}
{\Gamma \vdash \Delta, ~ A~\mathit{false} 
&amp;\Gamma \vdash \Delta, ~ B~\mathit{false}}
\qquad
\infer
{\Gamma, ~ A \wedge B~\mathit{true} \vdash \Delta}
{\Gamma, ~ A~\mathit{true}, ~ B~\mathit{true} \vdash \Delta}
\]

\[
\infer
{\Gamma \vdash \Delta, ~ A \vee B~\mathit{false}}
{\Gamma \vdash \Delta, ~ A~\mathit{false}, ~ B~\mathit{false}}
\qquad
\infer
{\Gamma, ~ A \vee B~\mathit{true} \vdash \Delta}
{\Gamma, ~ A~\mathit{true} \vdash \Delta
&amp;\Gamma, ~ B~\mathit{true} \vdash \Delta}
\]

&lt;p&gt;Two asides. First, in presentations that do not emphasize the fact that \(A_i~\mathit{false}\) and \(B_j~\mathit{true}\) are &lt;i&gt;judgments&lt;/i&gt; and not propositions, there is another reading of the two-sided sequent \[A_1,\ldots,A_n \vdash B_1,\ldots,B_m\] This interpretation is that the truth of &lt;i&gt;all&lt;/i&gt; of the \(A_i\) implies the truth of &lt;i&gt;one&lt;/i&gt; of the \(B_j\) - this reading suggests a reading of any intuitionistic sequent proof as a classical sequent proof with one conclusion. You should convince yourself that this interpretation is equivalent to the interpretation above (hint: it's just a mode of use of De Morgan's laws).&lt;/p&gt;

&lt;p&gt;Second aside: your rules may differ. I'm using a style of presentation where every connective is broken down by a unique connective and, from the perspective of bottom-up proof search, it's never a mistake to apply any rule, because the conclusion implies all of the premises (a property called &lt;i&gt;invertibility&lt;/i&gt;). The "true" (or left) rule for conjunction (that is, "and" or \(\wedge\)) and the "false" (or right) rule for disjunction (that is, "or" or \(\vee\)) both have a different, non-invertible presentation. In the case of conjunction, it's this pair of rules:

\[
\infer
{\Gamma, ~ A \wedge B~\mathit{true} \vdash \Delta}
{\Gamma, ~ A~\mathit{true} \vdash \Delta}
\qquad
\infer
{\Gamma, ~ A \wedge B~\mathit{true} \vdash \Delta}
{\Gamma, ~ B~\mathit{true} \vdash \Delta}
\]

You could "make a mistake" applying these rules in bottom-up proof search:
just because there is a proof of
\(\Gamma, ~ A \wedge B~\mathit{true} \vdash \Delta\) does not mean that there is a proof
of \(\Gamma, ~ A~\mathit{true} \vdash \Delta\).
&lt;/p&gt;

&lt;h3&gt;One-sided judgmental sequent sequent calculi&lt;/h3&gt;

&lt;p&gt;Of course, hypotheses are just hypotheses, there's no a priori reason why we need to separate the true ones and the false ones into separate contexts. Let's use a unified context and call it \(\Psi\).

\[\Psi ::= \cdot \mid \Psi, A~\mathit{true} \mid \Psi, A~\mathit{false}\]

Then, we can have the sequent form \(\Psi \vdash \#\), which we read as "all the assumptions in \(\Psi\) together imply a contradiction" - we pronounce \(\#\) as "contradiction." We'll need rewrite all of our rules:&lt;/p&gt;

\[
\infer
{\Psi, ~ P~\mathit{true}, ~ P~\mathit{false} \vdash \#}
{}
\]

\[
\infer
{\Psi, ~ \neg A~\mathit{false} \vdash \#}
{\Psi, ~ A~\mathit{true} \vdash \#}
\qquad
\infer
{\Psi, ~ \neg A~\mathit{true} \vdash \#}
{\Psi, ~ A~\mathit{false} \vdash \#}
\]

\[
\infer
{\Psi, ~ A \wedge B~\mathit{false} \vdash \#}
{\Psi, ~ A~\mathit{false} \vdash \#  
&amp;\Psi, ~ B~\mathit{false} \vdash \#}
\qquad
\infer
{\Psi, ~ A \wedge B~\mathit{true} \vdash \#}
{\Psi, ~ A~\mathit{true}, ~ B~\mathit{true} \vdash \#}
\]

\[
\infer
{\Psi, ~ A \vee B~\mathit{false} \vdash \#}
{\Psi, ~ A~\mathit{false}, ~ B~\mathit{false} \vdash \#}
\qquad
\infer
{\Psi, ~ A \vee B~\mathit{true} \vdash \#}
{\Psi, ~ A~\mathit{true} \vdash \#
&amp;\Psi, ~ B~\mathit{true} \vdash \#}
\]

&lt;p&gt;Hopefully you'll agree that this is "obviously the same" as the first presentation.&lt;/p&gt;

&lt;h3&gt;One-sided, truth-oriented sequent calculi&lt;/h3&gt;

&lt;p&gt;But wait! The "false" rule for conjunction looks just like the "true" rule for disjunction, and the "true" rule for conjunction looks just like the "false" rules for disjunction. Can we simplify these rules?&lt;/p&gt;

&lt;p&gt;The usual answer is that you can, indeed, do with fewer rules and without a false judgment  at all. However, we need two twists to deal with the rules that involved both the true and false judgments. First, we need to let every atomic proposition come in two flavors, the "regular" flavor \(P\) and the "negated" flavor \(\overline{P}\). Then, the rule dealing with atomic propositions looks like this:

\[
\infer
{\Gamma, ~ P~\mathit{true}, ~ \overline{P}~\mathit{true} \vdash \#}
{}
\]

Second, instead of negation being a &lt;i&gt;proposition&lt;/i&gt; \(\neg A\), we define a negation &lt;i&gt;function&lt;/i&gt;, which I will write as \((A)^\bot\) to distinguish it from the propositional negation \(\neg A\). W. The negation function is defined as follows:

\[
\begin{align}
{(P)^\bot} = &amp; \overline{P}\\
{(\overline{P})^\bot} = &amp; P\\
{(A \wedge B)^\bot} = &amp; {(A)^\bot} \vee {(B)^\bot}\\
{(A \vee B)^\bot} = &amp; {(A)^\bot} \wedge {(B)^\bot}\\
\end{align}
\]

With this definition, we can eliminate the negation proposition altogether - the negation function just applies De Morgan laws all the way down to atomic propositions. We now get our sequent calculus for "half off" - there's no more official negation, and we don't need the false judgment at all anymore. We only need two more rules (for a total of three)!&lt;/p&gt;

\[
\infer
{\Psi, ~ A \wedge B~\mathit{true} \vdash \#}
{\Psi, ~ A~\mathit{true}, ~ B~\mathit{true} \vdash \#}
\qquad
\infer
{\Psi, ~ A \vee B~\mathit{true} \vdash \#}
{\Psi, ~ A~\mathit{true} \vdash \#
&amp;\Psi, ~ B~\mathit{true} \vdash \#}
\]

&lt;p&gt;It would also be possible to play this game the other way around: gather everything on the right-hand side, bias the whole thing towards the "false" judgment, and basically
get the "other half" of the two-sided sequent calculi. This ability to play the game equally well either way is part of what people mean when they say that classical logic is "very symmetric."&lt;/p&gt;

&lt;p&gt;However, given that it's all the same, why not reason about truth and not falsehood? I've never understand why classical linear logic (in particular) always seems to bias itself towards one-sided sequent calculi on the &lt;i&gt;right&lt;/i&gt;. There are important differences in what it means to think like a classical linear logician and what it means to think like an intuitionistic linear logician, but I really think that it unnecessarily exacerbates this divide when we have to turn all of our \(\oplus\)es to \(\&amp;\)s and \(\otimes\)es to pars in order to talk to one another.&lt;/p&gt;

&lt;h2&gt;Polarized presentations of classical logic&lt;/h2&gt;

&lt;p&gt;Now for the real purpose of this note: writing out the review of classical logic that Noam gives in "Polarity and the Logic of Delimited Continuations." This discussion is a synthesis of that presentation and a little bit of "On the unity of duality."&lt;/p&gt;

&lt;h3&gt;Two for the price of two&lt;/h3&gt;

&lt;p&gt;Fundamentally, the observation Noam is making is that the one-sided truth-oriented sequent calculus goes &lt;i&gt;too far&lt;/i&gt; - really, there are two kinds of disjunction, and two kinds of conjunction, which is why it seemed like the original calculus seemed to have redundancies. The third system above (the one-sided, truth-oriented sequent calculus) made it look like we were getting our logic for "half-off" - but really that's because the first two judgmental presentations were defining &lt;i&gt;twice as many connectives&lt;/i&gt; as appeared to the naked eye. (As an aside, if you study classical linear logic, you're forced into the same conclusion for different reasons.)&lt;/p&gt;

&lt;p&gt;Jason Reed taught me that, if you have two different judgments in a logic, it's worth seeing what happens if you &lt;i&gt;syntactically differentiate&lt;/i&gt; the things you judge to be true and the things you judge to be false. Let's go ahead and "guess the right answer" - I'm going to call the things we judge to be true &lt;i&gt;positive&lt;/i&gt;, and that the things we judge to be false &lt;i&gt;negative&lt;/i&gt;. &lt;a href="http://en.wikipedia.org/wiki/Fringe_(TV_series)"&gt;There's more than one of everything!&lt;/a&gt;

\[
\begin{align}
A^- = &amp; \neg^- A^+ \mid P^- \mid A^- \wedge^- B^- \mid A^- \vee^- B^-\\
A^+ = &amp; \neg^+ A^- \mid P^+ \mid A^+ \wedge^+ B^+ \mid A^+ \vee^+ B^+
\end{align}
\]

Here are a bunch of rules: note that the fact that the two negations change the polarity of the propositions; the rules make it evident that this is the right thing to do, because we have (for example) \(\neg^+ A^- ~\mathit{true}\) but \(A^- ~\mathit{false}\):&lt;/p&gt;

\[
\infer
{\Psi, ~ \neg^- A^+~\mathit{false} \vdash \#}
{\Psi, ~ A^+~\mathit{true} \vdash \#}
\qquad
\infer
{\Psi, ~ \neg^+ A^-~\mathit{true} \vdash \#}
{\Psi, ~ A^-~\mathit{false} \vdash \#}
\]

\[
\infer
{\Psi, ~ A^- \wedge^- B^-~\mathit{false} \vdash \#}
{\Psi, ~ A^-~\mathit{false} \vdash \#  
&amp;\Psi, ~ B^-~\mathit{false} \vdash \#}
\qquad
\infer
{\Psi, ~ A^+ \wedge^+ B^+~\mathit{true} \vdash \#}
{\Psi, ~ A^+~\mathit{true}, ~ B^+~\mathit{true} \vdash \#}
\]

\[
\infer
{\Psi, ~ A^- \vee^- B^-~\mathit{false} \vdash \#}
{\Psi, ~ A^-~\mathit{false}, ~ B^-~\mathit{false} \vdash \#}
\qquad
\infer
{\Psi, ~ A^+ \vee^+ B^+~\mathit{true} \vdash \#}
{\Psi, ~ A^+~\mathit{true} \vdash \#
&amp;\Psi, ~ B^+~\mathit{true} \vdash \#}
\]

&lt;p&gt;So, are we good? Well, no, not really. The problem is that the "+" or "-" stuck to an atomic proposition isn't an annotation or modifier the way the overbar was in the one-sided, truth-oriented sequent calculus above. \(P^+\) and \(P^-\) are &lt;i&gt;different&lt;/i&gt; atomic propositions, and it wouldn't be right to given an inference rule that had, as its conclusion, \(\Psi, ~ P^+~\mathit{true}, ~ P^-\mathit{false}\). Why? Well, for now let's go with "because I said so." The argument I have for this point isn't bulletproof, and it has to do with the role of atomic propositions as stand-ins for other propositions.&lt;/p&gt;

&lt;p&gt;However, if you accept my argument from authority, we are left no way to prove, or even to state, anything equivalent to the classical \(P \vee \neg P\) into polarized logic, since any way we try to polarize this formula will lead to \(P\) needing to be both positive and negative. We're going to need some way, different from negation, of including positive propositions in negative ones.&lt;/p&gt;

&lt;p&gt;These inclusions of positive propositions into negative ones (and vice versa) are called &lt;i&gt;shifts&lt;/i&gt; - \({\downarrow}A^-\) is a positive proposition and \({\uparrow}A^+\) is a negative proposition. We could just add these two rules and call it a day...

\[
\infer
{\Psi, ~ P^+~\mathit{true}, ~ {\uparrow}P^+~\mathit{false} \vdash \#}
{}
\qquad
\infer
{\Psi, ~ P^-~\mathit{false}, ~ {\downarrow}P^-~\mathit{true} \vdash \#}
{}
\]
 
...but this is hardly general: the rules above should be derivable; this rule should be derivable as well:

\[
\infer
{\Psi, ~ P^+~\mathit{true}, ~{\uparrow}(P^+ \vee^+ Q^+)~\mathit{false} \vdash \#}
{}
\]

All three of these derivable rules share a common property: in an on-paper proof, we would say that the contradiction is "trivial." The hypothesis \({\uparrow}P^+~\mathit{false}\) is trivial due to the fact that \(P^^\) is true by a different hypothesis, and because the truth of \(P+^\) allows us to trivially conclude that \(P^+ \vee\^+ Q^+\) is true,  \(P^+ \vee^+ Q^+\) is trivially contradictory as well.&lt;/p&gt;

&lt;p&gt;This idea is encoded in two rules which capture proof-by-contradiction. One way we establish a contradiction is by showing that \(A^+\) is both false (by assumption) and trivial (by direct proof). The other way we establish a contradiction is by showing that \(A^-\) is both true (by assumption) and false (by direct proof of absurdity). These are embodied in the following two rules:&lt;/p&gt;

\[
\infer
{\Psi \vdash \#}
{{\uparrow}A^+~\mathit{false} \in \Psi 
&amp;\Psi \vdash A^+~\mathit{trivial}}
\qquad
\infer
{\Psi \vdash \#}
{{\downarrow}A^-~\mathit{true} \in \Psi 
&amp;\Psi \vdash A^-~\mathit{absurd}}
\]

&lt;p&gt;Now, of course, we need to give a bunch more rules to describe how to prove positive propositions trivial and negative propositions absurd.&lt;/p&gt;

\[
\infer
{\Psi, ~ P^+~\mathit{true} \vdash P^+~\mathit{trivial}}
{}
\qquad
\infer
{\Psi, ~ P^-~\mathit{false} \vdash P^-~\mathit{absurd}}
{}
\]

\[
\infer
{\Psi \vdash \neg^+ A^-~\mathit{trivial}}
{\Psi \vdash A^-~\mathit{absurd}}
\qquad
\infer
{\Psi \vdash \neg^- A^+~\mathit{absurd}}
{\Psi \vdash A^+~\mathit{trivial}}
\]

\[
\infer
{\Psi \vdash A^+ \wedge^+ B^+~\mathit{trivial}}
{\Psi \vdash A^+~\mathit{trivial}
&amp;\Psi \vdash B^+~\mathit{trivial}}
\qquad
\infer
{\Psi \vdash A^+ \vee^+ B^+~\mathit{trivial}}
{\Psi \vdash A^+~\mathit{trivial}}
\qquad
\infer
{\Psi \vdash A^+ \vee^+ B^+~\mathit{trivial}}
{\Psi \vdash B^+~\mathit{trivial}}
\]

\[
\infer
{\Psi \vdash A^- \wedge^- B^-~\mathit{absurd}}
{\Psi \vdash A^-~\mathit{absurd}}
\qquad
\infer
{\Psi \vdash A^- \wedge^- B^-~\mathit{absurd}}
{\Psi \vdash B^-~\mathit{absurd}}
\qquad
\infer
{\Psi \vdash A^- \vee^- B^-~\mathit{absurd}}
{\Psi \vdash A^-~\mathit{absurd}
&amp;\Psi \vdash B^-~\mathit{absurd}}
\]

&lt;p&gt;Even yet, we are not done! We need to deal with the shifts, which embody another form of proof-by-contradiction: to prove that \(A^-\) holds trivially, assume it's false and derive a contradiction.&lt;/p&gt;

\[
\infer
{\Psi \vdash {\downarrow}A^-~\mathit{trivial}}
{\Psi, A^-~\mathit{false} \vdash \#}
\qquad
\infer
{\Psi \vdash {\uparrow}A^+~\mathit{absurd}}
{\Psi, A^+~\mathit{true} \vdash \#}
\]

&lt;p&gt;The thing that we've come up with by this process is what I've been calling a "weakly focused" version of classical logic. If we wanted to turn it into a "fully focused" presentation of classical logic, we'd only need to make one change: the first "proof by contradiction" rules, which we call "focusing" rules, would need to require that the context \(\Psi\) includes only judgments of the form \(P^+~\mathit{true}\), \({\downarrow}A^-~\mathit{true}\), \(P^-~\mathit{false}\), and \({\uparrow}A^+~\mathit{false}\). A context including only judgments of these four forms is called &lt;i&gt;stable&lt;/i&gt;. To get full focusing, we would modify the "trivial focus" rule like this (a similar modification would be made to the "absurd focus" rule):&lt;/p&gt;

\[
\infer
{\Psi \vdash \#}
{{\uparrow}A^+~\mathit{false} \in \Psi 
&amp;\Psi \vdash A^+~\mathit{trivial}
&amp;\Psi~\mathit{stable}}
\]

&lt;p&gt;Thinking about the sequent calculus as a bottom-up proof search procedure, if we are looking for a proof of a non-stable sequent, we can use our original, invertible rules to break down the connectives in the contexts until we have only stable sequents, at which point we can apply a focusing rule.&lt;/p&gt;

&lt;h3&gt;Until next time...&lt;/h3&gt;

&lt;p&gt;I haven't quite had time to do the thing I originally set out to do, which was to work through the notation in "Polarity and the logic of delimited continuations" better. But I will save that for another time. The motivation is the same as the one from before: it seems like we're almost certainly duplicating work. Is it possible to give the presentation of polarized classical logic from the previous section using about half as many rules?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-3284389650562688481?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/dB8oFGWXnIc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/3284389650562688481/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/12/notes-on-classical-sequent-calculi-12.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/3284389650562688481?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/3284389650562688481?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/dB8oFGWXnIc/notes-on-classical-sequent-calculi-12.html" title="Notes on classical sequent calculi (1/2)" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/12/notes-on-classical-sequent-calculi-12.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUIBRXw9fCp7ImA9WhRSEkw.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-3026002262722072124</id><published>2011-11-12T10:50:00.001-05:00</published><updated>2011-11-13T14:45:54.264-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-13T14:45:54.264-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="focusing" /><category scheme="http://www.blogger.com/atom/ns#" term="natural deduction" /><category scheme="http://www.blogger.com/atom/ns#" term="polarity" /><title>Another take on polarized natural deduction</title><content type="html">&lt;p&gt;This has been sitting on my office whiteboard for a few days, where it doesn't do anybody (well, except for me and my officemates) any good. It's a canonical-forms presentation of natural deduction for polarized logic that corresponds to the focused sequent calculus I presented and analyzed in the (recently-updated) &lt;a href="www.cs.cmu.edu/~rjsimmon/drafts/focus.pdf"&gt;Structural focalization&lt;/a&gt; draft (PDF warning). The polarized sequent calculus in that draft isn't new: it's a tweaked version of Liang and Miller's authoritative LJF.&lt;sup&gt;&lt;a href"#atake1"&gt;1&lt;/a&gt;&lt;/sup&gt; This canonical-forms presentation, however, is not something I've seen, so I'd be interested to know if it's been seen elsewhere: I know this is an area where a lot of other people have been working.&lt;/p&gt;

&lt;h2&gt;A bidirectional type system for polarized logic&lt;/h2&gt;

&lt;p&gt;There is, in my mind at least, no argument about what the &lt;i&gt;propositions&lt;/i&gt; of polarized intuitionstic logic are; the following is straight of the aforementioned draft, but the basic idea dates back to Girard's 1991 post to the LINEAR mailing list, creatively titled "&lt;a href="http://www.seas.upenn.edu/~sweirich/types/archive/1991/msg00123.html"&gt;On the sex of angles&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;
\( {\bf Positive~propositions:} ~~ A^+, B^+, C^+ ~~ ::= ~~ p^+ \mid {\downarrow}A^- \mid \bot \mid A^+ \vee B^+ \mid \top^+ \mid A^+ \wedge^+ B^+ \)
&lt;br/&gt;
\( {\bf Negative~propositions:} ~~ A^-, B^-, C^- ~~ ::= ~~ p^- \mid {\uparrow}A^+ \mid A^+ \supset B^- \mid \top^- \mid A^- \wedge^- B^- \)
&lt;/p&gt;

&lt;p&gt;What makes a proposition positive or negative? Good question! I won't address it here. (I address it a bit in the draft.)&lt;/p&gt;

&lt;p&gt;Following tradition and best practices, we will structure the canonical forms presentation as a bidirectional type system. There are three judgments to worry about, as compared to the two judgments in other canonical forms presentations of logic. These judgments include contexts \(\Gamma\), which are sets of &lt;i&gt;negative&lt;/i&gt; variables \(x\) associated with negative propositions (\(x{:}A^-\)) and &lt;i&gt;positive&lt;/i&gt; variables \(z\) associated with &lt;i&gt;atomic&lt;/i&gt; positive propositions (\(z{:}p^+\)).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;\( \Gamma \vdash R \Rightarrow A^- \) - this is the familiar synthesis judgment from canonical forms presentations; it expresses that the &lt;i&gt;atomic term&lt;/i&gt; \(R\) &lt;i&gt;synthesizes&lt;/i&gt; \(A^-\). The word "synthesis" is used because it is possible to think of the type \(A^-\) as an output to the judgment, whereas \(\Gamma\) and \(R\) are inputs. In the other two judgments, everything will be treated as an input.&lt;/p&gt;
&lt;p&gt;\( R ::= x \mid R~V \mid \pi_1 R \mid \pi_2 R \)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;\( \Gamma \vdash V \Leftarrow A^+ \) - this is the new judgment corresponding to &lt;i&gt;right focus&lt;/i&gt; in the focused sequent calculus; we say that the &lt;i&gt;value&lt;/i&gt; \(V\) &lt;i&gt;checks against&lt;/i&gt; \(A^+\).&lt;/p&gt;
&lt;p&gt;\( V ::= z \mid N \mid {\sf inl}~V \mid {\sf inr}~V \mid \langle\rangle^+ \)&lt;/p&gt; &lt;/li&gt;
&lt;li&gt;&lt;p&gt;\( \Gamma \vdash N \Leftarrow [\Omega] A^-\) - this is a modification of the familiar checking judgment from canonical forms presentations, which usually lack the bit about \([\Omega]\), which is an ordered list of positive propositions. The reason we need \([\Omega]\) is precisely because we're dealing with positive propositions, which most canonical forms presentations lack or deal with in an unsatisfactory (in my humble opinion) manner. (I'll return to this point in the discussion at the end.)We say that thus judgment expresses that the &lt;i&gt;normal term&lt;/i&gt; \(N\) &lt;i&gt;decomposes&lt;/i&gt; \(\Omega\) &lt;i&gt;and verifies&lt;/i&gt; \(A^-\).&lt;/p&gt;
&lt;p&gt;\( N ::= R \mid z.N \mid V \mid {\sf let}~R~{\sf in}~N \mid x.N \mid \lambda N \mid \langle\rangle^- \mid \langle N_1, N_2 \rangle^- \mid {\sf abort} \mid [ N_1, N_2 ]\)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Except for the first four rules, everything is patterned in the usual style of presentation for a natural deduction system: for each connective, we give first the introduction rules and then the elimination rules.&lt;/p&gt;

&lt;h3&gt;Hypothesis and atomic propositions&lt;/h3&gt;
\[
\infer
{\Gamma \vdash R \Leftarrow []p^-}
{\Gamma \vdash R \Rightarrow p'^-
 &amp;
 p^- = p'^-}
\qquad
\infer
{\Gamma \vdash x \Rightarrow A^-}
{x{:}A^- \in \Gamma}
\qquad
\infer
{\Gamma \vdash z \Leftarrow p^+}
{z{:}p^+ \in \Gamma}
\qquad
\infer
{\Gamma \vdash z.N \Leftarrow [p^+, \Omega] C^-}
{\Gamma, z{:}p&amp;+ \vdash N \Leftarrow [\Omega] C^-}
\]

&lt;h3&gt;Shifts&lt;/h3&gt;
\[
\infer
{{\uparrow}A^+~{\it stable}}
{}
\qquad
\infer
{p^-~{\it stable}}
{}
\]

\[
\infer
{\Gamma \vdash V \Leftarrow []{\uparrow}A^+}
{\Gamma \vdash V \Leftarrow A^+}
\qquad
\infer
{\Gamma \vdash {\sf let}~R~{\sf in}~N \Leftarrow []C^-}
{\Gamma \vdash R \Rightarrow {\uparrow}A^+ 
 &amp;
 \Gamma \vdash N \Leftarrow [A^+]C^-
 &amp;
 C^-~{\it stable}}
\]
\[
\infer
{\Gamma \vdash N \Leftarrow {\downarrow}A^-}
{\Gamma \vdash N \Leftarrow []A^-}
\qquad
\infer
{\Gamma \vdash x.N \Leftarrow [{\downarrow}A^-, \Omega]C^-}
{\Gamma, x{:}A^- \vdash N \Leftarrow [\Omega]C^-}
\]

&lt;h3&gt;Connectives&lt;/h3&gt;
\[
\infer
{\Gamma \vdash \lambda N \Leftarrow []A^+ \supset B^-}
{\Gamma \vdash N \Leftarrow [A^+]B^-}
\qquad
\infer
{\Gamma \vdash R~V \Rightarrow B^-}
{\Gamma \vdash R \Rightarrow A^+ \supset B^-
 &amp;
 \Gamma \vdash V \Leftarrow A^+}
\]



\[
\infer
{\Gamma \vdash \langle\rangle^- \Leftarrow \top^-}
{}
\qquad
{\it (no~elim~rule~for~\top^-)}
\]

\[
\infer
{\Gamma \vdash \langle N_1, N_2 \rangle^- \Leftarrow A^- \wedge^- B^-}
{\Gamma \vdash N_1 \Leftarrow A^-
 &amp;
 \Gamma \vdash N_2 \Leftarrow B^-}
\qquad
\infer
{\Gamma \vdash \pi_1 R \Rightarrow A^-}
{\Gamma \vdash R \Rightarrow A^- \wedge^- B^-}
\qquad
\infer
{\Gamma \vdash \pi_2 R \Rightarrow B^-}
{\Gamma \vdash R \Rightarrow A^- \wedge^- B^-}
\]



\[
{\it (no~intro~rule~for~\bot)}
\qquad
\infer
{\Gamma \vdash {\sf abort} \Leftarrow [\bot, \Omega]C^-}
{}
\]

\[
\infer
{\Gamma \vdash {\sf inl}~V \Leftarrow A^+ \vee B^+}
{\Gamma \vdash V \Leftarrow A^+}
\qquad
\infer
{\Gamma \vdash {\sf inr}~V \Leftarrow A^+ \vee B^+}
{\Gamma \vdash V \Leftarrow B^+}
\qquad
\infer
{\Gamma \vdash [N_1, N_2] \Leftarrow [A^+ \vee B^+, \Omega] C^-}
{\Gamma \vdash N_1 \Leftarrow [A^+, \Omega] C^-
 &amp;
 \Gamma \vdash N_2 \Leftarrow [B^+, \Omega] C^-}
\]



\[
\infer
{\Gamma \vdash \langle\rangle^+ \Leftarrow \top^+}
{}
\qquad
\infer
{\Gamma \vdash \langle\rangle.N \Leftarrow [\top^+, \Omega] C^-}
{\Gamma \vdash N \Leftarrow [\Omega] C^-}
\]



\[
\infer
{\Gamma \vdash \langle V_1^+, V_2^+ \rangle \Leftarrow A^+ \wedge^+ B^+}
{\Gamma \vdash V_1^+ \Leftarrow A^+
 &amp;
 \Gamma \vdash V_2^+ \Leftarrow B^+}
\qquad
\infer
{\Gamma \vdash N \Leftarrow [A^+ \wedge^+ B^+, \Omega] C^-}
{\Gamma \vdash N \Leftarrow [A^+, B^+, \Omega] C^-}
\]

&lt;h2&gt;Discussion&lt;/h2&gt;

&lt;p&gt;There are two possible questions I want to address about this system in the previous section.&lt;/p&gt;

&lt;h3&gt;What's with those positive "elimination" rules?&lt;/h3&gt;

&lt;p&gt;It would be possible to complain that the system above is not very "natural deduction-ey" after all - for all the positive connectives, I basically give sequent calculus &lt;i&gt;left rules&lt;/i&gt; instead of natural deduction &lt;i&gt;elimination rules&lt;/i&gt;. What happened to the usual "large elimination"-style elimination rules, for instance the usual disjunction-elimination rule whose proof term is a case analysis?
\[
\infer
{\Gamma \vdash ({\sf case}~R~{\sf of}~{\sf inl}~x \rightarrow N_1 \mid {\sf inr}~y \rightarrow N_2) \Leftarrow C}
{\Gamma \vdash R \Rightarrow A \wedge B
 &amp;
 \Gamma, x{:}A \vdash N_1 \Leftarrow C
 &amp;
 \Gamma, y{:}B \vdash N_2 \Leftarrow C}
\]&lt;/p&gt;

&lt;p&gt;I think that the answer can be given by looking at the shifts. Essentially, every large elimination as we know and love it follows from the structure of the \({\uparrow}\) elimination rule, which all on its own looks an awful lot like a cut. You should verify for yourself that, if you let \({\sf case}~R~{\sf of}~{\sf inl}~x \Rightarrow N_1 \mid {\sf inr}~y \Rightarrow N_2\) be defined as syntactic sugar for \({\sf let}~R~{\sf in}~[ x.N_1, y.N_2]\), then the following rule is derivable whenever \(C^-~{\it stable}\) holds.&lt;sup&gt;&lt;a href="#atake2"&gt;2&lt;/a&gt;&lt;/sup&gt;
\[
\infer
{\Gamma \vdash {\sf case}~R~{\sf of}~{\sf inl}~x \Rightarrow N_1 \mid {\sf inr}~y \Rightarrow N_2 \Leftarrow C^-}
{\Gamma \vdash R \Rightarrow {\uparrow}({\downarrow}A^- \vee {\downarrow}B^-)
 &amp;
 \Gamma, x{:}A^- \vdash N_1 \Leftarrow C^-
 &amp;
 \Gamma, y{:}B^- \vdash N_2 \Leftarrow C^-}
\]
&lt;/p&gt;

&lt;p&gt;Pay attention to those two appearances of the downshift \({\downarrow}\) - they tell you something important about the structure of the usual elimination rules, which is that they "lose focus" while decomposing the disjunction. The usual way of thinking of normal natural deduction doesn't require, when you decompose \(A \vee B\) in an elimination, that you continue decomposing \(A\) and \(B\), which is represented here by the fact that, to match the structure of the usual elimination rule, you have to put downshifts \in explicitly. Jacob Howe, in his thesis and in his excellent paper "Proof search in lax logic," demonstrates this by making a focused sequent calculus that corresponds to the usual (constantly-interrupted) notion of decomposing positive propositions that you get if you follow your intuitions from natural deduction too closely.&lt;/p&gt;

&lt;p&gt;By gathering all the large eliminations together in the \({\uparrow}\) elimination rule, we allow for the usual large eliminations to be defined, but also allow for the possibility that we might want to "chain" large eliminations in a well-defined way. (As an exercise, consider the structure of the elimination rule for \({\uparrow}(({\downarrow}A^- \wedge^+ {\downarrow}B^-) \vee (p^+ \wedge^+ \top^+))\).) This is why I claim that this is a natural deduction system that corresponds to the focused sequent calculus, instead of Howe's system where it's the other way around.&lt;sup&gt;&lt;a href="#atake3"&gt;3&lt;/a&gt;&lt;sup&gt;&lt;/p&gt;

&lt;h3&gt;Where are all the patterns?&lt;/h3&gt;

&lt;p&gt;Patterns have been associated with focused and/or canonical forms presentations of logic ever since... well, since Neel wrote the paper "&lt;a href="http://dl.acm.org/citation.cfm?id=1480927"&gt;Focusing on pattern matching&lt;/a&gt;"... or maybe since Noam wrote "&lt;a href="http://dl.acm.org/citation.cfm?id=1328482"&gt;Focusing and higher-order abstract syntax&lt;/a&gt;"... well, really at least since the &lt;a href="http://reports-archive.adm.cs.cmu.edu/anon/2002/abstracts/02-101.html"&gt;CLF tech report&lt;/a&gt;. A lot of these, notably Noam's systems, have presented the rules of logic using &lt;i&gt;pattern judgments&lt;/i&gt;, devices which abstractly represent the way in which values of a particular (positive) type are constructed or the way atomic terms of a particular (negative) type are eliminated.&lt;/p&gt;

&lt;p&gt;There's this picture that isn't fully formed in my head, but that I've been thinking about for some time. On the left side of this picture, I think, you have the (pattern-free) presentation of natural deduction that I have given here at the top, and the (pattern-free) focused sequent calculus from "Structural focalization" at the bottom. Then, in the middle, you have (at the top) a natural deduction system that uses Noam's pattern judgments to &lt;i&gt;introduce&lt;/i&gt; negative propositions and &lt;i&gt;eliminate&lt;/i&gt; positive propositions - this is precisely (or at least very nearly) Taus Brock-Nannestad and Carsten Sch&amp;uuml;rmann's system from "&lt;a href="http://www.springerlink.com/content/h7551281753g5266/"&gt;Focused Natural Deduction&lt;/a&gt;." Below it, there is a sequent calculus system that uses Noam's pattern judgments to &lt;i&gt;eliminate&lt;/i&gt; negative propositions and &lt;i&gt;introduce&lt;/i&gt; positive propositions. Kevin Watkins and Frank Pfenning came up with this idea and named it the "skeleton calculus" (a reference to the "spine calculus" of Cervesato and Pfenning), but it hasn't been written up that I know of. The skeleton calculus was what I was thinking about this morning when I decided to write this post. Then, on the far right, you have Noam's system, which is entirely pattern-based: patterns are used to both introduce and eliminate all connectives, so that the logic itself basically doesn't "know" about any connectives at all. This hazy picture is why, in the structural focalization draft, I mentioned that I thought Noam's system was a "natural synthesis of natural deduction and sequent calculus presentations".&lt;/p&gt;

&lt;p&gt;But why should the picture look like the one I sketched above? Why not have a natural deduction system that uses patterns to introduce positives and eliminate negatives, or a sequent calculus that uses patterns to eliminate positives and introduce negatives? There's also the elephant in the room: CLF, which has both natural deduction and sequent calculus presentations, but which, in both instances, uses patterns only in the elimination of positive connectives. What are all these options doing here, and what are we to make of them? I don't know (yet).&lt;/p&gt;

&lt;hr&gt;
&lt;small&gt;
&lt;sup&gt;1&lt;a name="atake1"&gt;&lt;/a&gt;&lt;/sup&gt; I should add that, while the adaptation of LJF isn't particularly interesting, the proof term assignment I give is different than any others I've seen and I'm pretty happy with it; that's another case where I'd be interested to know if others have done anything similar.&lt;br/&gt;
&lt;sup&gt;2&lt;a name="atake2"&gt;&lt;/a&gt;&lt;/sup&gt; This additional requirement of stability just reflects that it's always possible to restrict large eliminations in a canonical forms presentation of natural deduction to situations where the; this isn't always required in canonical forms presentations of natural deduction, but is an important part of making sure the sequent calculus presented in "Structural focalization" corresponds correctly to the natural deduction presentation.&lt;br/&gt;
&lt;sup&gt;3&lt;a name="atake3"&gt;&lt;/a&gt;&lt;/sup&gt; I specifically suspect that this is a natural deduction system &lt;i&gt;isomorphic&lt;/i&gt; to the focused sequent calculus from Structural focalization, but I don't want to make that claim until I've proved it.
&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-3026002262722072124?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/L6dDBldKtg0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/3026002262722072124/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/11/another-take-on-polarized-natural.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/3026002262722072124?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/3026002262722072124?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/L6dDBldKtg0/another-take-on-polarized-natural.html" title="Another take on polarized natural deduction" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/11/another-take-on-polarized-natural.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UMSX8zeSp7ImA9WhRRGEs.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-5457835934675350972</id><published>2011-10-10T15:11:00.000-04:00</published><updated>2011-12-02T17:34:48.181-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-02T17:34:48.181-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="dart" /><category scheme="http://www.blogger.com/atom/ns#" term="static analysis" /><category scheme="http://www.blogger.com/atom/ns#" term="language design" /><title>Feeble Typing (a thought on Dart)</title><content type="html">&lt;p&gt;&lt;i&gt;&lt;b&gt;Update: A Word About The Title&lt;/b&gt;&lt;/i&gt;. If you came here from Twitter, the line I used - "not unsound, incomplete" - referred to the original title of the article "Incomplete by design," which was based on my misunderstanding of the dominant terminology in static analysis (see updates, and thanks David and Sam in the comments for pointing out my wrongness). When I realized this, I renamed the article "Deliberate decisions," but that wasn't an interesting title. When I read Rafa&amp;euml;l Garcia-Suarez's take on Dart this morning, &lt;a href="http://blogs.perl.org/users/rafael_garcia-suarez/2011/10/why-dart-is-not-the-language-of-the-future.html"&gt;Why Dart is not the language of the future&lt;/a&gt;, I decided to support his proposal of calling types as a "lint-type development aid, not a language feature" &lt;i&gt;feeble typing&lt;/i&gt;, and renamed the article again. You should read Rafa&amp;euml;l's post and this one; it is possibly the most agreement you will ever find between a Perl blogger and a Carnegie Mellon University programming languages graduate student.&lt;/p&gt;

&lt;h3&gt;...anyway...&lt;/h3&gt;

&lt;p&gt;There's a lot of feedback, and a non-trivial amount of snark, going around the internet based on the release of &lt;a href="http://www.dartlang.org/"&gt;Dart&lt;/a&gt;, a proposed Javascript-killer by Google. My primary experience with Javascript is that people tell me it's the worst compiler target language that is widely used as a compiler target language, so I basically have nothing invested in the language, but was interested by the discussions it brought up.&lt;/p&gt;

&lt;p&gt;The snark about Dart has centered around the following line on Page 72 of the language spec, which I believe was pointed out to the Twitterverse by &lt;a href="https://twitter.com/#!/debasishg/status/123332940175376384"&gt;Debasish Ghosh&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;
The type system is unsound, due to the covariance of generic types. This is
a deliberate choice (and undoubtedly controversial). Experience has shown that
sound type rules for generics fly in the face of programmer intuition. It is easy
for tools to provide a sound type analysis if they choose, which may be useful
for tasks like refactoring.
&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;But what does it mean for a type system to be unsound? I really think that the most illustrative snippet about Dart types came on the following page of the language spec was not the one that Debasish retweeted, but one that came on the next page:&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;
A Dart implementation must provide a static checker that detects and reports exactly those situations this specification identifies as static warnings.
However:
&lt;ul&gt;&lt;li&gt;Running the static checker on a program P is not required for compiling and running P.&lt;/li&gt;
&lt;li&gt;Running the static checker on a program P must not prevent successful compilation of P nor may it prevent the execution of P, regardless of whether any static warnings occur&lt;/li&gt;
&lt;/ul&gt;&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;This, for me, clarified what was going on substantially. Let me tell you a parable.&lt;/p&gt;

&lt;h2&gt;How to anger students in an undergraduate PL course&lt;/h2&gt;

&lt;p&gt;In four easy steps!&lt;/p&gt;

&lt;h3&gt;Step 1&lt;/h3&gt;

&lt;p&gt;Tell students to implement the following dynamic semantics of a programming language. Here's an example of a very simple language:&lt;/p&gt;

\[\infer
{{\tt if}~e~{\tt then}~e_1~{\tt else}~e_2 \mapsto {\tt if}~e'~{\tt then}~e_1~{\tt else}~e_2 }
{e \mapsto e'}
\]
\[\infer
{{\tt if}~{\tt true}~{\tt then}~e_1~{\tt else}~e_2 \mapsto e_1}
{}
\qquad
\infer
{{\tt if}~{\tt false}~{\tt then}~e_1~{\tt else}~e_2 \mapsto e_2}
{}
\]
\[
\infer
{e_1 + e_2 \mapsto e_1' + e_2}
{e_1 \mapsto e_1'}
\qquad
\infer
{{\tt num}(n_1) + e_2 \mapsto {\tt num}(n_1) + e_2'}
{e_2 \mapsto e_2'}
\]
\[
\infer
{{\tt num}(n_1) + {\tt num}(n_2) \mapsto {\tt num}(n_1 + n_2)}
{}
\]

&lt;p&gt;The implementation was to be an ML function &lt;tt&gt;step&lt;/tt&gt; with type &lt;tt&gt;expr -&gt; expr option&lt;/tt&gt;, and the specification was that &lt;tt&gt;step e = SOME e'&lt;/tt&gt; if there existed an &lt;tt&gt;e'&lt;/tt&gt; such that &lt;tt&gt;e&lt;/tt&gt; \(\mapsto\) &lt;tt&gt;e'&lt;/tt&gt;, and that &lt;tt&gt;step e = NONE&lt;/tt&gt; otherwise (for instance, \(\tt true\) obviously can't take a step according to these rules).&lt;/p&gt;

&lt;h3&gt;Step 2&lt;/h3&gt;

&lt;p&gt;Describe how they can type-checking the language, by defining a type system like this. Have them implement this type checker as an ML function with type &lt;tt&gt;expr -&gt; typ option&lt;/tt&gt;, same idea.&lt;/p&gt;

\[
\infer
{{\tt true} : {\tt bool}}
{}
\qquad
\infer
{{\tt false} : {\tt bool}}
{}
\qquad
\infer
{{\tt if}~e~{\tt then}~e_1~{\tt else}~e_2 : \tau}
{e : {\tt bool} &amp; e_1 : \tau &amp; e_2 : \tau}
\]
\[
\infer
{{\tt num}(n) : {\tt number}}
{}
\qquad
\infer
{e_1 + e_2 : {\tt number}}
{e_1 : {\tt number} &amp; e_2 : {\tt number}}
\]

&lt;h3&gt;Step 3&lt;/h3&gt;

&lt;p&gt;Have students &lt;i&gt;prove the theorem that this type system does something&lt;/i&gt;. The theorem statement goes as follows, and the proof is by the by-now standard technique of safety-via-progress-and-preservation.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Theorem (Safety):&lt;/b&gt; If \(e : \tau\) and \(e \mapsto \ldots \mapsto e'\), then \(e' : \tau\) and also there either exists some \(e''\) such that \(e' \mapsto e''\) or else \(e'\) is of the form \(\tt true\), \(\tt false\), or \({\tt num}(n)\).&lt;/p&gt;

&lt;h3&gt;Step 4&lt;/h3&gt;

&lt;p&gt;Test their ML code from Step 1 on expressions like &lt;tt&gt;if 4 then true else 9&lt;/tt&gt;, breaking many of the students implementations of the dynamic semantics which were prepared only to handle well-typed inputs.&lt;/p&gt;

&lt;h3&gt;Analysis: is this fair?&lt;/h3&gt;

&lt;p&gt;Think about the perspective of the student who complained about the fact that their interpreter either crashed (or maybe returned &lt;tt&gt;SOME(Num 9)&lt;/tt&gt;!) after being handed &lt;tt&gt;if 4 then true else 9&lt;/tt&gt;. On one hand, they clearly violated the spirit of the assignment: Step 1 was a perfectly well-defined assignment all on its own, and they didn't fulfill the specification of that particular assignment. But on the other hand, they proved the theorem in Step 3, and perhaps feel as if they should &lt;i&gt;get something&lt;/i&gt; out of the fact that they proved that theorem: the ability to only have to reason about the behavior of well-typed programs: why should it not be surpassing that garbage-in produced garbage-out?&lt;/p&gt;

&lt;p&gt;Compiler writers actually get to think like that; indeed it's almost essential that they be allowed to. On a 32-bit machine, most values are compiled to plain ol' 32-bit words, and so the representation of \(\tt false\) might have the same in-memory representation as, say, \({\tt num}(0)\). Or it might have the same in-memory representation as \({\tt num}(1)\)! It doesn't matter, because, for the compiler writer, the safety theorem has already given a guarantee that the language has &lt;i&gt;canonical forms&lt;/i&gt; - that if \(e : {\tt bool}\) and \(e\) eventually steps to an irreducible expression, then that irreducible expression &lt;i&gt;must&lt;/i&gt; either be \(\tt true\) or \(\tt false\).&lt;/p&gt;

&lt;p&gt;This means that the compiler writer need not worry about how &lt;tt&gt;if 1 then true else 9&lt;/tt&gt; and &lt;tt&gt;if 0 then true else 9&lt;/tt&gt; might behave - they may raise an exception, return (the memory representation of) &lt;tt&gt;true&lt;/tt&gt;, or return (the memory representation of) &lt;tt&gt;false&lt;/tt&gt;. The only programs upon which the compiler promises to behave the same way as the language definition are those that pass the typechecker, and the type safety theorem is a critical component of that promise.&lt;/p&gt;

&lt;p&gt;In this way of looking at the world, the &lt;i&gt;representation independence&lt;/i&gt; given by a type system is really quite important, and it means that an &lt;i&gt;unsound&lt;/i&gt; type system could cause very very bad things to happen: if you're allowed to mess around with the representation of, say, a pointer, by adding things to it, then you have introduced buffer overflow errors to a language, which would be pretty awful if you allowed code written in this language to execute in a privileged way in your browser. That (hopefully!) is not at all what Dart means when they mean their programming language is unsound.&lt;/p&gt;

&lt;h2&gt;Theorems versus bugs&lt;/h2&gt;

&lt;p&gt;I think the problem here is that, as a broad overgeneralization, there are to ways to look at what people are &lt;i&gt;doing&lt;/i&gt; with types in the first place. On one hand, there is the view that &lt;i&gt;types are a tool to provably preclude certain classes of errors&lt;/i&gt; - like the possibility that you might end up with the expresion &lt;tt&gt;if 1 then true else 9&lt;/tt&gt; which is "stuck" according to the defined operational semantics. On the other hand, there is the idea that &lt;i&gt;types are a language feature that is aimed at helping document code and reduce the number of bugs in a program without necessarily precluding any particular errors&lt;/i&gt;. In the academic circles I travel in, a &lt;i&gt;type system&lt;/i&gt; is understood as a technical definition about the former: if you can't prove a theorem about what kind of errors your type system precludes, then it is something else besides a type system. I think it's quite fair to both type systems and static analysis researchers to call the &lt;i&gt;latter&lt;/i&gt; notion of types a simple form of static analysis.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;[Updated]&lt;/i&gt; There's nothing wrong, per se, with such a static analysis, though I think it's fair to call it an &lt;b&gt;unsound static analysis&lt;/b&gt; instead of an &lt;b&gt;unsound type system&lt;/b&gt;. To use the language of Ciera Jaspan's recent thesis, start with a particular class of error (gets-stuck, raises-a-certain-exception, divides by zero, whatever). An analysis is &lt;i&gt;sound&lt;/i&gt; if it never passes a program with a particular sort of error (permitting a safety theorem about that analysis!) and &lt;i&gt;complete&lt;/i&gt; if it fails only programs that will actually manifest the error at runtime.&lt;sup&gt;&lt;a href="#choice1"&gt;1&lt;/a&gt;&lt;/sup&gt; A sound but incomplete analysis is called &lt;i&gt;conservative&lt;/i&gt;; the type checkers of ML and Java represent such analyses. An analysis that is neither sound nor complete is called &lt;i&gt;pragmatic&lt;/i&gt; by Jaspan, as there aren't any theorems to be proved about such an analysis: they can be justified only by their utility in practice.&lt;/p&gt;

&lt;p&gt;I can certainly think of situations where I'd want a pragmatic analysis. In the past, I have had occasion to write Python, which I will admit I have a certain fondness for. However, I have also complained about how my complicated Python program ran for half an hour and then failed with some cast exception that, upon inspection of the code, was &lt;i&gt;always, statically, evidently going to happen no matter what the complicated bits of the code did&lt;/i&gt; and why couldn't it have warned me that it was going to do that &lt;i&gt;before&lt;/i&gt; running for half an hour. Even if I implemented an analysis to generate such a warning, Python is and would remain a (hopefully) safe, strongly-typed programming language with exactly one type - the type of tagged data that causes an exception if you try to use an object as an integer (or whatever). The static analysis is trying to prove a different kind of theorem - one that says "you have indicated that raising &lt;tt&gt;ClassCastException&lt;/tt&gt; is undesirable, and here's a proof that your current program will raise &lt;tt&gt;ClassCastException&lt;/tt&gt;". If the static analysis &lt;i&gt;can't&lt;/i&gt; prove that theorem (thus demonstrating a bug), I'm no worse off than I was when I used Python without that static analysis. A type safety theorem, however, would have the form "if the program passes the typechecker, then &lt;tt&gt;ClassCastException&lt;/tt&gt; &lt;i&gt;will not be raised&lt;/i&gt;."&lt;/p&gt;

&lt;p&gt;And with my current understanding, the "unsound type system" of Dart is just such a "pragmatic analysis" as described by Jaspan. I hope my examples explain what might still be wrong with such a language - if you can't static preclude certain classes of errors, you must either allow "unspecified behavior" (and that way lies buffer overruns and security violations) or else you must be able and willing to check, at execution time, for the occurrence of those errors, which is not efficient (and for some classes of errors may be impossible). You're back in the world of our hypothetical angry student: you've got to be able to handle all the ill-formed programs and obey the language definition on a wider class of programs.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;[Updated]&lt;/i&gt; ...you could argue, of course, that you're no worse off than you were when you finished Step 1. On some level, you're certainly right; my hypothetical Python+tool-to-catch-a-couple-of-errors is better, in my humble opinion, than Python without (and this view has the virtue of &lt;a href="http://twitter.com/#!/simrob/status/123532533261549568"&gt;honesty&lt;/a&gt;). If you want to make that argument, however, I encourage you to read &lt;a href="http://conway.rutgers.edu/~ccshan/wiki/blog/posts/Unsoundness/"&gt;Chung-chieh Shan's related blog post about covariant generics&lt;/a&gt;, which argues from a less practical-compiler-optimizations and more philosophical point of view that I also find quite convincing. The point he makes is that the traditional view of types is important because &lt;i&gt;types should mean things&lt;/i&gt; - unless you want to choke on pencils!&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In summary: type systems are useful because of type safety theorems: a type safety theorem means that certain things &lt;i&gt;can't&lt;/i&gt; happen. One reason this is nice is because the complier writer, the programmer, and the language designer needn't worry about what happens in the case that such an impossible thing happens.&lt;/p&gt;

&lt;p&gt;Types are also a form of documentation, and they're a regular form of documentation that a complier can then take, generating warnings or errors about certain classes of bugs without actually promising to preclude those bugs. A static analysis that uses type information to preclude some (but not all) errors of a particular type is probably better termed an "pragmatic type-based analysis" than an "unsound type system." Garcia-Suarez called it "feeble typing" and I renamed my post accordingly. It's a bit more pejorative than the tone I was originally trying to take in the article, but I like it anyway.&lt;/p&gt;

&lt;p&gt;I think that's a fair way of looking at things, and it puts decidable type systems, on a practical level, as a member of a larger class of type based-static analyses.&lt;sup&gt;&lt;a href="choice2"&gt;2&lt;/a&gt;&lt;/sup&gt; In a type system, we must be able to ask a question about what sort of theorem is proved about programs that are well-typed, and if there's no such theorem, then the analysis is still within the class of type-based static analyses, but isn't so much a type system. At the end of the day, of course, English has no central authority, so asking people to distinguish "type-based analyses" from "type systems" may be a fool's errand,&lt;sup&gt;&lt;a href="choice3"&gt;3&lt;/a&gt;&lt;/sup&gt; but I think it's worthwhile to delineate the difference, and I don't think my delineation significantly departs from current usage (apart from "feeble typing" which was, I think, coined the day after I originally posted this).&lt;/p&gt;

&lt;p&gt;Something I started off wanting to talk about before this post got too long was &lt;i&gt;why&lt;/i&gt; it is the case that "sound type rules for generics fly in the face of programmer intuition" (which is pretty clearly, in my opinion, missing the addendum "in languages with subtyping"), because two of the reasons why I think this is the case are quite interesting on their own. One of them has to do with &lt;i&gt;polynomial data types&lt;/i&gt; and &lt;i&gt;persistent data&lt;/i&gt;, and the other has to do with &lt;i&gt;base types and refinement types&lt;/i&gt; as explored by William Lovas in his thesis. Neither of these ideas are adequately represented in existing programming languages, though they are more-or-less theoretically understood at this point. Another day, perhaps.&lt;/p&gt;

&lt;h3&gt;Last word&lt;/h3&gt;

&lt;p&gt;I noticed that one of the principal language designers was &lt;a href="http://gototoday.dk/2011/10/10/lars-bak-on-dart/"&gt;quoted&lt;/a&gt; as follows&lt;/p&gt;

&lt;blockquote&gt;&lt;i&gt;You have to understand that the types are interface types, not implementation types – so the runtime cannot use the type information for anything. The types are simply thrown away during compilation.&lt;/i&gt;&lt;/blockquote&gt;

&lt;p&gt;That is to say, insofar as this article goes, I think I've only said factual things that the language designers would essentially agree with; in particular, they seem to recognize that their use of the word "types" seems boud to confuse (or &lt;a href="http://twitter.com/#!/littlecalculist/status/123639731870380032"&gt;troll&lt;/a&gt;) others. But calling a "feeble type" an &lt;i&gt;interface types&lt;/i&gt; and a "type" an &lt;i&gt;implementation type&lt;/i&gt; seems to just be making up words. And, as made-up-words go, I really dislike "interface types" as a neologism (certainly it has nothing to do with Java &lt;tt&gt;interface&lt;/tt&gt; or anything that comes up when I search for "interface type"). The theorist's critique of Dart is precisely that things you call "type" should define inviolate interfaces and not mere suggestions that are neither enforced nor checked. Calling them &lt;i&gt;interface types&lt;/i&gt; makes them sound like &lt;a href="http://eecs.northwestern.edu/~robby/pubs/"&gt;contracts&lt;/a&gt;, which are &lt;i&gt;not&lt;/i&gt; thrown away by the compiler. "Suggestion type" might be a less pejorative version of "feeble type," perhaps? And "implementation types" is a terrible term to use to describe types in a a type system, types that (by way of a theorem about canonical forms) can be relied upon by &lt;i&gt;both&lt;/i&gt; the programmer and the implementation.&lt;/p&gt;

&lt;hr&gt;
&lt;p&gt;&lt;sup&gt;&lt;a name="choice1"&gt;&lt;/a&gt;1&lt;/sup&gt; Godefroid, Nori, Rajamani, and Tetal call the sound analyses &lt;i&gt;may&lt;/i&gt; analyses (though it should perhaps be &lt;i&gt;may not&lt;/i&gt;, as a sound analysis precludes a certain behavior) and call the complete analyses &lt;i&gt;must&lt;/i&gt; analyses (the error must happen) in the paper "Compositional may-must analysis."&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;a name="choice2"&gt;&lt;/a&gt;2&lt;/sup&gt; This view really &lt;i&gt;isn't&lt;/i&gt; fair to the reason that we are interested in type systems and believe they're supposed to be useful, but that has to do with Curry-Howard and the unreasonable effectiveness of mathematics and with other things Shan talked about in his linked post.&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;a name="choice3"&gt;&lt;/a&gt;3&lt;/sup&gt; Honestly, it probably won't help the fool's errand if I try to call the other group's type based analyses "feeble typing," but here I am, doing it anyway.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-5457835934675350972?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/eEkKmpxXuVc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/5457835934675350972/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/10/incomplete-by-design-thought-on-dart.html#comment-form" title="25 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/5457835934675350972?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/5457835934675350972?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/eEkKmpxXuVc/incomplete-by-design-thought-on-dart.html" title="Feeble Typing (a thought on Dart)" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>25</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2011/10/incomplete-by-design-thought-on-dart.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUADSX04eip7ImA9WhdUGEw.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-1593913029104389616</id><published>2011-10-03T22:58:00.000-04:00</published><updated>2011-10-05T07:22:58.332-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-10-05T07:22:58.332-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="judgmental reconstruction" /><category scheme="http://www.blogger.com/atom/ns#" term="modal logic" /><title>Slicing and dicing validity: existing ideas</title><content type="html">&lt;p&gt;This is a story of modal logic and the &lt;i&gt;judgmental methadology&lt;/i&gt;, a style of presenting and justifying logic that Pfenning and Davies [&lt;a href="#ak1"&gt;1&lt;/a&gt;] adapted from Martin L&amp;ouml;f's Siena Lectures [&lt;a href="#ak2"&gt;2&lt;/a&gt;] and which was, in turn, adapted by Bernado Toninho and I [&lt;a href="#ak3"&gt;3&lt;/a&gt;]. My goal is to re-present some existing work: I changed the title from "&lt;i&gt;old ideas&lt;/i&gt;" to "&lt;i&gt;existing ideas&lt;/i&gt;" to remove any implicit negative connotation - my next step is to extend these existing ideas a bit, not to replace these old ideas with better ones.&lt;/p&gt;

&lt;p&gt;The topic of this story is, at least at first, an account of modal logic that I have adapted from Pfenning and Davies's presentation [&lt;a href="#ak1"&gt;1&lt;/a&gt;]. I assume some familiarity with the background, this isn't a comprehensive introduction. Pfenning and Davies's topic was a presentation of modal logic as a logic where there are two &lt;i&gt;categorial judgments&lt;/i&gt;, \(A~{\it true}\) and \(A~{\it valid}\); the intent is that validity captures &lt;i&gt;unconditional truth&lt;/i&gt;, which is eventually related to modal necessity.&lt;/p&gt;

&lt;p&gt;We collect the categorical judgments of the form \(A~{\it true}\) into &lt;i&gt;true contexts&lt;/i&gt; which are written as \(\Gamma\) or \(\Psi\), and we collect the categorical judgments of the form \(A~{\it valid}\) into &lt;i&gt;valid contexts&lt;/i&gt; which are written as \(\Delta\). It is by use of contexts that categorical judgments give rise to &lt;i&gt;hypothetical judgments&lt;/i&gt;, and Pfenning-Davies modal logic has two hypothetical judgments: \(\seq{\Delta}{A~{\it valid}}\) and \(\seq{\Delta; \Gamma}{A~{\it true}}\)&lt;/p&gt;

&lt;p&gt;In a system with hypothetical judgments, meaning is given by describing three kinds of principles: the weakening principles (expressing how the context works), the identity principles (expressing how assumptions are used), and the substitution principles (expressing how assumptions are discharged). We rely on these principles as we explain a logic, and we are required to tie the knot eventually, demonstrating that our logic's particular rules satisfy its defining principles. Here are the defining principles for Pfenning-Davies modal logic:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Weakening principles&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;If \(\Delta \subseteq \Delta'\) and \(\seq{\Delta}{A~{\it valid}}\), then \(\seq{\Delta'}{A~{\it valid}}\)&lt;/li&gt;
&lt;li&gt;If \(\Delta \subseteq \Delta'\), \(\Gamma \subseteq \Gamma'\), and \(\seq{\Delta; \Gamma}{A~{\it true}}\), then \(\seq{\Delta'; \Gamma'}{A~{\it true}}\)&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Identity/hypothesis principles&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;\(\seq{\Delta, A~{\it valid}}{A~{\it valid}}\)&lt;/li&gt;
&lt;li&gt;\(\seq{\Delta; \Gamma, A~{\it true}}{A~{\it true}}\)&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Substitution principles&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;If \(\seq{\Delta}{A~{\it valid}}\) and \(\seq{\Delta, A~{\it valid}}{C~{\it valid}}\), then \(\seq{\Delta}{C~{\it valid}}\).&lt;/li&gt;
&lt;li&gt;If \(\seq{\Delta}{A~{\it valid}}\) and \(\seq{\Delta, A~{\it valid}; \Gamma}{C~{\it true}}\), then \(\seq{\Delta; \Gamma}{C~{\it true}}\).&lt;/li&gt;
&lt;li&gt;If \(\seq{\Delta; \Gamma}{A~{\it true}}\) and \(\seq{\Delta; \Gamma, A~{\it true}}{C~{\it true}}\), then \(\seq{\Delta; \Gamma}{C~{\it true}}\).&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;

&lt;p&gt;Two judgmental rules define the fundamental relationship between the vaildity and truth judgments; I'll call the first of these rules &lt;i&gt;valid introduction&lt;/i&gt; and the second &lt;i&gt;valid elimination&lt;/i&gt;; they capture the notion that validity is defined relative to truth, and that validity is truth in all contexts.&lt;/p&gt;

The fundamental relationship between truth and validity is set up by two rules, which express that &lt;i&gt;validity is unconditional truth&lt;/i&gt;. This means that \(A~{\it valid}\) should be entailed by \(A~{\it true}\) in the absence of any conditions, and that proving \(A~{\it valid}\) should entail \(A~{\it true}\) in any conditions, where "conditions" are represented by the context \(\Gamma\) of true hypotheses.The first rule is the introduction rule for validity: it shows how we &lt;i&gt;verify&lt;/i&gt; the judgment \(A~{\it valid}\). The second rule is the elimination rule for validity: it shows that, given a proof of \(A~{\it valid}\), we can use it to show the truth of \(A\) in any context \(\Gamma\).&lt;/p&gt;

\[
\infer
 {\seq{\Delta}{A~{\it valid}}}
 {\seq{\Delta; \cdot}{A~{\it true}}}
\qquad
\infer
 {\seq{\Delta; \Gamma}{A~{\it true}}} 
 {\seq{\Delta}{A~{\it valid}}}
\]

&lt;p&gt;The validity judgment is made interesting by its use in defining modal necessity \(\Box A\). Notice how similar the &lt;i&gt;introduction&lt;/i&gt; rule for modal necessity is to the &lt;i&gt;elimination&lt;/i&gt; rule for the validity judgment! The elimination rule, however, acts like a let- or case-expression; it is the kind of elimination rule known as a &lt;i&gt;large elimination&lt;/i&gt;, which are associated with the positive connectives (if you're a fan of polarized logic).&lt;/p&gt;

\[
\infer
 {\seq{\Delta; \Gamma}{\Box A~{\it true}}}
 {\seq{\Delta}{A~{\it valid}}}
\qquad
\infer
 {\seq{\Delta; \Gamma}{C~{\it true}}}
 {\seq{\Delta; \Gamma}{\Box A~{\it true}} 
  &amp;
  \seq{\Delta, A~{\it valid}; \Gamma}{C~{\it true}}}
\]

&lt;h3&gt;A truth-oriented justification of logic&lt;/h3&gt;

&lt;p&gt;This story above is (I believe) broadly compatible with the story from Pfenning and Davies' original paper; certainly what I called the introduction and elimination rules for validity are just the result of writing down the "Definition of Validity" at the beginning of Section 4 of their paper. However, Pfenning and Davies banish the second half of the definition of validity, what I called the elimination rule, from their actual formal system. In its place, they give a valid hypothesis rule, variously written as \(uhyp\) or \(hyp^*\).&lt;/p&gt;

\[
\infer
 {\seq{\Delta, A~{\it valid}; \Gamma}{A~{\it true}}} 
 {}
\]

&lt;p&gt;With this change, the introduction rule for validity now only appears in the conclusion of the validity introduction rule and the premise of the \(\Box\) introduction rule, and the two can be collapsed together. The introduction rule for validity is what is called &lt;i&gt;invertible&lt;/i&gt; - the conclusion implies the premise - so we don't fundamentally change the \(\Box\) introduction rule if we replace the premise \(\seq{\Delta}{A~{\it valid}}\) with the equivalent premise \(\seq{\Delta; \cdot}{A~{\it true}}\). &lt;/p&gt;

\[
\infer
 {\seq{\Delta; \Gamma}{\Box A~{\it true}}}
 {\seq{\Delta; \cdot}{A~{\it true}}}
\]

&lt;p&gt;These changes to the logical system, write Pfenning and Davies, are &lt;i&gt;sound&lt;/i&gt; with respect to the initial definitions I gave (the \(uhyp\) rule, in particular, is derivable by a combination of the valid hypothesis principle and the elimination rule for validity). However, the resulting system is incomplete with respect to the categorical judgment \(A~{\it valid}\). This necessitates that we give up on the one hypothesis principle and one substitution principle that deal exclusively with validity, and also edit the substitution principle with a premise \(\seq{\Delta}{A~{\it valid}}\) to have the premise \(\seq{\Delta; \cdot}{A~{\it true}}\) instead.&lt;/p&gt;

&lt;p&gt;These changes flow naturally out of the intentional goal of explaining the meaning of the logical connectives &lt;i&gt;entirely&lt;/i&gt; through the lens of the categorical judgment \(A~{\it true}\). This is a perfectly fine way of explaining S4 modal logic, but I don't see it as a fundamental part of the character of judgmental presentations of logic. For instance, there are plenty of situations, (Hybrid LF, Simpson's IK, Constructive Provability Logic) where there is no single categorical judgement for truth, but rather a whole family of indexed judgments, and it's possible to prove things at each of the judgments. This suggests a different story, a different presentation of the same system above. This presentation is one that I've adapted from Jason Reed [&lt;a href="#ak4"&gt;4&lt;/a&gt;].&lt;/p&gt;

&lt;h3&gt;Another story&lt;/h3&gt;

&lt;p&gt;If one is perhaps less interested in the correspondence to modal logic, it's possible to take the judgmental setup that we started with and tease apart the notion of modal necessity just a bit. We do this by introducing two connectives, \(\unicode{x25F8}A\) and \(\unicode{x25FF}A\), with the intentional visual pun that \(\unicode{x25F8}\!\!\!\!\unicode{x25FF} A = \Box A\). The introduction and elimination rules for validity are now properly understood as introduction and elimination rules for \(\unicode{x25FF}\), whereas the introduction and elimination rules for \(\Box\) are now understood as introduction and elimination rules for \(\unicode{x25F8}\).&lt;/p&gt;

\[
\infer
 {\seq{\Delta}{\unicode{x25FF}A~{\it valid}}}
 {\seq{\Delta; \cdot}{A~{\it true}}}
\qquad
\infer
 {\seq{\Delta; \Gamma}{A~{\it true}}} 
 {\seq{\Delta}{\unicode{x25FF}A~{\it valid}}}
\]
\[
\infer
 {\seq{\Delta; \Gamma}{\unicode{x25F8}A~{\it true}}}
 {\seq{\Delta}{A~{\it valid}}}
\qquad
\infer
 {\seq{\Delta; \Gamma}{C~{\it true}}}
 {\seq{\Delta; \Gamma}{\unicode{x25F8}A~{\it true}} 
  &amp;
  \seq{\Delta, A~{\it valid}; \Gamma}{C~{\it true}}}
\]

&lt;p&gt;Now, if these rules are really the only ones that deal with validity &amp;mdash; if all the "regular" connectives like implication are defined the traditional way based only on truth...&lt;/p&gt;

\[
\infer
 {\seq{\Delta; \Gamma}{A \supset B~{\it true}}}
 {\seq{\Delta; \Gamma, A~{\it true}}{B~{\it true}}}
\qquad
\infer
 {\seq{\Delta; \Gamma}{B~{\it true}}} 
 {\seq{\Delta; \Gamma}{A \supset B~{\it true}}
  &amp;
  \seq{\Delta; \Gamma}{A~{\it true}}}
\]

&lt;p&gt;...then it is possible to observe that this way in which we have teased apart box into two parts actually &lt;i&gt;syntactically differentiates&lt;/i&gt; the propositions judged by the two categorical judgments: if we're starting from truth, we'll only introduce propositions that live under a \(\unicode{x25F8}\), and we can only meaningfully use valid propositions that have \(\unicode{x25FF}\) as their outermost connective. This observation, which I picked up from by Jason Reed, makes it possible to talk about true propositions - those propositions judged as true \((A ::= \unicode{x25F8}P \mid A \supset B \mid a )\) separately from valid propositions - those propositions judged valid \((P ::= \unicode{x25FF}A)\) [&lt;a href="#ak4"&gt;4&lt;/a&gt;]. The rules that we have set up essentially enforce this syntactic separation already, however; there's no particular requirement that we enforce it on our own.&lt;/p&gt;

&lt;p&gt;In fact, one thing we can do is put another version of implication "up at validity," like this:&lt;/p&gt;

\[
\infer
 {\seq{\Delta}{A \supset B~{\it valid}}}
 {\seq{\Delta, A~{\it valid}}{B~{\it valid}}}
\qquad
\infer
 {\seq{\Delta}{B~{\it valid}}} 
 {\seq{\Delta}{A \supset B~{\it valid}}
  &amp;
  \seq{\Delta}{A~{\it valid}}}
\]

&lt;p&gt;It's not terribly obvious why you'd want to do this, but as Neel points out to me in the comments, this was first done in the context of &lt;i&gt;linear&lt;/i&gt; logic by Wadler and Benton, where it turns out to be quite useful for programming [&lt;a href="#ak5"&gt;5&lt;/a&gt;,&lt;a href="#ak6"&gt;6&lt;/a&gt;]. I was previously unaware of that work (doh). Reed used the idea of putting implication up at validity in order to describe both the necessity modality and the lax-logic circle (the "monad") as fragments of the same logic, which is where I got this notion from. If you ignore the "valid" implication, you get modal logic with \(\Box A = \unicode{x25F8}\!\!\!\!\unicode{x25FF} A\), but if you ignore the "true" implication and instead reason at "validity" (at which point it's definitely not quite right to call the old "validity" validity anymore), you get lax logic with \(\bigcirc A = \unicode{x25FF} \unicode{x25F8} A\). That observation is essentially the same one made by the two translations in Figure 6 of Wander and Benton's paper, though again Wadler and Benton's  "truth" judgment was linear, the one I've presented here was persistent, and Reed considered both variants [&lt;a href="#ak6"&gt;6&lt;/a&gt;].&lt;/p&gt;

&lt;p&gt;To reiterate, this isn't a very useful story if one is interested in giving a fundamental account of modal logic, but I believe that "teasing apart" the modal operator, and even opening up the possibility of inserting other propositions in the space of "valid propositions" that such a teasing apart naturally create, raises interesting possibilities. Hopefully in the next post I'll say about about that in the context of contextual modal type theory (CMTT).&lt;/p&gt;

&lt;hr/&gt;
&lt;small&gt;
&lt;a name="ak1"&gt;&lt;/a&gt; [1] Frank Pfenning and Rowan Davies, "A Judgmental Reconstruction of Modal Logic," 1999 (published 2001)&lt;br/&gt;
&lt;a name="ak2"&gt;&lt;/a&gt; [2] Per Martin-L&amp;ouml;f, "On the Meanings of the Logical Constants and the Justifications of the Logical Laws" a.k.a. "The Siena Lectures," 1983 (published 1996)&lt;br/&gt;
&lt;a name="ak3"&gt;&lt;/a&gt; [3] Robert J. Simmons and Bernardo Toninho, "Principles of Constructive Provability Logic," CMU Tech Report 2010.&lt;br/&gt;
&lt;a name="ak4"&gt;&lt;/a&gt; [4] Jason Reed, "A Judgmental Deconstruction of Modal Logic," unpublished 2009.&lt;br/&gt;
&lt;a name="ak5"&gt;&lt;/a&gt; [5] Nick Benton, "A Mixed Linear and Non-Linear Logic: Proofs, Terms and Models," CSL 1995.&lt;br/&gt;
&lt;a name="ak6"&gt;&lt;/a&gt; [6] Nick Benton and Phil Wadler, "Linear Logic, Monads and the Lambda  Calculus," LICS 1996.
&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-1593913029104389616?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/_V1E9FTBqE8" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/1593913029104389616/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/10/slicing-and-dicing-validity-old-ideas.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/1593913029104389616?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/1593913029104389616?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/_V1E9FTBqE8/slicing-and-dicing-validity-old-ideas.html" title="Slicing and dicing validity: existing ideas" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/10/slicing-and-dicing-validity-old-ideas.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUQER3g6fCp7ImA9WhdUEkg.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-8388872177851734659</id><published>2011-09-27T16:05:00.000-04:00</published><updated>2011-09-28T20:48:26.614-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-28T20:48:26.614-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="logical frameworks" /><category scheme="http://www.blogger.com/atom/ns#" term="Agda" /><category scheme="http://www.blogger.com/atom/ns#" term="Twelf" /><category scheme="http://www.blogger.com/atom/ns#" term="focusing" /><category scheme="http://www.blogger.com/atom/ns#" term="papers" /><category scheme="http://www.blogger.com/atom/ns#" term="logic" /><title>My New Focalization Technique is Unstoppable</title><content type="html">&lt;p&gt;While it took, as they say, a bit of &lt;i&gt;doing&lt;/i&gt;, I have a completed draft of a paper on my website that I believe provides a really elegant solution to what has been a very, very annoying problem for some time: writing down a proof called the &lt;i&gt;completeness of focusing&lt;/i&gt;. Don't worry, the paper explains what that means: it has to, because one of the things the paper argues is that most existing statements of the completeness of focusing aren't general enough! In the process, this writeup gave me a good (enough) excuse to talk in a very general way about a lot of fundamental phenomena around the idea of polarization in logic that we've been noticing in recent years.&lt;/p&gt;

&lt;p&gt;Anyway, the draft is here - &lt;a href="http://www.cs.cmu.edu/~rjsimmon/drafts/focus.pdf"&gt;Structural Focalization&lt;/a&gt;. The accompanying Twelf development is, of course, on the Twelf wiki: &lt;a href="http://twelf.org/wiki/Focusing"&gt;Focusing&lt;/a&gt;. I've thrown the paper and the Twelf code up &lt;a href="http://arxiv.org/abs/1109.6273"&gt;on arXiv&lt;/a&gt; while I figure out while I figure out what to do with it; comments would be greatly appreciated!&lt;/p&gt;

&lt;p&gt;I don't want to have a post that's just "hey here's a paper," so here's an addition, a follow-up to the rather popular "&lt;a href="http://requestforlogic.blogspot.com/2010/11/totally-nameless-representation.html"&gt;Totally Nameless Representation&lt;/a&gt;" post from awhile back. I still prove weakening in Agda by exactly the technique presented there, which commenter &lt;a href="http://requestforlogic.blogspot.com/2010/11/totally-nameless-representation.html?showComment=1290006178509#c6945219533548833041"&gt;thecod&lt;/a&gt; called the "presheaf method." But for natural deduction systems, I almost never use the term metric approach that was the core of what I was presenting in "totally nameless representation," since it works just fine to use the approach where term &lt;tt&gt;M&lt;/tt&gt; of type &lt;tt&gt;A&lt;/tt&gt; (the one you're substituting for &lt;tt&gt;x&lt;/tt&gt;) is in context &lt;tt&gt;&amp;Gamma;&lt;/tt&gt; and the term &lt;tt&gt;N&lt;/tt&gt; (the one with &lt;tt&gt;x&lt;/tt&gt; free) is in context &lt;tt&gt;&amp;Gamma;' ++ A :: &amp;Gamma;&lt;/tt&gt; - the free variable &lt;tt&gt;x&lt;/tt&gt; is allowed to be in the middle of the context, in other words; you don't have to use exchange on the second term, so you're always calling induction on something Agda recognizes as structurally smaller.&lt;/p&gt;

&lt;p&gt;This worked for natural deduction systems, but I didn't think it would work for sequent calculi, since you needed to toy around with both contexts and induct on both terms in presentation of cut for a sequent calculus. However, for a focused sequent calculus like what I present in the paper, you still can do without the totally nameless metric! If you set things up right, the &lt;i&gt;rightist&lt;/i&gt; substitutions (where you work on decomposing the right term, the one with the variable free) allow you to extend the context only of the first term, and the &lt;i&gt;leftist&lt;/i&gt; substitutions (where you work on decomposing the left term, the one you're substituting for the variable) allow you to work on the second term, and the two are only connected by the &lt;i&gt;principal&lt;/i&gt; substitutions (which reduce the type, which more or less lets you get away with anything as far as the induction principle is concerned).&lt;/p&gt;

&lt;p&gt;A code example of this, which could use some more commentary, can be found on GitHub: &lt;a href="https://github.com/robsimmons/agda-lib/blob/lambdatown/Polar.agda"&gt;Polar.agda&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-8388872177851734659?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/HG_AnSotbIQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/8388872177851734659/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/09/my-new-focalization-technique-is.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8388872177851734659?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8388872177851734659?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/HG_AnSotbIQ/my-new-focalization-technique-is.html" title="My New Focalization Technique is Unstoppable" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/09/my-new-focalization-technique-is.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8EQHk4cCp7ImA9WhdWFU0.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-2874178580549035204</id><published>2011-09-08T14:00:00.000-04:00</published><updated>2011-09-08T14:00:01.738-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-08T14:00:01.738-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="approximation" /><category scheme="http://www.blogger.com/atom/ns#" term="predicate abstraction" /><category scheme="http://www.blogger.com/atom/ns#" term="imperative programming" /><title>Nondeterministic thoughts on nondeterminism</title><content type="html">&lt;p&gt;So if you've been hanging around lately, I've been writing posts where I &lt;i&gt;think&lt;/i&gt; I'm talking about new ideas. (&lt;a href="http://requestforlogic.blogspot.com/2011/08/holey-data-postscript-hole-abstraction.html"&gt;I'm not always correct.&lt;/a&gt;) This post, on the other hand, is definitely more a review-and-synthesis sort of post; mostly stuff I gleaned over the summer from reading up on Dijkstra's &lt;a href="http://en.wikipedia.org/wiki/Guarded_Command_Language"&gt;GCL&lt;/a&gt;, Ball et al.'s &lt;a href="http://dl.acm.org/citation.cfm?id=378846"&gt;Automatic predicate abstraction of C programs&lt;/a&gt;, and a number of K. Rustan M. Leino's &lt;a href="http://research.microsoft.com/en-us/um/people/leino/papers.html"&gt;papers&lt;/a&gt; as synthesized for me by my advisors Aditya Nori and Sriram Rajamani at Microsoft Research India.&lt;/p&gt;

&lt;p&gt;The first section represents my somewhat simplistic thoughts on other's people's work in the semantics of imperative programming languages, mostly thoughts I had this summer at MSR. I hope they are merely naive and simplistic and not actively wrong, and that you (gentle reader) will have patience to correct me where I am actively wrong. Then I have three short, mostly unrelated discussions that I needed to clear out of my head. The first discussion reviews a neat way of understanding loop invariants, due to Leino. The second talks about the algebraic properties of non-deterministic programs. The third discussion tries to relate nondeterminism to the work I'm doing on representing transition systems in linear logic, though it's mostly just speculative and may not make sense to anyone but me in its current half-baked form.&lt;/p&gt;

&lt;h2&gt;C programs and their abstractions&lt;/h2&gt;

&lt;p&gt;Our starting point will be, essentially, a generic while language that we'll write with C-like syntax. Here's a program:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 1 */
  1. if(x &gt; 0) {
  2.   x += 5;
  3. } else {
  4.   x = -x - 2;
  5. }
  6. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The thing about a (fully-defined) C program is that it's &lt;i&gt;deterministic&lt;/i&gt; - for any initial assignments to variables, there's a unique behavior. So, for the above program, if the initial value of &lt;tt&gt;x&lt;/tt&gt; is, say, 4, then the program will execute line 1 (with &lt;tt&gt;x&lt;/tt&gt;=4), then line 2 (with &lt;tt&gt;x&lt;/tt&gt;=4), then line 6 (with &lt;tt&gt;x&lt;/tt&gt;=9&lt;/tt&gt;), and the program will then return 9. If the initial value of &lt;tt&gt;x&lt;/tt&gt; is -12, then the program will execute line 1 (with &lt;tt&gt;x&lt;/tt&gt;=-12), then line 4 (with &lt;tt&gt;x&lt;/tt&gt;=-12), then line 6 (with &lt;tt&gt;x&lt;/tt&gt;=10&lt;/tt&gt;), and the program will then return 10. I've now implicitly told you what what counts as a "behavior" - it's a stream of line numbers and states that may or may not end with a returned value. So the meaning of a program is a function from initial states to &lt;i&gt;streams&lt;/i&gt; of line numbers and states.&lt;/p&gt;

&lt;p&gt;We can even think of the line numbers as a convenient fiction: we could translate the program above into this form:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;   linenum = 1;
   &lt;span style="color:#0cc"&gt;checkpoint();&lt;/span&gt;
   if(x &gt; 0) {
     linenum = 2;
     &lt;span style="color:#0cc"&gt;checkpoint();&lt;/span&gt;
     x += 5;
   } else {
     linenum = 4;
     &lt;span style="color:#0cc"&gt;checkpoint();&lt;/span&gt;
     x = -x - 2;
   }
   linenum = 6;
   &lt;span style="color:#0cc"&gt;checkpoint();&lt;/span&gt;
   return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Then we say that the behavior of a program is a function from initial states to the stream of intermediate states as reported by the special &lt;tt&gt;&lt;span style="color:#0cc; font-weight:bold"&gt;checkpoint()&lt;/span&gt;&lt;/tt&gt; function; the "line number" part of the stream is just handled by the value associated with &lt;tt&gt;linenum&lt;/tt&gt; in the memory state.&lt;/p&gt;

&lt;p&gt;So that's the meaning (the &lt;i&gt;denotation&lt;/i&gt;) that I choose for deterministic C programs: they're functions from initial states to streams of states (where the state includes the line number). From here on out I'll just think of any given deterministic C program as a way of specifying one such function. There are also many such functions that can't be written down appropriately with the syntax of a C program; that's not my concern here.&lt;/p&gt;

&lt;h3&gt;Nondeterminism&lt;/h3&gt;

&lt;p&gt;Instead, I want to talk about non-deterministic C programs. The meaning of a nondeterministic C program is a function from initial states to &lt;i&gt;sets&lt;/i&gt; of streams of states,&lt;sup&gt;&lt;a href="#alg-foot1"&gt;1&lt;/a&gt;&lt;/sup&gt; and the syntax we'll use to write down nondeterministic C programs is an extension of the syntax of deterministic C programs. This means, of course, that there's a trivial inclusion of deterministic C programs into nondeterministic C programs.&lt;/p&gt;

&lt;p&gt;The easiest way to come up with nondeterministic C programs (which represent sets of functions from initial states to streams) is to turn &lt;tt&gt;if&lt;/tt&gt; branches into nondeterministic branches. The standard way that the C model checking folks represent nondeterministic choice is to write &lt;tt&gt;if(*)&lt;/tt&gt;. Here's an example:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 2 */
  1. if(*) {
  2.   x += 5;
  3. } else {
  4.   x = -x - 2;
  5. }
  6. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;tt&gt;*&lt;/tt&gt;, near as I can tell, was chosen to resemble the "wildcard" symbol, since &lt;i&gt;any&lt;/i&gt; boolean expression we put in that &lt;tt&gt;if&lt;/tt&gt; statement (such as &lt;tt&gt;x &gt; 0&lt;/tt&gt; to recover our Example 1) results in a program that refines Example 2. (Terminology: a program &lt;i&gt;refines&lt;/i&gt; another if, for every initial state, every stream in the meaning of the more-refined program also belongs to the meaning of the less-refined program.)&lt;/p&gt;

&lt;h3&gt;Assume/impossible&lt;/h3&gt;

&lt;p&gt;Nondeterministic choice allows us to &lt;i&gt;enlarge&lt;/i&gt; the meaning of a nondeterministic program. Inserting &lt;tt&gt;assume()&lt;/tt&gt; statements will &lt;i&gt;cut down&lt;/i&gt; the set of streams in the meaning of a nondeterministic program. In particular, we have to exclude any streams that would, for any initial state, violate an assumption. We therefore have to be careful that we don't cut down the set of streams so far that there aren't any left: there are no deterministic programs that refine &lt;tt&gt;assume(false)&lt;/tt&gt; - every initial state maps to the empty set of streams. For that matter, there also aren't any deterministic programs that refine Example 3:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 3 */
  1. assume(x &gt; 0);
  2. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;For every initial state where the value of &lt;tt&gt;x&lt;/tt&gt; is positive, the meaning of Example 3 is a set containing only the stream that goes to line one, then line two, then returns the initial value of &lt;tt&gt;x&lt;/tt&gt;. For every initial state where the value of &lt;tt&gt;x&lt;/tt&gt; is not positive, the meaning of the program has to be the empty set: any stream would immediately start by violating an assumption.&lt;/p&gt;

&lt;p&gt;Assumptions were used in Ball et al.'s "Automatic predicate abstraction of C programs" paper, which explains part of the theory behind the SLAM software verifier. In that work, they got rid of &lt;i&gt;all&lt;/i&gt; of the &lt;tt&gt;if&lt;/tt&gt; statements as a first step, replacing them with nondeterministic choices immediately followed by assumptions.&lt;sup&gt;&lt;a href="#alg-foot2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 4 */
  1. if(*) {
       assume(x &gt; 0);
  2.   x += 5;
  3. } else {
       assume(x &lt;= 0);
  4.   x = -x - 2;
  5. }
  6. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The program in Example 4 is basically a degenerate nondeterministic program: its meaning is exactly equivalent to the deterministic Example 1.

On the other hand, if we remove the statement &lt;tt&gt;assume(x &lt;= 0)&lt;/tt&gt; after line 3 in Example 4, we have a nondeterministic program that is refined by many deterministic programs. For instance, the deterministic program in Example 1 refines Example 4 without the &lt;tt&gt;assume(x &lt;= 0)&lt;/tt&gt;, but so do Examples 5 and 6:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 5 */
  1. x = x;
  4. x = -x - 2;
  6. return x;

  /* Example 6 */
  1. if(x &gt; 100) {
  2.   x += 5;
  3. } else { 
  4.   x = -x - 2;
  5. }
  6. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Example 4 as it was presented shows how &lt;tt&gt;assume()&lt;/tt&gt; together with nondeterministic choice can encode normal &lt;tt&gt;if&lt;/tt&gt; statements. We could also define an statement &lt;tt&gt;impossible&lt;/tt&gt; and say that a stream just cannot ever reach an &lt;tt&gt;impossible&lt;/tt&gt; statement. Impossibility can be defined in terms of &lt;tt&gt;assume&lt;/tt&gt; - &lt;tt&gt;impossible&lt;/tt&gt; is equivalent to &lt;tt&gt;assume(false)&lt;/tt&gt;. Alternatively, we can use impossibility to define assumptions - &lt;tt&gt;assume(e)&lt;/tt&gt; is equivalent to &lt;tt&gt;if(e) { impossible; }&lt;/tt&gt;. So there's a bit of a chicken-and-egg issue: I'm not totally sure whether we should build in &lt;tt&gt;impossible&lt;/tt&gt;/&lt;tt&gt;if&lt;/tt&gt; combination and use it to define &lt;tt&gt;assume()&lt;/tt&gt; or whether we should build in &lt;tt&gt;assume()&lt;/tt&gt; and use it to define &lt;tt&gt;impossible&lt;/tt&gt; and &lt;tt&gt;if&lt;/tt&gt; statements. It probably doesn't matter.&lt;/p&gt;

&lt;h3&gt;Assert/abort&lt;/h3&gt;

&lt;p&gt;In "Automatic predicate abstraction of C programs," &lt;tt&gt;assert()&lt;/tt&gt; statements are understood to be the things that are supposed to be avoided. However, in Leino's work, they have a meaning of absolute and unbounded nondeterminism, which is the interpretation I want to use. If the expression &lt;tt&gt;e&lt;/tt&gt; in an &lt;tt&gt;assert(e)&lt;/tt&gt; statement evaluates to false, anything can happen - it's as if we could jump to an arbitrary point in memory and start executing code; absolutely any deterministic program that refines a nondeterministic program up to the point where the nondeterministic program fails an assertion will definitely refine that nondeterministic program.&lt;/p&gt;

&lt;p&gt;So &lt;tt&gt;assert()&lt;/tt&gt; represents unbounded nondeterminism: and in the sense of "jump to any code," not just in the sense of "replace me with any code" - the program &lt;tt&gt;assert(false); while(true) {}&lt;/tt&gt; is refined by every program, including ones that terminate. This interpretation is easy to connect to the SLAM interpretation where we say "assertion failures are to be avoided," since obviously one of the things you might prove about your C code is that it doesn't jump to arbitrary code and start executing it.&lt;/p&gt;

&lt;p&gt;Analogy: &lt;tt&gt;assert()&lt;/tt&gt; is to &lt;tt&gt;abort&lt;/tt&gt; as &lt;tt&gt;assume()&lt;/tt&gt; is to &lt;tt&gt;impossible&lt;/tt&gt; - we can define &lt;tt&gt;assert(e);&lt;/tt&gt; as &lt;tt&gt;if(e) { abort; }&lt;/tt&gt;.

&lt;h2&gt;Abstracting loops&lt;/h2&gt;

&lt;p&gt;The three primitives we have discussed so far are almost enough to let us perform a fun trick that my advisors at MSR attribute to Leino. First, though, we need one more primitive, a "baby" form of assert/abort called &lt;tt&gt;havoc(x)&lt;/tt&gt;, which allows the value associated with the variable &lt;tt&gt;x&lt;/tt&gt; to be changed in any way. In other words, a program with the statement &lt;tt&gt;havoc(x)&lt;/tt&gt; is refined by the program where the statement &lt;tt&gt;havoc(x)&lt;/tt&gt; is replaced by the statement &lt;tt&gt;x = 4&lt;/tt&gt;, the statement &lt;tt&gt;x = x - 12&lt;/tt&gt;, the statement &lt;tt&gt;x = y - 16&lt;/tt&gt;, or even the statement &lt;tt&gt;if(z) { x = y; } else { x = w; }&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Given the &lt;tt&gt;havoc&lt;/tt&gt; primitive, imagine we have a program with a loop, and no checkpoints inside the loop:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  1. /* Before the loop */
     while(e) {
       ... loop body, 
        which only assigns 
        to variables x1,...,xn ...
     }
  2. /* After the loop */&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Say we know the following two things: 
&lt;ul&gt;
&lt;li&gt;The loop will always terminate if the expression &lt;tt&gt;e_inv&lt;/tt&gt; evaluates to true at line 1, and&lt;/li&gt;
&lt;li&gt;From any state where &lt;tt&gt;e_inv&lt;/tt&gt; and &lt;tt&gt;e&lt;/tt&gt; both evaluate to true, after the loop body is run, &lt;tt&gt;e_inv&lt;/tt&gt; will evaluate to true.
&lt;/ul&gt;
Then, we know the program above refines the following program:&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  1. /* Before the loop */
     assert(e_inv);
     havoc(x1); ... havoc(xn);
     assume(e_inv &amp;&amp; !e);
  2. /* After the loop */&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This is a somewhat unusual way of looking at loop invariants: we can take a loop and abstract it with nondeterministic straight line code. If we get to the beginning of the loop and our loop invariant is violated, all hell breaks loose, but if the loop invariant holds at the beginning, then when we exit the loop we know the following things: variables not assigned to by the loop haven't changed, the loop invariant holds, and the negation of the loop guard holds.&lt;/p&gt;

&lt;p&gt;I like this particular game: it's a non-traditional way of looking at the analysis of loops by asking "is this program abstraction sound."&lt;/p&gt;

&lt;h2&gt;Algebraic structure of non-determinism&lt;/h2&gt;

&lt;p&gt;Notice that &lt;tt&gt;assume(false)&lt;/tt&gt; is the &lt;b&gt;unit&lt;/b&gt; of non-deterministic choice: writing the nondeterministic program &lt;tt&gt;if(*) assume(false); else Stmt&lt;/tt&gt; is, in all program contexts, the same as writing just &lt;tt&gt;Stmt&lt;/tt&gt;. Furthermore, nondeterministic choice is commutative (&lt;tt&gt;if(*) Stmt1; else Stmt2;&lt;/tt&gt; is equivalent to &lt;tt&gt;if(*) Stmt2; else Stmt1;&lt;/tt&gt;) and associative (it doesn't matter how I nest nondeterministic choices if I want to make a three-way nondeterministic choice). This means that nondeterministic choice and the &lt;tt&gt;impossible&lt;/tt&gt; statement (which is equivalent to &lt;tt&gt;assume(false)&lt;/tt&gt;) form a &lt;i&gt;monoid&lt;/i&gt; - it's like the wildcard &lt;tt&gt;*&lt;/tt&gt; could also be interpreted as multiplication, and we could write &lt;tt&gt;if(*) Stmt2; else Stmt1;&lt;/tt&gt; as &lt;tt&gt;Stmt1 &amp;times; Stmt2&lt;/tt&gt; and write &lt;tt&gt;impossible&lt;/tt&gt; as &lt;tt&gt;1&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore, &lt;tt&gt;if(*) assert(false); else Stmt&lt;/tt&gt; is a nondeterministic program that is refined by every program, since &lt;tt&gt;assert(false)&lt;/tt&gt; refines every program and we can just use the "wildcard" reading of nondeterminism to replace &lt;tt&gt;*&lt;/tt&gt; with &lt;tt&gt;true&lt;/tt&gt;. Algebraically, this means that the &lt;tt&gt;abort&lt;/tt&gt; statement (which is equivalent to &lt;tt&gt;assert(false)&lt;/tt&gt;) &lt;i&gt; annihilates &lt;/i&gt; nondeterminism - we could write &lt;tt&gt;impossible&lt;/tt&gt; as &lt;tt&gt;0&lt;/tt&gt;, and then we have &lt;tt&gt;0 &amp;times; Stmt = Stmt &amp;times; 0 = 0&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Is &lt;tt&gt;abort&lt;/tt&gt; the unit of a binary operation &lt;tt&gt;Stmt1 &amp;plus; Stmt2&lt;/tt&gt; in the same way that the number 0 is the unit of addition? It's not clear that it's useful for the abstraction of C programs, but I think if we go looking for a binary operation that &lt;tt&gt;abort&lt;/tt&gt; is the unit of, what we'll find is perhaps best called &lt;tt&gt;both&lt;/tt&gt;.&lt;/p&gt;

&lt;h3&gt;Both-and statements&lt;/h3&gt;

&lt;p&gt;The &lt;tt&gt;both&lt;/tt&gt; statement is a weird statement that allows us to complete the picture about the algebraic structure of &lt;tt&gt;abort/assert(false)&lt;/tt&gt;, &lt;tt&gt;impossible/assume(false)&lt;/tt&gt; and &lt;tt&gt;if(*)&lt;/tt&gt;. A deterministic program only refines the program &lt;tt&gt;both Stmt1 and Stmt2&lt;/tt&gt; if it refines both &lt;tt&gt;Stmt1&lt;/tt&gt; and &lt;tt&gt;Stmt2&lt;/tt&gt;. As an example the program below is exactly equivalent to Example 1 - the first statement forces all streams starting from initial states where &lt;tt&gt;x&lt;/tt&gt; is not positive to hit line 4 and not line 2 (lest they violate the &lt;tt&gt;assume(x &gt; 0)&lt;/tt&gt;, and the second statement forces the initial states where &lt;tt&gt;x&lt;/tt&gt; is positive to hit line 2 and not line 4 (lest they violate the &lt;tt&gt;assume(x &lt;= 0)&lt;/tt&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;span style="color:#000; font-weight:bold"&gt;  /* Example 7 */
     both {
  1.   if(*) {
         assume(x &gt; 0);
  2.     x += 5;
  3.   } else {
  4.     x = -x - 2;
  5.   }
     } and {
  1.   if(*) {
  2.     x += 5;
  3.   } else {
         assume(x &lt;= 0);
  4.     x = -x - 2;
  5.   }
     }
  6. return x;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;tt&gt;both&lt;/tt&gt; statement is a binary operation whose unit is &lt;tt&gt;abort&lt;/tt&gt;, forming a monad: doing anything at all - as long as it's some specific thing - is the same as doing that specific thing. The &lt;tt&gt;both&lt;/tt&gt; is also annihilated by &lt;tt&gt;impossible&lt;/tt&gt;, because doing nothing as long as it's one specific thing is the same thing as doing nothing. (This is all very fuzzy, but can be made formal in terms of set union and intersection operations.) That's interesting, because &lt;tt&gt;both&lt;/tt&gt; statements aren't really like addition at all: we have two monoids whose the units both annihilate the binary operator that they aren't the unit of. If distributivity works in both directions (I'm not sure it does...) then we have a Boolean algebra without negation (what's that called?).&lt;/p&gt;

&lt;h2&gt;Two linear logic interpretations&lt;/h2&gt;

&lt;p&gt;One of the things that I like to do is to take the state of an evolving machine, encode it as a linear logic context &lt;tt&gt;&amp;Delta;&lt;/tt&gt;, and then say that the linear logic derivability judgment &lt;tt&gt;&amp;Delta; &amp;vdash; A&lt;/tt&gt; proves something about the state. I think there are two ways of doing this for the language semantics I wrote out above. One is familiar, both are interesting.&lt;/p&gt;

&lt;h3&gt;The existential interpretation&lt;/h3&gt;

&lt;p&gt;The way I'm used to thinking about these things is that &lt;tt&gt;&amp;Delta; &amp;vdash; A&lt;/tt&gt; shows that &lt;tt&gt;A&lt;/tt&gt; is a possible (that is, existential) property of the system encoded into the linear logic context &lt;tt&gt;&amp;Delta;&lt;/tt&gt;. In that case, we want to encode nondeterministic as the additive conjunction &lt;tt&gt;A &amp;amp; B&lt;/tt&gt;, as we can execute a nondeterministic choice by taking either choice. We want to encode &lt;tt&gt;impossible&lt;/tt&gt; as &lt;tt&gt;&amp;top;&lt;/tt&gt;, which prevents us from proving anything interesting about a series of nondeterministic choices that lead us to an impossible point in the program. We'll furthermore want to encode &lt;tt&gt;abort&lt;/tt&gt; as &lt;tt&gt;0&lt;/tt&gt;, since once we reach an abort we can prove any existential property that we want to about the program!&lt;/p&gt;

&lt;h3&gt;The universal interpretation&lt;/h3&gt;

&lt;p&gt;Another way of understanding derivability would be to say that &lt;tt&gt;&amp;Delta; &amp;vdash; A&lt;/tt&gt; shows that &lt;tt&gt;A&lt;/tt&gt; is a necessary property of the system encoded into the linear logic context &lt;tt&gt;&amp;Delta;&lt;/tt&gt;. In that case, we would want to encode nondeterministic choice as the additive disjunction &lt;tt&gt;A &amp;oplus; B&lt;/tt&gt;, since to prove that something necessarily holds of a nondeterministically branching program, we have to show that it holds regardless of how the nondeterministic choice is resolved. This ensures that we will have to consider all possible resolutions of nondeterministic choices, but reaching an &lt;tt&gt;impossible&lt;/tt&gt; state means that no programs can get to the current state, so all universal properties hold vacuously. We therefore would want to encode &lt;tt&gt;impossible&lt;/tt&gt; as &lt;tt&gt;0&lt;/tt&gt;. On the other hand, reaching an &lt;tt&gt;abort&lt;/tt&gt; means we know nothing about the universal properties of the program - the program can now do anything - so we encode &lt;tt&gt;abort&lt;/tt&gt; as &lt;tt&gt;&amp;top;&lt;/tt&gt;.&lt;/p&gt;

&lt;hr&gt;
&lt;small&gt;&lt;a name="alg-foot1"&gt;&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt; Note that functions from initial states to sets of streams is *different* than sets of functions from initial states to streams! Both might be valid ways of looking at the meaning of nondeterministic programs depending on how you look at it, in fact, I originally wrote this post think in terms of the other definition.&lt;br/&gt;
&lt;a name="alg-foot2"&gt;&lt;/a&gt;&lt;sup&gt;2&lt;/sup&gt; Certainly Ball et al. didn't come up with this idea - the idea is implicit in the Guarded Command Language; I'm just referring to Ball et al. because I'm sticking with their syntax.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-2874178580549035204?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/18T67YT6ydg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/2874178580549035204/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/09/nondeterministic-thoughts-on.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2874178580549035204?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2874178580549035204?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/18T67YT6ydg/nondeterministic-thoughts-on.html" title="Nondeterministic thoughts on nondeterminism" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/09/nondeterministic-thoughts-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUQER385fSp7ImA9WhdWE08.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-8396248211253792187</id><published>2011-09-06T11:30:00.000-04:00</published><updated>2011-09-06T11:35:06.125-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-09-06T11:35:06.125-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="maps" /><category scheme="http://www.blogger.com/atom/ns#" term="clowns and jokers" /><category scheme="http://www.blogger.com/atom/ns#" term="hole abstraction" /><category scheme="http://www.blogger.com/atom/ns#" term="levy" /><category scheme="http://www.blogger.com/atom/ns#" term="folds" /><title>Clowns to the left of me, jokers to the right, here I am, stuck in a hole abstraction</title><content type="html">Happy day-after-labor-day weekend! This also stems from a discussion I had with &lt;a href="http://www.ccs.neu.edu/home/turon/"&gt;Aaron Turon&lt;/a&gt;, who, a while back with &lt;a href="http://research.microsoft.com/en-us/um/people/crusso/"&gt;Claudio Russo&lt;/a&gt;, also thought about using hole abstractions for maps and folds over data (with some fascinating twists, but I'll leave Aaron and Claudio's twists for Aaron and Claudio).
&lt;br /&gt;
&lt;br /&gt;One of the things Aaron noticed was that it's nice to define a tail-recursive map over trees this way, and indeed that is true. I transliterated some code Aaron wrote out into Levy#: you can see it at &lt;a href="https://github.com/robsimmons/levy/blob/holey/turon.levy"&gt;turon.levy&lt;/a&gt;. The example really starts rubbing against two of the unnecessary deficiencies of Levy# - a lack of polymorphism (the trees have to be integer trees) and a lack of mutual recursion. We really want to define the map in terms of two mutually (tail-)recursive functions &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;moveUp&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;moveDown&lt;/span&gt;&lt;/tt&gt;, both of which take a holey &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt; and a &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree&lt;/span&gt;&lt;/tt&gt; that belongs "in the hole," the difference being that in &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;moveUp&lt;/span&gt;&lt;/tt&gt; I've &lt;i&gt;already&lt;/i&gt; applied the map function to the subtree in the hole, and in &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;moveDown&lt;/span&gt;&lt;/tt&gt; I still need to apply the map function to the subtree in the hole.
&lt;br /&gt;
&lt;br /&gt;This only works for &lt;/i&gt;monomorphic&lt;/i&gt; maps - if we had polymorphism, our hole abstraction zippers would allow us to write maps from &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt; tree&lt;/span&gt;&lt;/tt&gt; to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt; tree&lt;/span&gt;&lt;/tt&gt; using a map function with type &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt; -&gt; F &lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt;&lt;/tt&gt;. It would not allow us to write the maps we're really used to from &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt; tree&lt;/span&gt;&lt;/tt&gt; to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'b&lt;/span&gt; tree&lt;/span&gt;&lt;/tt&gt; using a map function with type &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;&lt;span style="color:#00aaaa; font-weight:bold"&gt;'a&lt;/span&gt; -&gt; F &lt;span style="color:#00aaaa; font-weight:bold"&gt;'b&lt;/span&gt;&lt;/tt&gt;. 
&lt;br /&gt;
&lt;br /&gt;In order to capture more general maps - or &lt;a href="http://en.wikipedia.org/wiki/Fold_(higher-order_function)"&gt;fold/reduce&lt;/a&gt; operations - the non-hole-abstraction approach is to use the generalization of the derivative that Conor McBride describes in &lt;a href="http://strictlypositive.org/CJ.pdf"&gt;clowns to the left of me, jokers to the right&lt;/a&gt;. We observe that a map function like the one in &lt;a href="https://github.com/robsimmons/levy/blob/holey/turon.levy"&gt;turon.levy&lt;/a&gt; sweeps left-to-right through the data structure, always segmenting the data structure into some already-processed "clowns to the left," some not-yet-processed "jokers to the right," and a path through the middle. Then, we either have a sub-tree of clowns, which means we'll now look up for more jokers, or a sub-tree of jokers, which means we need to look down into the jokers to process them. The overall picture is this one:
&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-cj1.png"/&gt;
&lt;br /&gt;
&lt;br /&gt;A nice thing about the hole abstraction framework is that we can represent and dynamically manipulate &lt;i&gt;precisely this picture&lt;/i&gt;, whereas the derivative/zipper approach generally forces one to think about the derivative-like structure from the "inside out." If the jokers are a tree of ints and the clowns are a tree of bools, we can describe them like this:&lt;pre&gt;&lt;span style="color:#009900; font-weight:bold"&gt;   data ILeaf: &lt;span style="color:#0000ff"&gt;int -o itree&lt;/span&gt;&lt;br/&gt;      | IBranch: &lt;span style="color:#0000ff"&gt;itree -o itree -o itree&lt;/span&gt;&lt;br/&gt;&lt;br/&gt;   data BLeaf: &lt;span style="color:#0000ff"&gt;bool -o btree&lt;/span&gt;&lt;br/&gt;      | BBranch: &lt;span style="color:#0000ff"&gt;btree -o btree -o btree&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;Then, the data structure that we will use as a representation of the intermediate state of computation as illustrated above is either stuck in the middle with clowns to the left or stuck in the middle with jokers to the right.&lt;pre&gt;&lt;span style="color:#009900; font-weight:bold"&gt;   data Clowns: &lt;span style="color:#0000ff"&gt;btree -o cj -o cj&lt;/span&gt; &lt;span style="color:#000000"&gt;# Clowns to the left of me&lt;/span&gt;&lt;br/&gt;      | Jokers: &lt;span style="color:#0000ff"&gt;cj -o itree -o cj&lt;/span&gt; &lt;span style="color:#000000"&gt;# Jokers to the right&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;Just like our difference lists from before, there are no closed members of the type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;cj&lt;/span&gt;&lt;/tt&gt;; we can only form values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;cj -o cj&lt;/span&gt;&lt;/tt&gt;. The map implementation can be found at &lt;a href="https://github.com/robsimmons/levy/blob/holey/clownjoker.levy"&gt;clownjoker.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;If we did have polymorphism, the clown/joker data structure for a map would look like this:&lt;pre&gt;&lt;span style="color:#009900; font-weight:bold"&gt;   data Clowns: &lt;span style="color:#0000ff"&gt;&lt;span style="color:#00aaaa"&gt;'clown&lt;/span&gt; tree &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clown, 'joker)&lt;/span&gt; cj &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clown, 'joker)&lt;/span&gt; cj&lt;/span&gt;&lt;br/&gt;      | Jokers: &lt;span style="color:#0000ff"&gt;&lt;span style="color:#00aaaa"&gt;('clown, 'joker)&lt;/span&gt; cj &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;'joker&lt;/span&gt; tree &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clown, 'joker)&lt;/span&gt; cj&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;The more general clown/joker data structure for a fold would look like this:&lt;pre&gt;&lt;span style="color:#009900; font-weight:bold"&gt;   data Clowns: &lt;span style="color:#0000ff"&gt;&lt;span style="color:#00aaaa"&gt;'clowns&lt;/span&gt; &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clowns, 'joker)&lt;/span&gt; cj &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clowns, 'joker)&lt;/span&gt; cj&lt;/span&gt;&lt;br/&gt;      | Jokers: &lt;span style="color:#0000ff"&gt;&lt;span style="color:#00aaaa"&gt;('clowns, 'joker)&lt;/span&gt; cj &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;'joker&lt;/span&gt; tree &lt;br/&gt;             -o &lt;span style="color:#00aaaa"&gt;('clowns, 'joker)&lt;/span&gt; cj&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;This is, it must be said, all reasonably unsatisfying. We have seen that hole abstractions can &lt;i&gt;completely replace&lt;/i&gt; the derivative data structure - we could well and truly "scrap our zippers." To use the clown/joker generalization of derivatives, we have to define an obvious, boiler-plate-ey datatype &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;cj&lt;/span&gt;&lt;/tt&gt;, which it is merely mechanical to compute for any datatype of jokers. Can we do better?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-8396248211253792187?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/s-xJXjSMaYs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/8396248211253792187/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/09/clowns-to-left-of-me-jokers-to-right.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8396248211253792187?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8396248211253792187?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/s-xJXjSMaYs/clowns-to-left-of-me-jokers-to-right.html" title="Clowns to the left of me, jokers to the right, here I am, stuck in a hole abstraction" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/09/clowns-to-left-of-me-jokers-to-right.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YARXsyfSp7ImA9WhRRGEo.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-79297579993519139</id><published>2011-08-24T12:32:00.000-04:00</published><updated>2011-12-02T19:12:24.595-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-02T19:12:24.595-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="related work" /><category scheme="http://www.blogger.com/atom/ns#" term="hole abstraction" /><category scheme="http://www.blogger.com/atom/ns#" term="difference lists" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="holey data" /><category scheme="http://www.blogger.com/atom/ns#" term="affine types" /><title>Holey Data, Postscript: Hole Abstraction</title><content type="html">I love the PL community on Twitter. Yesterday, David Van Horn presented this observation:
&lt;br /&gt;
&lt;br /&gt;&lt;div style="width:500px"&gt;&lt;!-- http://twitter.com/#!/lambda_calculus/status/105988679956299777 --&gt; &lt;style type='text/css'&gt;.bbpBox105988679956299777 {background:url(http://a1.twimg.com/images/themes/theme14/bg.gif) #131516;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox105988679956299777'&gt;&lt;p class='bbpTweet'&gt;Most papers in computer science describe how their author learned what someone else already knew.  -- Peter Landin&lt;span class='timestamp'&gt;&lt;a title='Tue Aug 23 13:04:05 +0000 2011' href='http://twitter.com/#!/lambda_calculus/status/105988679956299777'&gt;Tue Aug 23 13:04:05&lt;/a&gt; via &lt;a href="http://bufferapp.com" rel="nofollow"&gt;Buffer&lt;/a&gt; &lt;a href='http://twitter.com/intent/favorite?tweet_id=105988679956299777'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=105988679956299777'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=105988679956299777'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/lambda_calculus'&gt;&lt;img src='http://a3.twimg.com/profile_images/1339068530/badlogo_normal.png' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/lambda_calculus'&gt;dvanhorn@λ-calcul.us&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;lambda_calculus&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/div&gt;
&lt;br /&gt;I'm gonna be perfectly honest: I was specifically thinking of the &lt;a href="http://requestforlogic.blogspot.com/search/label/holey%20data"&gt;holey data&lt;/a&gt; series when I responded.
&lt;br /&gt;
&lt;br /&gt;&lt;div style="width:500px"&gt;&lt;!-- http://twitter.com/#!/simrob/status/105996182416932868 --&gt; &lt;style type='text/css'&gt;.bbpBox105996182416932868 {background:url(http://a0.twimg.com/images/themes/theme1/bg.png) #9ae4e8;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox105996182416932868'&gt;&lt;p class='bbpTweet'&gt;@&lt;a class="tweet-url username" href="http://twitter.com/lambda_calculus" rel="nofollow"&gt;lambda_calculus&lt;/a&gt; Presumably the implication is that this is bad for the advancement of science. OTOH, it's a pretty viable model for a blog.&lt;span class='timestamp'&gt;&lt;a title='Tue Aug 23 13:33:53 +0000 2011' href='http://twitter.com/#!/simrob/status/105996182416932868'&gt;Tue Aug 23 13:33:53&lt;/a&gt; via web &lt;a href='http://twitter.com/intent/favorite?tweet_id=105996182416932868'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=105996182416932868'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=105996182416932868'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/simrob'&gt;&lt;img src='http://a0.twimg.com/profile_images/474270007/rome-pop-icon_normal.jpg' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/simrob'&gt;Rob Simmons&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;simrob&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/div&gt;
&lt;br /&gt;'Cause really, I was kind of surprised that I hadn't found any previous presentations of the idea (and was therefore encouraged when Conor indicated that he at least &lt;a href="http://twitter.com/#!/pigworker/status/103445003367497728"&gt;sort of had thought of it too&lt;/a&gt;). Chung-chieh Shan's response was great:
&lt;br /&gt;
&lt;br /&gt;&lt;div style="width:500px"&gt;&lt;!-- http://twitter.com/#!/ccshan/status/106131049997811712 --&gt; &lt;style type='text/css'&gt;.bbpBox106131049997811712 {background:url(http://a0.twimg.com/images/themes/theme1/bg.png) #C0DEED;padding:20px;} p.bbpTweet{background:#fff;padding:10px 12px 10px 12px;margin:0;min-height:48px;color:#000;font-size:18px !important;line-height:22px;-moz-border-radius:5px;-webkit-border-radius:5px} p.bbpTweet span.metadata{display:block;width:100%;clear:both;margin-top:8px;padding-top:12px;height:40px;border-top:1px solid #fff;border-top:1px solid #e6e6e6} p.bbpTweet span.metadata span.author{line-height:19px} p.bbpTweet span.metadata span.author img{float:left;margin:0 7px 0 0px;width:38px;height:38px} p.bbpTweet a:hover{text-decoration:underline}p.bbpTweet span.timestamp{font-size:12px;display:block}&lt;/style&gt; &lt;div class='bbpBox106131049997811712'&gt;&lt;p class='bbpTweet'&gt;@&lt;a class="tweet-url username" href="http://twitter.com/simrob" rel="nofollow"&gt;simrob&lt;/a&gt; @&lt;a class="tweet-url username" href="http://twitter.com/lambda_calculus" rel="nofollow"&gt;lambda_calculus&lt;/a&gt; I'm not sure that Landin intended to imply that it's bad!&lt;span class='timestamp'&gt;&lt;a title='Tue Aug 23 22:29:48 +0000 2011' href='http://twitter.com/#!/ccshan/status/106131049997811712'&gt;Tue Aug 23 22:29:48&lt;/a&gt; via web &lt;a href='http://twitter.com/intent/favorite?tweet_id=106131049997811712'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/favorite.png' /&gt; Favorite&lt;/a&gt; &lt;a href='http://twitter.com/intent/retweet?tweet_id=106131049997811712'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/retweet.png' /&gt; Retweet&lt;/a&gt; &lt;a href='http://twitter.com/intent/tweet?in_reply_to=106131049997811712'&gt;&lt;img src='http://si0.twimg.com/images/dev/cms/intents/icons/reply.png' /&gt; Reply&lt;/a&gt;&lt;/span&gt;&lt;span class='metadata'&gt;&lt;span class='author'&gt;&lt;a href='http://twitter.com/ccshan'&gt;&lt;img src='http://a0.twimg.com/profile_images/1194502495/spacee_normal.png' /&gt;&lt;/a&gt;&lt;strong&gt;&lt;a href='http://twitter.com/ccshan'&gt;Chung-chieh Shan&lt;/a&gt;&lt;/strong&gt;&lt;br/&gt;ccshan&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;!-- end of tweet --&gt;&lt;/div&gt;
&lt;br /&gt;I guess I hope he's right (or at least that I am), because in the comments to Part 3, &lt;a href="http://www.ccs.neu.edu/home/turon/"&gt;Aaron Turon&lt;/a&gt; &lt;a href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-33-type-of-one-hole.html?showComment=1314192917682#c1092290329570263586"&gt;correctly observes&lt;/a&gt; that I missed a whopper: Minamide's 1998 POPL Paper "&lt;a href="http://dl.acm.org/citation.cfm?id=268953"&gt;A Functional Representation of Data Structures with a Hole&lt;/a&gt;." Horray for blogs, I guess: if this has been a paper review, I would have been quite embarrassed, but as a blog comment I was delighted to find out about this related work.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;A Functional Representation of Data Structures with a Hole&lt;/h2&gt;Minamide's paper effectively covers the same ground I covered in &lt;a href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-13-almost-difference.html"&gt;Part 1&lt;/a&gt; of the Holey Data series: his linear representational lambdas are called &lt;i&gt;hole abstractions&lt;/i&gt;. It's a very well written paper from the heady days when you could talk about the &lt;i&gt;proposed&lt;/i&gt; Standard ML Basis Library and it was still common for authors to cite Wright and Felleisen when explaining that they were proving language safety by (what amounts to) proving progress and preservation lemmas.
&lt;br /&gt;
&lt;br /&gt;My favorite part of reading the paper was that it simultaneously confirmed two suspicions that I picked up after a recent discussion with Dan Licata:&lt;ol&gt;&lt;li&gt;Levy#/call-by-push-value was an unnecessarily restrictive calculus for programming with linear representational functions - ML would work just fine.&lt;/li&gt;&lt;li&gt;By using call-by-push-value, I'd avoided certain red herrings that would have plagued the development otherwise - somewhere on almost every page I thought "yep, that explanation is less clear than it could be because they don't know about difference between value (positive) types and computation (negative) types yet."&lt;/li&gt;&lt;/ol&gt;One neat thing this paper describes that I hadn't thought about is automatically transforming non-tail-recursive programs that are naturally structurally inductive to tail-recursive programs based on hole abstractions/difference lists/linear representational functions. It seems like this optimization in particular is where many of the paper's claimed performance gains are found. It also seems like zippers-as-derivatives are pretty clearly lurking around the discussion in Section 4, which is neat.
&lt;br /&gt;
&lt;br /&gt;Overall, this paper made me quite happy - it suggests there is something canonical about this idea, and proves that the idea leads to concrete performance gains. It also made me sad, of course, because it seems like the ideas therein didn't really catch on last time around. But that's part of why I didn't stop with Part 1 in the series: it's not clear, even to me, that hole abstractions/difference lists/linear representational functions are worth adding to a functional programming language if all they can do is be applied and composed. However, with the additional expressiveness that can be found in pattern matching against hole abstractions (hell, that's a way better name than "linear representational functions," I'm just going to call them hole abstractions from now on), I think there's a significantly stronger case to be made.
&lt;br /&gt;
&lt;br /&gt;I've thrown a transliteration of Minamide's examples &lt;a href="https://github.com/robsimmons/levy/blob/holey/minamide.levy"&gt;up on GitHub&lt;/a&gt;. The binary tree insertion example, in particular, could come from Huet's paper: it's a beautiful example of how even the "Part 1" language can implement zipper algorithms so long as you never need to move up in the tree. As for the &lt;tt&gt;hfun_addone&lt;/tt&gt; function, I don't really understand it at all, I just transliterated it. In particular, it seems to not be entirely tail recursive (in particular, it seems to regular-recurse along the leftmost spine of the binary tree - if I'm not mistaken about this, I accuse &lt;a href="https://github.com/robsimmons/levy/blob/503525c1c7f1690ec586b2203fbfb8f929e5ea8a/minamide.levy#L131"&gt;line 131&lt;/a&gt; of being the culprit.)
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;6.3 Logic Variable&lt;/h3&gt;&lt;i&gt;(Note: I've tried to make sure this section doesn't come across as mean-spirited in any way, but I want to emphasize: this is not intended to be any sort of criticism of Yasuhiko Minamide. His paper was terrific! &lt;a href="http://www.score.cs.tsukuba.ac.jp/~minamide/papers/hole.popl98.pdf"&gt;Go read it!&lt;/a&gt;)&lt;/i&gt;
&lt;br /&gt;
&lt;br /&gt;My other favorite part of reading the paper was Section 6.3, which discusses difference lists. I plan to actually email Minamide and ask him about Section 6.3. Here's my reconstruction of events: Fictional Minamide has a great idea, implements it into a prototype ML compiler, tests it. His paper has strong theoretical and practical results, and gets accepted to POPL 1998. However, one of the reviewers says "oh, this is almost exactly difference lists in logic programming, you need to explain the connection." Fictional Minamide is not a logic programming person, has no access to a logic programming person, doesn't particularly have any reason to care about logic programming, but he does feel the need to address the concerns of a reviewer that he can't actually communicate with. Fictional Minamide manages to find, with great difficulty in the pre-Google-Scholar world, some poorly expressed explanation for what difference lists are in some random papers that are mostly about something else.&lt;sup&gt;&lt;a href="#1xepi"&gt;1&lt;/a&gt;&lt;/sup&gt; After a couple of hours, Fictional Minamide gives up, exclaiming "okay, this makes absolutely no sense &lt;i&gt;whatsoever&lt;/i&gt;," and writes something kinda mumbly about graph reduction that seems vaguely plausible to satisfy the reviewer's demand. 
&lt;br /&gt;
&lt;br /&gt;The result is a section that mostly misses the point about the connection between hole abstraction and difference lists, both of which are &lt;i&gt;declarative abstractions that allow a programmer to think about working modulo an uninitialized pointer in memory&lt;/i&gt; (though the way Minamide and I do it, the types help you &lt;i&gt;way&lt;/i&gt; more). This is &lt;b&gt;not&lt;/b&gt; intended as any criticism of either Real Minamide or Fictional Minamide. Indeed, it's mostly a criticism of the conference review processes: I'm pretty sure you could find similar "Section 6.3"s in my papers as well!&lt;sup&gt;&lt;a href="#2xexpi"&gt;2&lt;/a&gt;&lt;/sup&gt; I do hope, however, that my exposition in Part 1, which was in fact &lt;i&gt;motivated&lt;/i&gt; by difference lists and reached more-or-less the exact same setup that Minamide came up with, clarifies the record on how these two ideas are connected.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;[Update Aug 25]&lt;/b&gt; I heard back from Real Minamide - while it was a long time ago, he did recall one of the reviewers mentioning logic variables, leading to the inclusion of that section. I win! Well, kind of. There was probably no "this makes no sense" exclamation; Minimade says that at the time his understanding at the time was in line with my comment about working modulo an uninitialized pointer. The comments about graph reduction, which were why I thought the section misses the point, were more of a side comment. 
&lt;br /&gt;
&lt;br /&gt;Minamide also remembered another wonderfully tantalizing tidbit: he recalls that, at POPL 1998, Phil Wadler said he'd seen a similar idea even earlier. Perhaps hole abstraction is just destined to be continuously reinvented until it finally gets included in the C++2040 standard.&lt;sup&gt;&lt;a href="#3xexpi"&gt;3&lt;/a&gt;&lt;/sup&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;hr&gt;&lt;small&gt;&lt;sup&gt;&lt;a name="1xepi"&gt;1&lt;/a&gt;&lt;/sup&gt; The work he cites is on the adding the logic programming notions of unbound variables to functional programming languages, which (while I haven't looked at them) certainly don't look they would give a good introduction to the simple-but-goofy logic programming intuitions behind difference lists.
&lt;br /&gt;
&lt;br /&gt;That said, I basically have never seen a good, clear, self-contained description of what a difference list is - I consider Frank's &lt;a href="http://www.cs.cmu.edu/~fp/courses/lp/lectures/11-diff.pdf"&gt;logic programming notes&lt;/a&gt; to be pretty good, but I recognize that I'm not a fair judge because I was also present at the associated lecture.
&lt;br /&gt;
&lt;br /&gt;&lt;sup&gt;&lt;a name="2xexpi"&gt;2&lt;/a&gt;&lt;/sup&gt; Grep for "&amp;nabla;", or "nominal", especially in anything prior to my thesis proposal, if you want a head start.
&lt;br /&gt;
&lt;br /&gt;&lt;sup&gt;&lt;a name="3xexpi"&gt;3&lt;/a&gt;&lt;/sup&gt; I wonder what brackets they'll use, since as of the current standard they &lt;a href="http://twitter.com/#!/mattmight/status/103592582675832833"&gt;seem to have run out&lt;/a&gt;.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-79297579993519139?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/bg7W1EoQW6M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/79297579993519139/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/holey-data-postscript-hole-abstraction.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/79297579993519139?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/79297579993519139?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/bg7W1EoQW6M/holey-data-postscript-hole-abstraction.html" title="Holey Data, Postscript: Hole Abstraction" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/holey-data-postscript-hole-abstraction.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DUYCQXo9fCp7ImA9WhdXEEs.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-9144093789250928496</id><published>2011-08-22T14:34:00.000-04:00</published><updated>2011-08-22T22:39:20.464-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-22T22:39:20.464-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="zippers" /><category scheme="http://www.blogger.com/atom/ns#" term="one-hole contexts" /><category scheme="http://www.blogger.com/atom/ns#" term="levy" /><category scheme="http://www.blogger.com/atom/ns#" term="subordination" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="generic programming" /><category scheme="http://www.blogger.com/atom/ns#" term="holey data" /><title>Holey Data, Part 3/3: The Type Of A One-Hole Context</title><content type="html">Let's review:&lt;ul&gt;&lt;li&gt;As a prelude, I introduced the &lt;a href="http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html"&gt;Levy# language&lt;/a&gt;, Bauer and Pretnar's implementation of call-by-push-value, a programming formalism that is very persnickety about the difference between &lt;i&gt;value code&lt;/i&gt; and &lt;i&gt;computation code&lt;/i&gt;, extended with datatypes. I have come to the position, especially after a conversation with Dan Licata, that we should really think of Levy# as an &lt;a href="http://en.wikipedia.org/wiki/Administrative_normal_form"&gt;A-normal form&lt;/a&gt; intermediate language that is explicit about control: using it allowed me to avoid certain red herrings that would have arisen in an ML-like syntax, but you'd really want the ML-like language to actually program in.&lt;/li&gt;&lt;li&gt;In &lt;a href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-13-almost-difference.html"&gt;Part 1&lt;/a&gt;, I showed how representational linear functions could capture a logic programming idiom, &lt;i&gt;difference lists&lt;/i&gt;. Difference lists can be implemented in ML/Haskell as functional data structures, but they don't have O(1) append and turn-into-a-regular-list operations; my Levy# difference lists, represented as values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;, can perform all these operations in constant time with local pointer manipulation. The cost is that operations on linear functions are implemented by destructive pointer mutation - I should really have an &lt;a href="http://requestforlogic.blogspot.com/2011/03/request-for-typestate-part-2-linear.html"&gt;affine type system&lt;/a&gt; to ensure that values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt; are used at most once.&lt;/li&gt;&lt;li&gt;In &lt;a href=""&gt;Part 2&lt;/a&gt;, I observed that the perfectly natural, &amp;lambda;Prolog/Twelf-inspired operation of matching against these linear functions greatly increased their expressive power. By adding an extra bit of information to the runtime representation of data (an answer to the the question "where is the hole, if there is a hole?"), the matching operation could be done in constant time (well, time linear in the number of cases). A simple subordination analysis meant that checking for exhaustiveness and redundancy in case analysis was possible as well.&lt;/li&gt;&lt;/ul&gt;In the case study in Part 2, I motivated another kind of pattern matching, one foreign to the &amp;lambda;Prolog/Twelf way of looking at the world but one intimately connected to the famous functional data structure known as &lt;a href="http://en.wikipedia.org/wiki/Zipper_(data_structure)"&gt;The Zipper&lt;/a&gt;. In this last installment, I show how linear representational functions can &lt;i&gt;completely subsume&lt;/i&gt; zippers.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;The essence of zippers&lt;/h2&gt;A zipper is a functional data structure that allows you to poke around on the inside of a datatype without having to constantly descend all the way int the datatype. Illustrations of zippers generally look something like this:&lt;sup&gt;&lt;a href="foot1x3"&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/One-hole-context-plug.png" /&gt;
&lt;br /&gt;
&lt;br /&gt;The zipper data structure consists of two parts: one of them is a "path" or "one-hole-context", which, owing to Conor's influence [&lt;a href="#1x3"&gt;1&lt;/a&gt;], I will call a &lt;i&gt;derivative&lt;/i&gt;, and the other is a subterm. We maintain the invariant that as we move into the derivative ("up") or into the subterm ("down") with constant-time operations, the combination of the derivative and the subterm remains the original term that we are editing. A Levy# implementation of derivative-based zippers as presented in Huet's original paper on zippers [&lt;a href="#2x3"&gt;2&lt;/a&gt;] can be found in &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-3/thezipper.levy"&gt;thezipper.levy&lt;/a&gt;. 
&lt;br /&gt;
&lt;br /&gt;To understand linear function-based zippers, we see that a linear term &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;a -o b&lt;/span&gt;&lt;/tt&gt; is kind of obviously a &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;b&lt;/span&gt;&lt;/tt&gt; value with one &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;a&lt;/span&gt;&lt;/tt&gt; value missing, so if we pair a value &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;a -o b&lt;/span&gt;&lt;/tt&gt; with a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;a&lt;/span&gt;&lt;/tt&gt;, we would hope to be able to use the pair as a zipper over &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;b&lt;/span&gt;&lt;/tt&gt; values. The one thing that we can't do with the linear functions we've discussed so far, however, is look "up" in the tree. 
&lt;br /&gt;
&lt;br /&gt;A list is a good simple example here, since the two parts of a linear function-based zipper over a list are a difference list (the beginning of the list) and a list (the end of the list). Looking "up" involves asking what the last item in the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt; is (if there is at least one item). Since a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt; has the structure &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] Cons n&lt;sub&gt;1&lt;/sub&gt; (Cons n&lt;sub&gt;2&lt;/sub&gt; ... (Cons n&lt;sub&gt;k-1&lt;/sub&gt; (Cons n&lt;sub&gt;k&lt;/sub&gt; hole))...)&lt;/span&gt;&lt;/tt&gt;, it's reasonable to match this term against the pattern &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[hole: list] &lt;span style="color:#0000ff"&gt;outside&lt;/span&gt; (Cons &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; hole)&lt;/span&gt;&lt;/tt&gt; to learn that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;outside&lt;/span&gt;&lt;/tt&gt; is &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] Cons n&lt;sub&gt;1&lt;/sub&gt; (Cons n&lt;sub&gt;2&lt;/sub&gt; ... (Cons n&lt;sub&gt;k-1&lt;/sub&gt; hole)...)&lt;/span&gt;&lt;/tt&gt; and that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;i&lt;/span&gt;&lt;/tt&gt; is &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;n&lt;sub&gt;k&lt;/sub&gt;&lt;/span&gt;&lt;/tt&gt;. The key is that, in the pattern, the linear variable &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;hole&lt;/span&gt;&lt;/tt&gt; appears as the &lt;i&gt;immediate&lt;/i&gt; subterm to the constructor &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;Cons&lt;/span&gt;&lt;/tt&gt;, so that we're really only asking a question about what the &lt;i&gt;closest&lt;/i&gt; constructor to the hole is.
&lt;br /&gt;
&lt;br /&gt;This kind of interior pattern matching is quite different from existing efforts to understand "pattern fragments" of linear lambda cacluli (that I know of), but it's perfectly sensible. As I'll show in the rest of this post, it's also easy enough to modify the implementation to deal with interior pattern matching efficiently, easy enough to do exhaustiveness checking, and easy enough to actually use for programming. For the last part, I'll use an example from Michael Adams; you can also see the linear pattern matching version of Huet's original example on Github: (&lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-3/linzipper.levy"&gt;linzipper.levy&lt;/a&gt;).
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Implementation&lt;/h2&gt;The only trick to implementing zippers that allow interior pattern matching is to turn our linked list structure into a doubly linked list: the final data structure basically is a double-ended queue implemented by a doubly-linked list. 
&lt;br /&gt;
&lt;br /&gt;First: we make our "tail pointer," which previously pointed into the last structure where the hole was, a pointer to the &lt;i&gt;beginning&lt;/i&gt; of the last allocated cell, the one that immediately surrounds the hole. This lets us perform the pattern match, because we can see what the immediate context of the hole is just by following the tail pointer. (It also requires that we create a different representation of linear functions that are the identity, but that's the kind of boring observation that you can get by implementing a doubly-linked list in C.) 
&lt;br /&gt;
&lt;br /&gt;After we have identified the immediate context of the hole, we also need a parent pointer to identify the smaller "front" of the linear function. The in-memory representation of &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] Cons 9 (Cons 3 (Cons 7 hole))&lt;/span&gt;&lt;/tt&gt;, for example, will look something like this:
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-fig5.png"/&gt;
&lt;br /&gt;Just like the "where is the hole" information, this parent pointer gets to be completely ignored by the runtime if it hangs around after the linear function is turned into a non-holey value. 
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Exhaustiveness checking&lt;/h2&gt;Providing non-exhaustive match warnings for case analysis on the inside of a linear function is a bit tricker than providing non-exhaustive match warnings for case analysis on the outside of a linear function, but it's only just a bit trickier. First, observe that the subordination relation I talked about in the previous installment is the transitive closure of an &lt;i&gt;immediate subordination&lt;/i&gt; relation that declares what types of values can be immediate subterms to constructors of other types. For instance, when we declare the type of the constructor &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;Cons&lt;/span&gt;&lt;/tt&gt; to be &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -o list -o list&lt;/span&gt;&lt;/tt&gt;, Levy# learns that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list&lt;/span&gt;&lt;/tt&gt; are both immediately subordinate to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list&lt;/span&gt;&lt;/tt&gt;. 
&lt;br /&gt;
&lt;br /&gt;Levy# was already tracking both the immediate subordination relation and the full subordination relation; we can change the output of the "print subordination" command to reflect this reality:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;Levy. Press Ctrl-D to exit.&lt;br/&gt;   Levy&gt; &lt;span style="color:#009900"&gt;data Z: &lt;span style="color:#0000ff"&gt;even&lt;/span&gt; | EO: &lt;span style="color:#0000ff"&gt;even -o odd&lt;/span&gt; | OE: &lt;span style="color:#0000ff"&gt;odd -o even&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   &lt;span style="color:#009900"&gt;data Z: &lt;span style="color:#0000ff"&gt;even&lt;/span&gt;&lt;br/&gt;      | EO: &lt;span style="color:#0000ff"&gt;even -o odd&lt;/span&gt;&lt;br/&gt;      | OE: &lt;span style="color:#0000ff"&gt;odd -o even&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;   Levy&gt; $subord ;;&lt;br/&gt;   Subordination for current datatypes:&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;even&lt;/span&gt; &lt;| &lt;span style="color:#0000ff"&gt;even&lt;/span&gt;&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;even&lt;/span&gt; &lt;| &lt;span style="color:#0000ff"&gt;odd&lt;/span&gt; (immediate)&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;odd&lt;/span&gt; &lt;| &lt;span style="color:#0000ff"&gt;even&lt;/span&gt; (immediate)&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;odd&lt;/span&gt; &lt;| &lt;span style="color:#0000ff"&gt;odd&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;Now, the way we enumerate the possible cases for an interior pattern match against a linear value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;holeTy -o valueTy&lt;/span&gt;&lt;/tt&gt; is the following:&lt;ul&gt;&lt;li&gt;Enumerate all of the types &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ctxTy&lt;/span&gt;&lt;/tt&gt; that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;holeTy&lt;/span&gt;&lt;/tt&gt; is immediately subordinate to. These are all the types with constructors that might immediately surround the hole (which, of course, has type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;holeTy&lt;/span&gt;&lt;/tt&gt;).&lt;/li&gt;&lt;li&gt;Filter out all the types &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ctxTy&lt;/span&gt;&lt;/tt&gt; above that aren't subordinate to, or the same as, the value type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;valueTy&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;For every constructor of the remaining types &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ctxTy&lt;/span&gt;&lt;/tt&gt;, list the positions where a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;holeTy&lt;/span&gt;&lt;/tt&gt; may appear as an immediate subterm.&lt;/li&gt;&lt;/ul&gt;Using the immediate subordination relation is actually unnecessary: alternatively, we could just start the filtering step with &lt;i&gt;all&lt;/i&gt; types subordinate (or equal) to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;valueTy&lt;/span&gt;&lt;/tt&gt;. I think the use of the immediate subordination relation is kind of neat, though.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Case Study: No, Really, Scrap Your Zippers&lt;/h2&gt;When I said that this idea had been kicking around in my head since shortly after &lt;a href="http://osl.iu.edu/wgp2010/"&gt;WGP 2010&lt;/a&gt;, I meant specifically since the part of WGP 2010 when &lt;a href="http://www.cs.indiana.edu/~adamsmd/"&gt;Michael Adams&lt;/a&gt; presented the paper "&lt;a href="http://www.cs.indiana.edu/~adamsmd/papers/scrap_your_zippers/"&gt;Scrap Your Zippers&lt;/a&gt;". One of the arguments behind the Scrap Your Zippers approach is that Huet's zippers involve a lot of boilerplate and don't work very well for heterogenerous datatypes. 
&lt;br /&gt;
&lt;br /&gt;Small examples tend to minimize the annoyingness of boilerplate by virtue of their smallness, but the example Adams gave about heterogeneous zippers works (almost) beautifully in our setting. First, we describe the datatype of departments, which are pairs of an employee record (the boss) and a list of employees (subordinates):&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#009900"&gt;data E: &lt;span style="color:#0000ff"&gt;name -o int -o employee&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   &lt;span style="color:#009900"&gt;data Nil: &lt;span style="color:#0000ff"&gt;list&lt;/span&gt;&lt;br/&gt;      | Cons: &lt;span style="color:#0000ff"&gt;employee -o list -o list&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   &lt;span style="color:#009900"&gt;data D: &lt;span style="color:#0000ff"&gt;employee -o list -o dept&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;agamemnon&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;E Agamemnon 5000&lt;/span&gt; ;;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;menelaus&lt;/span&gt;  = &lt;span style="color:#0000ff"&gt;E Menelaus  3000&lt;/span&gt; ;;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;achilles&lt;/span&gt;  = &lt;span style="color:#0000ff"&gt;E Achilles  2000&lt;/span&gt; ;;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;odysseus&lt;/span&gt;  = &lt;span style="color:#0000ff"&gt;E Odysseus  2000&lt;/span&gt; ;;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;dept&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;D agamemnon &lt;br/&gt;     (Cons menelaus &lt;br/&gt;       (Cons achilles &lt;br/&gt;         (Cons odysseus Nil)))&lt;/span&gt; ;;&lt;span&gt;&lt;/pre&gt;Our goal is to zipper our way in to the department value &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dept&lt;/span&gt;&lt;/tt&gt; and rename "Agamemnon" "King Agamemnon."
&lt;br /&gt;
&lt;br /&gt;The reason this is only &lt;i&gt;almost&lt;/i&gt; beautiful is that Levy# doesn't have a generic pair type, and the type of zippers over a heterogeneous datatype like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dept&lt;/span&gt;&lt;/tt&gt; is a pair of a linear representational function &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;T -o dept&lt;/span&gt;&lt;/tt&gt; and a value &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;T&lt;/span&gt;&lt;/tt&gt; for some type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;T&lt;/span&gt;&lt;/tt&gt;. So, we need to come up with specific instances of this as datatypes, the way we might in Twelf:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#009900"&gt;data PD: &lt;span style="color:#0000ff"&gt;(dept -o dept) -o dept -o paird&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   &lt;span style="color:#009900"&gt;data PE: &lt;span style="color:#0000ff"&gt;(employee -o dept) -o employee -o paire&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   &lt;span style="color:#009900"&gt;data PN: &lt;span style="color:#0000ff"&gt;(name -o dept) -o name -o pairn&lt;/span&gt;&lt;/span&gt; ;;
&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;Given these pair types, we are able to descend into the structure without any difficulty:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   # Create the zipper pair&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;PD ([hole: dept] hole) dept&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   # Move down and to the left&lt;br/&gt;   comp &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; = &lt;br/&gt;     &lt;span style="color:#cc4020"&gt;let &lt;span style="color:#009900"&gt;(PD &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;dept&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; in&lt;br/&gt;     let &lt;span style="color:#009900"&gt;(D &lt;span style="color:#0000ff"&gt;boss&lt;/span&gt; &lt;span style="color:#0000ff"&gt;subord&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;dept&lt;/span&gt; in&lt;br/&gt;     return &lt;span style="color:#0000ff"&gt;PE&lt;br/&gt;       ([hole: employee] path (D hole subord))&lt;br/&gt;       boss&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   # Move down and to the left&lt;br/&gt;   comp &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; = &lt;br/&gt;     &lt;span style="color:#cc4020"&gt;let &lt;span style="color:#009900"&gt;(PE &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; in&lt;br/&gt;     let &lt;span style="color:#009900"&gt;(E &lt;span style="color:#0000ff"&gt;name&lt;/span&gt; &lt;span style="color:#0000ff"&gt;salary&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt; in&lt;br/&gt;     return &lt;span style="color:#0000ff"&gt;PN&lt;br/&gt;       ([hole: name] path (E hole salary))&lt;br/&gt;       name&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;At this point, we &lt;i&gt;could&lt;/i&gt; just do the replacement in constant time by linear application:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   comp &lt;span style="color:#0000ff"&gt;revision&lt;/span&gt; = &lt;br/&gt;     &lt;span style="color:#cc4020"&gt;let &lt;span style="color:#009900"&gt;(PN &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;name&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; in&lt;br/&gt;     return &lt;span style="color:#0000ff"&gt;path KingAgamemnon&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;For comparison, the &lt;i&gt;Scrap Your Zippers&lt;/i&gt; framework implements this with the function &lt;tt&gt;fromZipper&lt;/tt&gt;.
&lt;br /&gt;
&lt;br /&gt;However, everything above could have been done in the previous installment. Our new kind of pattern matching reveals its power when we try to walk "up" in the data structure, so we'll do that instead. The first step takes us back to an &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;employee -o dept&lt;/span&gt;&lt;/tt&gt; zipper, and is where we give Agamemnon his kingly designation:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   comp &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; = &lt;br/&gt;     &lt;span style="color:#cc4020"&gt;let &lt;span style="color:#009900"&gt;(PN &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;name&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; in&lt;br/&gt;     let &lt;span style="color:#009900"&gt;([hole: &lt;span style="color:#0000ff"&gt;name&lt;/span&gt;] &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; (E hole &lt;span style="color:#0000ff"&gt;salary&lt;/span&gt;))&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; in&lt;br/&gt;     return &lt;span style="color:#0000ff"&gt;PE path (E KingAgamemnon salary)&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;The first step was easy: the only place a &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;name&lt;/span&gt;&lt;/tt&gt; hole can appear in an &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dept&lt;/span&gt;&lt;/tt&gt; datatype is inside of an &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;employee&lt;/span&gt;&lt;/tt&gt;. An &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;employee&lt;/span&gt;&lt;/tt&gt;, however, can appear in a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dept&lt;/span&gt;&lt;/tt&gt; in one of two paces: either as the boss or as one of the members of the list of subordinates. Therefore, if we want to avoid nonexhaustive match warnings, we have to give an extra case:&lt;sup&gt;&lt;a href="#foot2x3"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   comp &lt;span style="color:#0000ff"&gt;revision&lt;/span&gt; = &lt;br/&gt;     &lt;span style="color:#cc4020"&gt;let &lt;span style="color:#009900"&gt;(PE &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;)&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;loc&lt;/span&gt; in&lt;br/&gt;     match &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; with&lt;br/&gt;     | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;] D hole &lt;span style="color:#0000ff"&gt;subord&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;         return &lt;span style="color:#0000ff"&gt;D employee subord&lt;/span&gt;&lt;br/&gt;     | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;] &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; (Cons hole &lt;span style="color:#0000ff"&gt;other_subord&lt;/span&gt;)&lt;/span&gt; -&gt;&lt;br/&gt;         return &lt;span style="color:#0000ff"&gt;dept&lt;/span&gt;&lt;/span&gt; ;; # Error?&lt;/span&gt;&lt;/pre&gt;Note that, in the first match above, the case was &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[hole: &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;] D hole &lt;span style="color:#0000ff"&gt;subord&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;, not &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[hole: &lt;span style="color:#0000ff"&gt;employee&lt;/span&gt;] &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; (D hole &lt;span style="color:#0000ff"&gt;subord&lt;/span&gt;)&lt;/span&gt;&lt;/tt&gt;. As in the previous installment, I used the subordination relation to conclude that there were no values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dept -o dept&lt;/span&gt;&lt;/tt&gt; other than the identity; therefore, it's okay to allow the simpler pattern that assumes &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;path&lt;/span&gt;&lt;/tt&gt; is the identity.
&lt;br /&gt;
&lt;br /&gt;The code for this example is in &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-3/scrap.levy"&gt;scrap.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;Proposals for radically new language features should be treated with some care; do they really add enough expressiveness to the language? I hope that this series has at least suggested the possibility that linear function types might be desirable as a core language feature in a functional language. Linear representational functions expand the class of safe, pure algorithms to capture algorithms that could previously only be done in an impure way, and they give a completely principled (and cast-free) way of scrapping your zipper boilerplate.
&lt;br /&gt;
&lt;br /&gt;And perhaps the most important feature of this proposal is one I haven't touched so far, which is the added simplicity of reasoning about programs, both informally and formally. As for the "informally," if you've ever been flummoxed by the process of making sure that your heavily tail-recursive program has an even number of &lt;tt&gt;List.rev&lt;/tt&gt; errors, or if you have avoided making functions tail-recursive for precisely this reason, I think linear representational functions could be a huge help. One thing I'd like to do if I have time is to work through &lt;a href="http://requestforlogic.blogspot.com/2010/10/type-inference-in-and-out-of-context.html"&gt;type inference in context&lt;/a&gt; with linear representational functions; I imagine many things would be much clearer. In particular, I suspect there wouldn't be any need for both Cons and Snoc lists or the "fish" operator.
&lt;br /&gt;
&lt;br /&gt;The formal reasoning aspect can be glimpsed by looking at the previous case study: proving that the tail-recursive functions &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;lin_of_zip&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;zip_of_lin&lt;/span&gt;&lt;/tt&gt; are inverses has the structure of a double-reverse theorem (proving that &lt;tt&gt;List.rev (List.rev xs) = xs&lt;/tt&gt;). Maybe it's just me being dense, but I have trouble with double-reverse theorems. On the other hand, if we needed to prove that the structurally-inductive and not tail-recursive functions &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;lin_of_zip'&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;zip_of_lin'&lt;/span&gt;&lt;/tt&gt; (which we can &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-3/linear-vs-zipper.levy#L23-32"&gt;now implement&lt;/a&gt;, of course) are inverses, that's just a straightforward induction and call to the induction hypothesis. And making dumb theorems easier to prove is, in my experience at least half the battle of using theorem provers.
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Expressiveness and efficiency, reloaded&lt;/h3&gt;The claim that linear representational functions can completely subsume zippers is undermined somewhat by the emphasis I have put on making matching and other operations O(1). Just to be clear: I can entirely implement linear representational functions using functional data structures (in fact, by using derivatives!) if I'm not concerned with performance. There's even a potential happy medium: rather than invalidating a zipper, I &lt;i&gt;think&lt;/i&gt; it would be possible to merely mark a zipper as "in use," so that the second time you use a zipper it gets silently copied. This means that if you think about affine usage, you get constant-time guarantees, but if you just want to use more-awesome zippers, you can program as if it was a persistent data structure. This "persistent always, efficient if you use it right" notion of persistant data structures has precedent, it's how &lt;a href="http://dl.acm.org/citation.cfm?id=1292541"&gt;persistent union-find&lt;/a&gt; works.
&lt;br /&gt;
&lt;br /&gt;&lt;hr&gt;&lt;small&gt;&lt;a name="foot1x3"&gt;&lt;/a&gt;&lt;sup&gt;1&lt;/sup&gt; That particular image is a CC-SA licensed contribution by Heinrich Apfelmus on the &lt;a href="http://en.wikibooks.org/wiki/Haskell/Zippers"&gt;Haskell Wikibook on zippers&lt;/a&gt;. Thanks, Heinrich!
&lt;br /&gt;&lt;a name="foot2x3"&gt;&lt;/a&gt;&lt;sup&gt;2&lt;/sup&gt; If we had a polymorphic option type we could just return &lt;tt&gt;Some&lt;/tt&gt; or &lt;tt&gt;None&lt;/tt&gt;, of course. Meh.
&lt;br /&gt;[&lt;a name="1x3"&gt;&lt;/a&gt;1] Conor McBride, "&lt;a href="http://strictlypositive.org/diff.pdf"&gt;The Derivative of a Regular Type is its Type of One-Hole Contexts&lt;/a&gt;," comically unpublished.
&lt;br /&gt;[&lt;a name="2x3"&gt;&lt;/a&gt;2] G&amp;uacute;rard Huet, "&lt;a href="http://journals.cambridge.org/action/displayAbstract?fromPage=online&amp;aid=44121"&gt;Function Pearl: The Zipper&lt;/a&gt;," JFP 1997.
&lt;br /&gt;[&lt;a name="3x3"&gt;&lt;/a&gt;3] Michael D. Adams "&lt;a href="https://www.cs.indiana.edu/~adamsmd/papers/scrap_your_zippers/"&gt;Scrap Your Zippers&lt;/a&gt;," WGP 2010.
&lt;br /&gt;&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-9144093789250928496?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/_H2sqPvBftg" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/9144093789250928496/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-33-type-of-one-hole.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/9144093789250928496?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/9144093789250928496?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/_H2sqPvBftg/holey-data-part-33-type-of-one-hole.html" title="Holey Data, Part 3/3: The Type Of A One-Hole Context" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/holey-data-part-33-type-of-one-hole.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4BQnwyeip7ImA9WhdXEE8.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-985836498877684717</id><published>2011-08-15T23:47:00.000-04:00</published><updated>2011-08-22T10:39:13.292-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-22T10:39:13.292-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="levy" /><category scheme="http://www.blogger.com/atom/ns#" term="subordination" /><category scheme="http://www.blogger.com/atom/ns#" term="difference lists" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="holey data" /><category scheme="http://www.blogger.com/atom/ns#" term="difference queues" /><title>Holey Data, Part 2/3: Case Analysis on Linear Functions</title><content type="html">The &lt;a href="http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html"&gt;previous installment&lt;/a&gt; was titled "(Almost) Difference Lists" because there was one operation that we could (technically) do on a Prolog difference list that we can't do on the difference lists described in the previous section. If a Prolog difference list is &lt;i&gt;known to be nonempty&lt;/i&gt;, it's possible to match against the front of the list. Noone ever does this that I can tell, because if the Prolog difference list &lt;i&gt;is&lt;/i&gt; empty, this will mess up all the invariants of the difference list. Still, however, it's there.
&lt;br /&gt;
&lt;br /&gt;We will modify our language to allow &lt;i&gt;pattern matching&lt;/i&gt; on linear functions, which is like pattern matching on a difference list but better, because we can safely handle emptiness. The immediate application of this is that we have a list-like structure that allows constant time affix-to-the-end and remove-from-the-beginning operations: a queue! Due to the similarity with difference lists, I'll call this curious new beast a &lt;i&gt;difference queue&lt;/i&gt;. This is all rather straightforward, except for the dicussion of coverage checking, which involves a well-understood analysis called &lt;i&gt;subordination&lt;/i&gt;. But we'll cross that bridge when we come to it.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;A pattern matching aside.&lt;/b&gt; Pattern matching against functions? It's certainly the case that in ML we can't pattern match against functions, but as we've already discussed towards the end of the &lt;a href="http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html"&gt;intro to Levy#&lt;/a&gt;, the linear function space is not a &lt;i&gt;computational&lt;/i&gt; function space like the one in ML, it's a &lt;i&gt;representational&lt;/i&gt; function space like the one in LF/Twelf, a distinction that comes from Dan Licata, Bob Harper, and Noam Zeilberger [&lt;a href="#1x2"&gt;1&lt;/a&gt;, &lt;a href="#2x2"&gt;2&lt;/a&gt;]. And we pattern match against representational functions all the time in LF/Twelf. Taking this kind of pattern matching from the logic programming world of Twelf into the functional programming world is famously tricky (leading to proposals like &lt;a href="http://www.cs.mcgill.ca/~complogic/beluga/"&gt;Beluga&lt;/a&gt;, &lt;a href="http://cs-www.cs.yale.edu/homes/delphin/"&gt;Delphin&lt;/a&gt;, (sort of) &lt;a href="http://abella.cs.umn.edu/"&gt;Abella&lt;/a&gt;, and the aforementioned efforts of Licata et al.), but the trickiness is always from attempts to open up a (representational) function, do something computational on the inside, and then put it back together. We're not going to need to do anything like that, luckily for us.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Difference queues&lt;/h2&gt;We're going to implement difference queues as values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o q&lt;/span&gt;&lt;/tt&gt;, where &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; is an interesting type: because definitions are inductive, the type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; actually has no inhabitants. &lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#009900"&gt;data QCons: &lt;span style="color:#0000ff"&gt;int -o q -o q&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;An alternative would be to implement difference queues using the difference lists &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt; from the previous installment, which would work fine too.
&lt;br /&gt;
&lt;br /&gt;We'll also have an option type, since de-queueing might return nothing if the queue is empty, as well as a "valof" equivalent operation to force the queue from something that may or may not be a queue. This &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;getq&lt;/span&gt;&lt;/tt&gt; option will raise a non-exhaustive match warning during coverage checking, since it can obviously raise a runtime error.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#009900"&gt;data None: &lt;span style="color:#0000ff"&gt;option&lt;/span&gt;&lt;br/&gt;      | Some: &lt;span style="color:#0000ff"&gt;int -o (q -o q) -o option&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;getq&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;fun &lt;span style="color:#0000ff"&gt;opt&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;option&lt;/span&gt; -&gt;&lt;br/&gt;     let (&lt;span style="color:#009900"&gt;Some &lt;span style="color:#0000ff"&gt;_&lt;/span&gt; &lt;span style="color:#0000ff"&gt;q&lt;/span&gt;&lt;/span&gt;) be &lt;span style="color:#0000ff"&gt;opt&lt;/span&gt; in return &lt;span style="color:#0000ff"&gt;q&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;The operations to make a new queue and to push an item onto the end of the queue use the functionality that we've already presented:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   val &lt;span style="color:#0000ff"&gt;new&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;return &lt;span style="color:#0000ff"&gt;[x:q] x&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;&lt;br/&gt;   val &lt;span style="color:#0000ff"&gt;push&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk&lt;br/&gt;     &lt;span style="color:#cc4020"&gt;fun &lt;span style="color:#0000ff"&gt;i&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; -&gt;&lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;queue&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(q -o q)&lt;/span&gt; -&gt;&lt;br/&gt;       return &lt;span style="color:#0000ff"&gt;[x:q] queue (QCons i x)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;The new functionality comes from the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;pop&lt;/span&gt;&lt;/tt&gt; function, which matches against the front of the list. An empty queue is represented by the identity function.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   val &lt;span style="color:#0000ff"&gt;pop&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;fun &lt;span style="color:#0000ff"&gt;queue&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(q -o q)&lt;/span&gt; -&gt;&lt;br/&gt;     match &lt;span style="color:#0000ff"&gt;queue&lt;/span&gt; with&lt;br/&gt;       | &lt;span style="color:#009900"&gt;[x:&lt;span style="color:#0000ff"&gt;q&lt;/span&gt;] x&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;None&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#009900"&gt;[x:&lt;span style="color:#0000ff"&gt;q&lt;/span&gt;] QCons &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;queue'&lt;/span&gt; x)&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;Some i queue'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;Lets take a closer look at the second pattern, &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[x:q] QCons &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;queue'&lt;/span&gt; x)&lt;/span&gt;&lt;/tt&gt;. The &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;QCons&lt;/span&gt;&lt;/tt&gt; constructor has two arguments, and because the linear variable &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;x&lt;/span&gt;&lt;/tt&gt; occurs exactly once, it has to appear in one of the two arguments. This pattern is intended to match the case where the linear variable &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;x&lt;/span&gt;&lt;/tt&gt; appears in the second argument of the constructor (read: inside of the the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; part, not inside of the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; part), and the pattern binds a linear function &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;queue'&lt;/span&gt;&lt;/tt&gt; that has type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o q&lt;/span&gt;&lt;/tt&gt;.
&lt;br /&gt;
&lt;br /&gt;You can see how these difference queues are used in &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-2/linearqueue.levy#L26-43"&gt;linearqueue.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Another pattern matching aside.&lt;/b&gt; The above-mentioned patterns (and, in fact, all accepted patterns in this current extension of Levy#) actually come from the set of Linear LF terms that are in what is known as the &lt;i&gt;pattern fragment&lt;/i&gt; (appropriately enough). The pattern fragment was first identified by Dale Miller as a way of carving out a set of unification problems on higher-order terms that could 1) always be given unitary and decidable solutions and 2) capture many of the actual unification problems that might arise in λProlog [&lt;a href="#3x2"&gt;3&lt;/a&gt;]. Anders Schack-Nielsen and Carsten Schürmann later generalized this to Linear LF [&lt;a href="#4x2"&gt;4&lt;/a&gt;], which as I've described is the language that we're essentially using to describe our data.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Coverage checking with subordination&lt;/h2&gt;In the previous section we saw that the two patterns &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[x:q] x&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[x:q] QCons &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;queue'&lt;/span&gt; x)&lt;/span&gt;&lt;/tt&gt; were used to match against a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o q&lt;/span&gt;&lt;/tt&gt;, and the coverage checker in Levy# accepted those two patterns as providing a complete case analysis of values of this type. But the constructor &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;QCons&lt;/span&gt;&lt;/tt&gt; has two arguments; why was the coverage checker satisfied with a case analysis that only considered the linear variable occurring in the second argument?
&lt;br /&gt;
&lt;br /&gt;To understand this, consider the pattern &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[x:q] x&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[x:q] QCons (&lt;span style="color:#0000ff"&gt;di&lt;/span&gt; x) &lt;span style="color:#0000ff"&gt;queue'&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;, where the linear variable does occur in the first argument. This pattern binds the variable &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;di&lt;/span&gt;&lt;/tt&gt;, a linear function value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o int&lt;/span&gt;&lt;/tt&gt;. But the only inhabitants of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; are constants, and the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; must go somewhere; where can it go? It can't go anywhere! This effectively means that there are &lt;i&gt;no closed values of type&lt;/i&gt; &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o int&lt;/span&gt;&lt;/tt&gt;, so there's no need to consider what happens if the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; hole appears inside of the first argument to &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;QCons&lt;/span&gt;&lt;/tt&gt;.
&lt;br /&gt;
&lt;br /&gt;Because of these considerations, Levy# has to calculate what is called the &lt;a href="http://twelf.plparty.org/wiki/Subordination"&gt;subordination relation&lt;/a&gt; for the declared datatypes. Subordination is an analysis developed for Twelf that figures out what types of terms can appear as subterms of other types of terms. I added a new keyword to Levy# for reporting this subordination information:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;Levy&gt; $subord ;;&lt;br/&gt;   Subordination for current datatypes:&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; &amp;lt;| &lt;span style="color:#0000ff"&gt;q&lt;/span&gt;&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;q&lt;/span&gt; &amp;lt;| &lt;span style="color:#0000ff"&gt;q&lt;/span&gt;&lt;br/&gt;   &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; &amp;lt;| &lt;span style="color:#0000ff"&gt;option&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;So &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; is subordinate to both &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;option&lt;/span&gt;&lt;/tt&gt;, and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; is subordinate only to itself. Subordination is intended to be a conservative analysis, so this means that there &lt;i&gt;might&lt;/i&gt; be values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -o q&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -o option&lt;/span&gt;&lt;/tt&gt; and that there &lt;i&gt;might&lt;/i&gt; be non-identity values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o q&lt;/span&gt;&lt;/tt&gt;, but that there are &lt;i&gt;no&lt;/i&gt; values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o option&lt;/span&gt;&lt;/tt&gt; and the only value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;option -o option&lt;/span&gt;&lt;/tt&gt; is &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[x: option] x&lt;/span&gt;&lt;/tt&gt;. Levy# uses the no-overlapping-holes restriction to make subordination analysis more precise; without this restriction, a reasonable subordination analysis would likely declare &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q&lt;/span&gt;&lt;/tt&gt; subordinate to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;option&lt;/span&gt;&lt;/tt&gt;.&lt;sup&gt;&lt;a href="#foot1x2"&gt;1&lt;/a&gt;&lt;/sup&gt;
&lt;br /&gt;
&lt;br /&gt;Some more examples of subordination interacting with coverage checking can be seen in &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-2/linearmatch.levy#L22-36"&gt;linearmatch.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Subordination and identity in case analysis&lt;/h3&gt;We use subordination data for one other optimization. The following function is also from &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-2/linearmatch.levy#L7-12"&gt;linearmatch.levy&lt;/a&gt;; it takes a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -o list&lt;/span&gt;&lt;/tt&gt; and discards everything until the place where the hole in the list was. &lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;run&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;run&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(int -o list)&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff"&gt;list&lt;/span&gt; is&lt;br/&gt;    fun &lt;span style="color:#0000ff"&gt;x&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(int -o list)&lt;/span&gt; -&gt;&lt;br/&gt;      match &lt;span style="color:#0000ff"&gt;x&lt;/span&gt; with&lt;br/&gt;        | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;] Cons hole &lt;span style="color:#0000ff"&gt;l&lt;/span&gt;&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;l&lt;/span&gt;&lt;br/&gt;        | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;] Cons &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;dx&lt;/span&gt; hole)&lt;/span&gt; -&gt; force &lt;span style="color:#0000ff"&gt;run&lt;/span&gt; &lt;span style="color:#0000ff"&gt;dx&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;Because Levy# is limited to depth-1 pattern matching, a pattern match should really only say that the hole is &lt;i&gt;somewhere in&lt;/i&gt; a subterm, not that the hole is &lt;i&gt;exactly at&lt;/i&gt; a subterm. This would indicate that the first pattern should really be &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;[hole: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;] Cons (&lt;span style="color:#0000ff"&gt;di&lt;/span&gt; hole) &lt;span style="color:#0000ff"&gt;l&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;, but by subordination analysis, we know that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; is not subordinate to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;&lt;/tt&gt; and so therefore the only value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -o int&lt;/span&gt;&lt;/tt&gt; is the identity function, so &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;di = [hole:int] hole&lt;/span&gt;&lt;/tt&gt; and we can beta-reduce &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;([hole:int] hole) &lt;span style="color:#009900"&gt;hole&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; to get just &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;hole&lt;/span&gt;&lt;/tt&gt;.
&lt;br /&gt;
&lt;br /&gt;So subordination is a very helpful analysis for us; it allows us to avoid writing some patterns altogether (patterns that bind variables with types that aren't inhabited) and it lets us simplify other patterns by noticing that for certain types "the hole appears somewhere in this subterm" is exactly the same statement as "this subterm is exactly the hole."
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Implementation&lt;/h2&gt;In order to efficiently pattern match against the beginning of a list, we need to be able to rapidly tell which sub-part of a data structure the hole can be found in. This wasn't a problem for difference lists and difference queues, since subordination analysis is enough to tell us where the hole will be if it exists, but consider trees defined as follows:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#009900"&gt;data Leaf: &lt;span style="color:#0000ff"&gt;tree&lt;/span&gt;&lt;br/&gt;      | Node: &lt;span style="color:#0000ff"&gt;tree -o tree -o tree&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;If we match against a value of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt;, we need to deal with the possibility that it is the identity function, the possibility that the hole is in the left subtree, and the possibility that the hole is in the right subtree. This means that, if we wish for matching to be a constant-time operation, we also need to be able to &lt;i&gt;detect&lt;/i&gt; whether the hole is in the left or right subtree without doing a search of the whole tree.
&lt;br /&gt;
&lt;br /&gt;This is achieved by adding an extra optional field to the in-memory representation of structures, a number that indicates where the hole is. Jason Reed correctly pointed out in a &lt;a href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-13-almost-difference.html?showComment=1313337306965#c701274819557663771"&gt;comment&lt;/a&gt; that for the language extension described in the previous installment, there was actually no real obstacle to having the runtime handle multiple overlapping holes and types like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o (tree -o tree)&lt;/span&gt;&lt;/tt&gt;. But due to the way we're modifying the data representation to do matching, the restriction to having at most one hole at a time is now critical: the runtime stores directions to &lt;i&gt;the&lt;/i&gt; hole at every point in the structure.
&lt;br /&gt;
&lt;br /&gt;The memory representation produced by the value code &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: tree] Node (Node Leaf Leaf) (Node (Node hole Leaf) Leaf)&lt;/span&gt;&lt;/tt&gt; might look something like this, where I represent the number indicating where the hole is by circling the indicated hole in red:
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-fig4.png" /&gt;
&lt;br /&gt;If the hole is filled, the extra data (the red circles) will still exist, but the part of the runtime that does operations on normal inductively defined datatypes can just ignore the presence of this extra data. (In a full implementation of these ideas, this would likely complicate garbage collection somewhat.)
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Case Study: Holey Trees and Zippers&lt;/h2&gt;The binary trees discussed before, augmented with integers at the leaves, are the topic of this case study. A famous data structure for functional generic programming is Huet's zipper [&lt;a href="#5x2"&gt;5&lt;/a&gt;, &lt;a href="#6x2"&gt;6&lt;/a&gt;], which describes inside-out paths through inductive types such as trees. The idea of a zipper is that it allows a programmer to place themselves &lt;i&gt;inside&lt;/i&gt; a tree and move up, left-down, and right-down the tree using only constant-time operations based on pointer manipulation.
&lt;br /&gt;
&lt;br /&gt;The zipper for trees looks like this:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#009900"&gt;data Top: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt;&lt;br/&gt;      | Left: &lt;span style="color:#0000ff"&gt;path -o tree -o path&lt;/span&gt;&lt;br/&gt;      | Right: &lt;span style="color:#0000ff"&gt;tree -o path -o path&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;In this case study, we will show how to coerce linear functions &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt; into the zipper data structure &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;path&lt;/span&gt;&lt;/tt&gt; and vice versa. 
&lt;br /&gt;
&lt;br /&gt;In order to go from a linear function &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt; to a zipper &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;path&lt;/span&gt;&lt;/tt&gt;, we use a function that takes two arguments, an "outside" &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;path&lt;/span&gt;&lt;/tt&gt; and an "inside" &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt;. As we descend into the tree-with-a-hole by pattern matching against the linear function, we tack the subtrees that aren't on the path to the hole onto the outside &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;path&lt;/span&gt;&lt;/tt&gt;, so that in every recursive call the zipper gets bigger and the linear function gets smaller.&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;zip_of_lin&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;enzip&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt; &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; is &lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;outside&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt; &lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;inside&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; -&gt; &lt;br/&gt;       match &lt;span style="color:#0000ff"&gt;inside&lt;/span&gt; with&lt;br/&gt;         | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;tree&lt;/span&gt;] hole&lt;/span&gt; -&gt; &lt;br/&gt;             return &lt;span style="color:#0000ff"&gt;outside&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;tree&lt;/span&gt;] Node (&lt;span style="color:#0000ff"&gt;left&lt;/span&gt; hole) &lt;span style="color:#0000ff"&gt;right&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enzip&lt;/span&gt; &lt;span style="color:#0000ff"&gt;(Left outside right)&lt;/span&gt; &lt;span style="color:#0000ff"&gt;left&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;[hole: &lt;span style="color:#0000ff"&gt;tree&lt;/span&gt;] Node &lt;span style="color:#0000ff"&gt;left&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;right&lt;/span&gt; hole)&lt;/span&gt; -&gt;  &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enzip&lt;/span&gt; &lt;span style="color:#0000ff"&gt;(Right left outside)&lt;/span&gt; &lt;span style="color:#0000ff"&gt;right&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;Given this function, the obvious implementation of its inverse just does the opposite, shrinking the zipper with every recursive call and tacking the removed data onto the linear function:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;lin_of_zip&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt; &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; is &lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;outside&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt;&lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;inside&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; -&gt;&lt;br/&gt;       match &lt;span style="color:#0000ff"&gt;outside&lt;/span&gt; with&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Top&lt;/span&gt; -&gt; &lt;br/&gt;             return &lt;span style="color:#0000ff"&gt;inside&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Left &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;right&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;([hole: tree] Node (inside hole) right)&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Right &lt;span style="color:#0000ff"&gt;left&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;([hole: tree] Node left (inside hole))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;That's the obvious implementation, where we tack things on to the outside of the linear function. Linear functions have the property, of course, that you can tack things on to the inside or the outside, which gives us the opportunity to consider another way of writing the inverse that looks more traditionally like an induction on the structure of the zipper:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;lin_of_zip'&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff"&gt;(tree -o tree)&lt;/span&gt; is&lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;path&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; -&gt; &lt;br/&gt;       match &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; with&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Top&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;[hole: tree] hole&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Left &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; &lt;span style="color:#0000ff"&gt;right&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;lin&lt;/span&gt; in&lt;br/&gt;             return &lt;span style="color:#0000ff"&gt;[hole: tree] lin (Node hole right)&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Right &lt;span style="color:#0000ff"&gt;left&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt;&lt;/span&gt; -&gt; &lt;br/&gt;             force &lt;span style="color:#0000ff"&gt;enlin&lt;/span&gt; &lt;span style="color:#0000ff"&gt;path&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;lin&lt;/span&gt; in&lt;br/&gt;             return &lt;span style="color:#0000ff"&gt;[hole: tree] lin (Node left hole)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;These functions, and examples of their usage, can be found in &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-2/linear-vs-zipper.levy"&gt;linear-vs-zipper.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Foreshadowing&lt;/h3&gt;This installment was written quickly after the first one; I imagine there will be a bigger gap before the third installment, so I'm going to go ahead and say a bit about where I'm going with this, using the case study as motivation.
&lt;br /&gt;
&lt;br /&gt;I wrote three functions: &lt;ul&gt;&lt;li&gt;&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;lin_of_zip&lt;/span&gt;&lt;/tt&gt; turns zippers into linear functions by case analyzing the zipper and tacking stuff onto the "beginning" our outside of the linear function,&lt;/li&gt;&lt;li&gt;&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;lin_of_zip'&lt;/span&gt;&lt;/tt&gt; turns zippers into linear functions by inducting over the path and tacking stuff onto the "end" or inside of the linear function, and&lt;/li&gt;&lt;li&gt;&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;zip_of_lin&lt;/span&gt;&lt;/tt&gt; turns linear functions into zippers by case analyzing the "beginning" or outside of the linear function and tacking stuff on to the zipper.&lt;/li&gt;&lt;/ul&gt;What about &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;zip_of_lin'&lt;/span&gt;&lt;/tt&gt;, which turns linear functions into zippers by case analyzing the "end" or inside of the linear function? It's easy enough to describe what this function would look like:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;#  val zip_of_lin' = thunk rec enzip: (tree -o tree) -&gt; F path is &lt;br/&gt;#    fun lin: (tree -o tree) -&gt; &lt;br/&gt;#      match lin with&lt;br/&gt;#        | [hole: tree] hole -&gt; return Top&lt;br/&gt;#        | [hole: tree] lin' (Node hole right) -&gt; &lt;br/&gt;#            force enzip lin' to path in&lt;br/&gt;#            return Left path right&lt;br/&gt;#        | [hole: tree] lin' (Node left hole) -&gt;&lt;br/&gt;#            force enzip lin' to path in&lt;br/&gt;#            return Right left path ;;&lt;/span&gt;&lt;/pre&gt;Toto, we're not in the pattern fragment anymore, but if we turn the representation of linear functions into &lt;i&gt;doubly linked lists&lt;/i&gt; (or a double-ended-queues implemented as linked lists, perhaps), I believe we can implement these functions without trouble. At that point, we basically don't need the zippers anymore: instead of declaring that &lt;a href="http://www.google.com/search?sourceid=chrome&amp;ie=UTF-8&amp;q=the+derivative+of+a+type+is+the+type+of+its+one+hole+contexts"&gt;the derivative of a type is the type of its one-hole contexts&lt;/a&gt;, we can make the obvious statement that the linear function from a type to itself is the type of one-hole contexts of that type, and we can program accordingly: no new boilerplate datatype declarations needed!
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;A relatively simple modification of the runtime from the previous installment, a runtime data tag telling us where the hole is, allows us to efficiently pattern match against linear representational functions. This modification makes the use of linear representational functions far more general than just a tool for efficiently implementing a logic programming idiom of difference lists. In fact, I hope the case study gives a convincing case that these holey data structures can come close to capturing many of the idioms of &lt;i&gt;generic programming&lt;/i&gt;, though that argument won't be fully developed until the third installment, where we move beyond patterns that come from the Miller/Schack-Nielsen/Sch&amp;uuml;rmann pattern fragment.
&lt;br /&gt;
&lt;br /&gt;More broadly, we have given a purely logical and declarative type system that can implement algorithms that would generally be characterized as imperative algorithms, not functional algorithms. Is it fair to call the queue representation a "functional data structure"? It is quite literally a data structure that is a function, after all! If it is (and I'm not sure it is), this would seem to challenge at least my personal understanding of what "&lt;a href="http://cstheory.stackexchange.com/questions/1539/whats-new-in-purely-functional-data-structures-since-okasaki"&gt;functional data structures&lt;/a&gt;" and functional algorithms are in the first place.
&lt;br /&gt;
&lt;br /&gt;&lt;hr /&gt;&lt;small&gt;
&lt;br /&gt;&lt;sup&gt;&lt;a name="foot1x2"&gt;&lt;/a&gt;1&lt;/sup&gt; This is true even though there are, in fact, no closed values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;q -o option&lt;/span&gt;&lt;/tt&gt; even if we don't have the no-overlapping-holes restriction (proof left as an exercise for the reader).
&lt;br /&gt;[&lt;a name="1x2"&gt;&lt;/a&gt;1] Daniel R. Licata, Noam Zeilberger, and Robert Harper, "&lt;a href="http://www.cs.cmu.edu/~drl/pubs/lzh08focbind/lzh08focbind.pdf"&gt;Focusing on Binding and Computation&lt;/a&gt;," LICS 2008.
&lt;br /&gt;[&lt;a name="2x2"&gt;&lt;/a&gt;2] Daniel R. Licata and Robert Harper, "&lt;a href="http://www.cs.cmu.edu/~drl/pubs/lh09unibind/lh09unibind.pdf"&gt;A Universe of Binding and Computation&lt;/a&gt;," ICFP 2009.
&lt;br /&gt;[&lt;a name="3x2"&gt;&lt;/a&gt;3] Dale Miller, "&lt;a href="http://www.lix.polytechnique.fr/Labo/Dale.Miller/papers/jlc91.pdf"&gt;A Logic Programming Language with Lambda-Abstraction, Function Variables, and Simple Uniﬁcation&lt;/a&gt;," JLC 1(4), 1991.
&lt;br /&gt;[&lt;a name="4x2"&gt;&lt;/a&gt;4] Anders Schack-Nielsen and Carsten Sch&amp;uuml;rmann, "&lt;a href="http://www.itu.dk/people/anderssn/pat-uni-art.pdf"&gt;Pattern Uniﬁcation for the Lambda Calculus with Linear and Afﬁne Types&lt;/a&gt;," LFMTP 2010.
&lt;br /&gt;[&lt;a name="5x2"&gt;&lt;/a&gt;5] G&amp;uacute;rard Huet, "&lt;a href="http://journals.cambridge.org/action/displayAbstract?fromPage=online&amp;aid=44121"&gt;Function Pearl: The Zipper&lt;/a&gt;," JFP 1997.
&lt;br /&gt;[&lt;a name="6x2"&gt;&lt;/a&gt;6] Wikipedia: &lt;a href="http://en.wikipedia.org/wiki/Zipper_(data_structure)"&gt;Zipper (data structure)&lt;/a&gt;.
&lt;br /&gt;&lt;/small&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-985836498877684717?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/HnTVJKJ8NDE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/985836498877684717/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-23-case-analysis-on.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/985836498877684717?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/985836498877684717?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/HnTVJKJ8NDE/holey-data-part-23-case-analysis-on.html" title="Holey Data, Part 2/3: Case Analysis on Linear Functions" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>1</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/holey-data-part-23-case-analysis-on.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QFRnc5fyp7ImA9WhdQFUw.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-4709289504582259567</id><published>2011-08-12T15:09:00.000-04:00</published><updated>2011-08-16T12:15:17.927-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-16T12:15:17.927-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="levy" /><category scheme="http://www.blogger.com/atom/ns#" term="difference lists" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="holey data" /><title>Holey Data, Part 1/3: (Almost) Difference Lists</title><content type="html">This series has been brewing in my head since a year ago, starting at the &lt;a href="http://osl.iu.edu/wgp2010/"&gt;2010 Workshop on Generic Programming&lt;/a&gt; in Baltimore. It was at least a quarter-baked idea by the time I asked, on the CSTheory Stackexchange, a question that amounted to "are there functional programming difference lists that act like logic programming difference lists"? [&lt;a href="#1"&gt;1&lt;/a&gt;]
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Difference lists&lt;/h2&gt;Difference lists, which are deep lore of the logic programming community, are essentially data structures that allow you to append to the beginning and the end of the list as a constant time operation; they can also be turned back into "regular" lists as a constant time operation. You can see [&lt;a href="#2"&gt;2&lt;/a&gt;,&lt;a href="#3"&gt;3&lt;/a&gt;,&lt;a href="#4"&gt;4&lt;/a&gt;] for details, but I'd almost encourage you not to: logic programming difference lists are a bit crazy.
&lt;br /&gt;
&lt;br /&gt;Let me give you two ways of thinking about difference lists. If you're a lazy person (in the Haskell sense), you may say that difference lists really have something to do with laziness in functional programming languages. William Lovas showed me some crazy Haskell code yesterday that does something of this flavor, and there's a paper that espouses this viewpoint [&lt;a href="#5"&gt;5&lt;/a&gt;]. I'll stick with a different viewpoint: difference lists are &lt;i&gt;functions from lists to lists&lt;/i&gt;. This is how difference lists are implemented in the Haskell Data.DList library [&lt;a href="#6"&gt;6&lt;/a&gt;], and you can find people that back-ported the idea that difference lists are "really" functions to higher-order logic programming languages [&lt;a href="#7"&gt;7&lt;/a&gt;].
&lt;br /&gt;
&lt;br /&gt;The problem with the idea of difference lists being functions is that you lose one of the fundamental properties that you started with: while it depends on how you implement things, difference lists implemented as functions will usually have a O(1) append operation but a O(n) "turn me into a regular list" operation. For a discussions of why, see the &lt;a href="http://cstheory.stackexchange.com/questions/2432/difference-lists-in-functional-programming/2442#2442"&gt;answers&lt;/a&gt; to my question on CSTheory Stackexchange. 
&lt;br /&gt;
&lt;br /&gt;I've believed for some time that this unfortunate O(n)ness could be overcome, but I wanted a working proof-of concept implementation before I talked about it. It was during my recent visit to France that I realized that I really needed to base the proof-of-concept off of a language that was appropriately persnickety about the difference between what I called "value code" and what I called "computation code" in the previous post. And then I found Levy, and embraced and extended it into Levy#.&lt;sup&gt;&lt;a href="#foot1"&gt;1&lt;/a&gt;&lt;/sup&gt; So at this point you should &lt;a href="http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html"&gt;read the previous post&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Representing datatypes&lt;/h2&gt;In the last post I talked about declaring and using datatypes in Levy#, using the example of lists of integers:&lt;pre&gt;   &lt;span style="color:#009900; font-weight:bold"&gt;data Nil: &lt;span style="color:#0000ff"&gt;list&lt;/span&gt;&lt;br/&gt;      | Cons: &lt;span style="color:#0000ff"&gt;int -o list -o list&lt;/span&gt;&lt;/pre&gt;It's necessary to say a few words about how these things are implemented. Every value in Levy# is represented in the OCaml interpreter as a &lt;tt&gt;heapdata ref&lt;/tt&gt; - that is, a mutable pointer into a "box" in memory. Some boxes hold integers, other boxes hold the code and environments that represent suspended (&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;thunk&lt;/span&gt;&lt;/tt&gt;ed) computations. Declared constants from datatype declarations are another kind of box which holds both a tag (like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Nil&lt;/tt&gt;&lt;/tt&gt; or &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons&lt;/tt&gt;&lt;/tt&gt;) and an appropriate number of values (that is, pointers) for the given datatype.
&lt;br /&gt;
&lt;br /&gt;As an example, here's the way the list &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons 3 (Cons 7 Nil)&lt;/span&gt;&lt;/tt&gt;, stored in the variable &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;xs&lt;/span&gt;&lt;/tt&gt;, could be laid out in memory:
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-fig1.png" /&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Representing difference lists&lt;/h2&gt;&lt;h3&gt;Types&lt;/h3&gt;On the level of &lt;i&gt;types&lt;/i&gt;, a difference list will be represented as a member of the value type (the Linear LF type) &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;. This adequately represents what a difference list is better than the &lt;tt&gt;list -&gt; list&lt;/tt&gt; type of Haskell or Lambda Prolog/Twelf. In Haskell, &lt;i&gt;lots&lt;/i&gt; of functions have type &lt;tt&gt;list -&gt; list&lt;/tt&gt;, including the list reversal function. Lambda Prolog/Twelf does better; the LF type &lt;tt&gt;list -&gt; list&lt;/tt&gt; really has to be &lt;i&gt;substitution function&lt;/i&gt; - it can only take a list and plug it into designated places in another list. But &lt;tt&gt;&amp;lambda;x. Nil&lt;/tt&gt; is a perfectly good LF value of type &lt;tt&gt;list -&gt; list&lt;/tt&gt;. In other words, it's not necessarily the case that applying something to a function is equivalent to tacking that thing on to the end of the difference list - the applied argument can simply be ignored. 
&lt;br /&gt;
&lt;br /&gt;Linear functions must use their argument exactly once, so linear functions &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt; accurately represent the idea of difference lists, a list with &lt;i&gt;exactly one missing list somewhere in it&lt;/i&gt;. For lists this is kind of a dumb way to put it: the missing list has to go at the end of a series of &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons&lt;/span&gt;&lt;/tt&gt;es or nowhere at all, so the linearity forces there to be one (as opposed to zero) occurrences of the hole. If we were talking about terms of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree&lt;/span&gt;&lt;/tt&gt;, then linearity would enforce that there was one (as opposed to zero or two or three...) occurrences of the hole. We'll come back to that later...
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Terms&lt;/h3&gt;Recall from the previous post that Levy# starts off syntactically precluded from forming values of this type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;; we'll have to fix that by adding new syntax. On the level of &lt;i&gt;syntax&lt;/i&gt;, a difference list will be represented using a Twelf-like notation where "&amp;lambda; x:&amp;tau;.v" is written as &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[x:tau] v&lt;/span&gt;&lt;/tt&gt;. 
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;Example&lt;/b&gt; The difference list containing first 9 and then 4 will be represented as &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] Cons 9 (Cons 4 hole)&lt;/span&gt;&lt;/tt&gt;; let's call that difference list &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dxs&lt;/span&gt;&lt;/tt&gt;. Let &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dys&lt;/span&gt;&lt;/tt&gt; be the some other piece of value code with type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;, and let &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;xs&lt;/span&gt;&lt;/tt&gt; be the example difference list &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons 3 (Cons 7 Nil)&lt;/span&gt;&lt;/tt&gt; from the previous section. 
&lt;br /&gt;
&lt;br /&gt;Then &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dxs xs&lt;/span&gt;&lt;/tt&gt; appends the difference list and regular list by filling in the hole with &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;xs&lt;/span&gt;&lt;/tt&gt;; the result is &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons 9 (Cons 4 (Cons 3 (Cons 7 Nil)))&lt;/span&gt;&lt;/tt&gt;. Similarly, &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] dxs (dys hole)&lt;/span&gt;&lt;/tt&gt; is a piece of value code that forms a new difference list by appending the two smaller difference lists.
&lt;br /&gt;
&lt;br /&gt;In terms of the expressive power of these difference lists, that's pretty much the story: the file &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-1/linear.levy"&gt;linear.levy&lt;/a&gt; has some more examples, which can be run in the "holey-blog-1" tagged point in the repository.
&lt;br /&gt;
&lt;br /&gt;&lt;b&gt;A Linear Logic Aside&lt;/b&gt;. This, perhaps, clears up the reason I used linear implication to define constructors like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons&lt;/span&gt;&lt;/tt&gt;. Say instead of &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons&lt;/span&gt;&lt;/tt&gt; we had &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ConsBad&lt;/span&gt;&lt;/tt&gt;, a Linear LF constant of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;int -&gt; list -&gt; list&lt;/span&gt;&lt;/tt&gt;. That type is equivalent in Linear LF to a term of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;!int -o !list -o list&lt;/span&gt;&lt;/tt&gt;. The exclamation points ("bangs") prevent the occurrence of a linear variable in either argument to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ConsBad&lt;/span&gt;&lt;/tt&gt;, so &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] ConsBad 9 (ConsBad 4 hole)&lt;/span&gt;&lt;/tt&gt; would &lt;i&gt;NOT&lt;/i&gt; be a (piece of value code)/(Linear LF term) of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;. 
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Memory representation&lt;/h3&gt;So far, I've explained how difference lists can be represented as linear functions, but what I originally promised was difference lists with O(1) append and turn-into-a-regular-list operations. To do this, I need to explain how linear functions can be represented in memory. A linear function is represented as another kind of box in memory, one with two pointers. The first pointer acts like a regular value - it points to the beginning of a data structure. The second pointer acts like a pointer into a data structure: it locates the "hole" - the location of the linear variable. This is the in-memory representation of our example &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;[hole: list] Cons 9 (Cons 4 hole)&lt;/span&gt;&lt;/tt&gt; from above, stored as the variable &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dxs&lt;/span&gt;&lt;/tt&gt;.
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-fig2.png" /&gt;
&lt;br /&gt;If we want to apply this linear function to a value and thereby insert a list into the hole, we merely have to follow the second hole-pointer and write to it, and then return the first value-pointer as the result. Voilà, application with only local pointer manipulation! If the result of applying &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;xs&lt;/span&gt;&lt;/tt&gt; to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dxs&lt;/span&gt;&lt;/tt&gt; was stored as the variable &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ys&lt;/span&gt;&lt;/tt&gt;, the state of memory would look something like this:
&lt;br /&gt;&lt;img src="http://typesafety.net/rfl/rjs-fig3.png" /&gt;
&lt;br /&gt;The catch is that the linear function box that &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;dxs&lt;/span&gt;&lt;/tt&gt; refers to no longer can be used in the same way: if we tried to write something different to the hole pointer, disaster could result: it would change the value of &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ys&lt;/span&gt;&lt;/tt&gt;!
&lt;br /&gt;
&lt;br /&gt;Therefore, the difference list, and all linear function values, are &lt;i&gt;use-only-once data structures&lt;/i&gt;, and the current implementation invalidates used linear function values (shown by the red X in the figure above) and will raise a runtime error if they are used twice. This could be precluded with a type system that ensured that values whose type was a linear function are used, computationally, in an &lt;i&gt;affine&lt;/i&gt; way - that is, used at most once. Work on affine type systems is interesting, it's important, I've &lt;a href="http://requestforlogic.blogspot.com/2011/03/request-for-typestate-part-2-linear.html"&gt;written about it before&lt;/a&gt;, but I see it as an orthogonal issue. That's all I really have to say about that.
&lt;br /&gt;
&lt;br /&gt;And that's how we implement linear&lt;sup&gt;&lt;a href="#foot2"&gt;2&lt;/a&gt;&lt;/sup&gt; representational functions with constant time &lt;i&gt;composition&lt;/i&gt; and &lt;i&gt;application&lt;/i&gt;, which corresponds to implementing different lists with O(1) &lt;i&gt;append&lt;/i&gt; and &lt;/i&gt;turn-into-a-regular-list operations&lt;/i&gt;. 
&lt;br /&gt;
&lt;br /&gt;&lt;small&gt;&lt;i&gt;(Disclaimer: this section is a bit of an idealization of what's actually going on in the OCaml implementation, but it's honest enough in the sense that everything's really implemented by local pointer manipulation, and represents what I think you'd expect an complied implementation of this code to do.)&lt;/i&gt;&lt;/small&gt;
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Expressiveness and efficiency&lt;/h3&gt;One cost of our representation strategy is that we can only use values whose type is a linear function in an affine way. Another cost is, because the implementation really thinks in terms of "&lt;i&gt;the&lt;/i&gt; hole," we can't have two-hole structures like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tree -o tree -o tree&lt;/span&gt;&lt;/tt&gt;. &lt;i&gt;(Edit: Jason, in the comments, points out that I may be wrong about more-than-one-hole-structures being problematic.)&lt;/i&gt; But, if we were interested primarily in &lt;i&gt;expressiveness&lt;/i&gt; and were willing to sacrifice constant-time composition and application guarantees, then it would absolutely be possible to have reusable difference lists and linear types representing &lt;i&gt;n&lt;/i&gt;-holed contexts for any &lt;i&gt;n&lt;/i&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Case Study: The Dutch National Flag Problem&lt;/h2&gt;William Lovas proposed this example, and I think it's great: the Dutch National Flag problem was proposed by Edsger Dijkstra as a generalization of what happens in a Quicksort partition step. The logic/functional programming variant of this problem is as follows: you have a list of red, white, and blue tagged numbers. You want to stably sort these to put red first, white second, and blue third: in other words, if the ML function &lt;tt&gt;red&lt;/tt&gt; filters out the sublist of red-tagged numbers and so on, you want to return &lt;tt&gt;red list @ white list @ blue list&lt;/tt&gt;. 
&lt;br /&gt;
&lt;br /&gt;That's easy: the catch is that you can't use append, because you're only allowed to iterate over the initial unpartitioned list, and you're only allowed to iterate over that list one time. 
&lt;br /&gt; 
&lt;br /&gt;The solution in Levy# extended with difference lists is to pass along three difference lists representing the partitioned &lt;i&gt;beginning&lt;/i&gt; of the full list and a regular list representing the un-partitioned &lt;i&gt;end&lt;/i&gt; of the full list. At each step, you pick an item off the un-partitioned list and (constant-time) append it on to the end of the appropriate difference list. When there's nothing left in the un-partitioned list, you (constant-time) append the three difference lists while (constant-time) turning the concatenated difference lists into a normal list.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;dutch'&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;loop&lt;/span&gt; : &lt;br/&gt;    &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt;&lt;br/&gt;      -&gt; &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt;&lt;br/&gt;        -&gt; &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt;&lt;br/&gt;          -&gt; &lt;span style="color:#0000ff"&gt;list&lt;/span&gt;&lt;br/&gt;            -&gt; F &lt;span style="color:#0000ff"&gt;list&lt;/span&gt; is &lt;br/&gt;  fun &lt;span style="color:#0000ff"&gt;reds&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt; -&gt; &lt;br/&gt;  fun &lt;span style="color:#0000ff"&gt;whites&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt; -&gt; &lt;br/&gt;  fun &lt;span style="color:#0000ff"&gt;blues&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;(list -o list)&lt;/span&gt; -&gt; &lt;br/&gt;  fun &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;list&lt;/span&gt; -&gt; &lt;br/&gt;    match &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; with&lt;br/&gt;      | &lt;span style="color:#009900"&gt;Nil&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;(reds (whites (blues Nil)))&lt;/span&gt;&lt;br/&gt;      | &lt;span style="color:#009900"&gt;Cons&lt;/span&gt; &lt;span style="color:#0000ff"&gt;x&lt;/span&gt; &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; -&gt; &lt;br/&gt;         (match &lt;span style="color:#0000ff"&gt;x&lt;/span&gt; with &lt;br/&gt;            | &lt;span style="color:#009900"&gt;Red&lt;/span&gt; &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; -&gt; &lt;br/&gt;                force &lt;span style="color:#0000ff"&gt;loop&lt;/span&gt; &lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;([hole: list] reds (Cons x hole))&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;whites&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;blues&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;&lt;br/&gt;            | &lt;span style="color:#009900"&gt;White&lt;/span&gt; &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; -&gt;  &lt;br/&gt;                force &lt;span style="color:#0000ff"&gt;loop&lt;/span&gt; &lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;reds&lt;/span&gt;  &lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;([hole: list] whites (Cons x hole))&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;blues&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;&lt;br/&gt;            | &lt;span style="color:#009900"&gt;Blue&lt;/span&gt; &lt;span style="color:#0000ff"&gt;i&lt;/span&gt; -&gt; &lt;br/&gt;                force &lt;span style="color:#0000ff"&gt;loop&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;reds&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;whites&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;([hole: list] blues (Cons x hole))&lt;/span&gt;&lt;br/&gt;                  &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;This solution is in the repository in the file &lt;a href="https://github.com/robsimmons/levy/blob/holey-blog-1/dutch.levy#L31-62"&gt;dutch.levy&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;I think that the incorporation of linear representational functions as difference lists is beautiful. I've written plenty of Standard ML where I've done tail-recursive manipulations on lists and so either 1) had to keep track of whether I'd called &lt;tt&gt;List.rev&lt;/tt&gt; the right number of times or 2) worried whether all these append operations would end up hurting efficiency. This solution gives you the append functions that you need in a way that makes it easy to think about both the order of items and the runtime cost. And it's all enabled by some very pretty types!
&lt;br /&gt;
&lt;br /&gt;The real straw that broke my back and led to this line of thinking, by the way, was an issue of expressiveness, not efficiency: I was trying to reason about such code that did tail-recursive operations on lists in Agda. That's another story, but it's one that's connected to my thesis in an important way, so I will try to get around to writing it.
&lt;br /&gt;
&lt;br /&gt;In the next installment of the Holey Data series, I'll show how we can pattern match against difference lists in Levy#, which turns linear representational functions from (almost) difference lists into something significantly awesomer than difference lists. 
&lt;br /&gt;
&lt;br /&gt;(P.S. Thanks Paul a.k.a. Goob for sneaking me into the English Department's cluster to make the illustrations for this blog post.)
&lt;br /&gt;
&lt;br /&gt;&lt;hr&gt;&lt;small&gt;
&lt;br /&gt;&lt;sup&gt;&lt;a name="foot1"&gt;&lt;/a&gt;1&lt;/sup&gt; Originally I wanted to base it off of a Noam/Dan/Bob style language based on focusing in polarized logic, but it turns out that focused logic isn't a very natural language to actually program in. I owe a debt to Andrej and Matija for going through the legwork of making CBPV into an implemented toy language that it was possible to play around with. 
&lt;br /&gt;&lt;sup&gt;&lt;a name="foot2"&gt;&lt;/a&gt;2&lt;/sup&gt; Actually, this representation strategy &lt;i&gt;might&lt;/i&gt; work fine not just for linear functions but for regular-old LF substitution functions with zero, one, two... arguments. When I tried to work this out with William Lovas, we tentatively concluded that you might need some sort of union-find structure to make sure that all the holes were effectively pointers to "the same hole." In this note, I only motivated linear functions in terms of adequately representing difference lists; the real beauty of using difference lists starts coming into play with the next two posts in this series.
&lt;br /&gt;&lt;a name="1"&gt;&lt;/a&gt;[1] Robert J. Simmons, "&lt;a href="http://cstheory.stackexchange.com/questions/2432/difference-lists-in-functional-programming"&gt;Difference Lists in Functional Programming&lt;/a&gt;", CSTheory StackExchange.
&lt;br /&gt;&lt;a name="2"&gt;&lt;/a&gt;[2] Wikibook on &lt;a href="http://en.wikibooks.org/wiki/Prolog/Difference_Lists"&gt;Prolog Difference Lists&lt;/a&gt;.
&lt;br /&gt;&lt;a name="3"&gt;&lt;/a&gt;[3] Dale Miller's implementation of (classic, logic-programmey) difference lists: "&lt;a href="http://www.lix.polytechnique.fr/Labo/Dale.Miller/lProlog/cse360/lectures/lect5.html#dlist"&gt;Difference Lists provide access to the tail of a list&lt;/a&gt;".
&lt;br /&gt;&lt;a name="4"&gt;&lt;/a&gt;[4] Frank Pfenning's course notes: "&lt;a href="http://www.cs.cmu.edu/~fp/courses/lp/lectures/11-diff.pdf"&gt;Difference Lists&lt;/a&gt;".
&lt;br /&gt;&lt;a name="5"&gt;&lt;/a&gt;[5] Sandro Etalle and Jon Mountjoy. "&lt;a href="http://doc.utwente.nl/56170/1/etalle00lazy.pdf"&gt;The &lt;i&gt;Lazy&lt;/i&gt; Functional Side of Logic Programming&lt;/a&gt;".
&lt;br /&gt;&lt;a name="6"&gt;&lt;/a&gt;[6] Don Stewart's &lt;a href="http://hackage.haskell.org/packages/archive/dlist/0.5/doc/html/Data-DList.html"&gt;Data.DList&lt;/a&gt; library.
&lt;br /&gt;&lt;a name="7"&gt;&lt;/a&gt;[7] Yves Bekkers and Paul Tarau. "&lt;a href="http://logic.csci.unt.edu/tarau/research/PapersHTML/monadic.html#DIFFLISTS"&gt;The Monads of Difference Lists&lt;/a&gt;".&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-4709289504582259567?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/lYeQVOFUr-M" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/4709289504582259567/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/holey-data-part-13-almost-difference.html#comment-form" title="8 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4709289504582259567?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4709289504582259567?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/lYeQVOFUr-M/holey-data-part-13-almost-difference.html" title="Holey Data, Part 1/3: (Almost) Difference Lists" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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>8</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/holey-data-part-13-almost-difference.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MCQ3Y4eSp7ImA9WhdQFEQ.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-1456587253223940309</id><published>2011-08-11T15:38:00.001-04:00</published><updated>2011-08-16T08:57:42.831-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-16T08:57:42.831-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="functional programming" /><category scheme="http://www.blogger.com/atom/ns#" term="call-by-push-value" /><category scheme="http://www.blogger.com/atom/ns#" term="levy" /><title>Embracing and extending the Levy language</title><content type="html">I started writing the post about the thing I really wanted to write about, but then I realized that the background was already a long post on its own. So, that's this post! It's about two things:&lt;ol&gt;&lt;li&gt;Levy, an implementation of &lt;a href="http://www.cs.bham.ac.uk/~pbl/cbpv.html"&gt;call-by-push-value&lt;/a&gt; that Andrej Bauer and Matija Pretnar wrote in OCaml for the &lt;a href="http://andrej.com/plzoo/"&gt;PL Zoo&lt;/a&gt;. I made a &lt;a href="https://github.com/robsimmons/levy/tree/modprec"&gt;fork of Levy&lt;/a&gt; that, among other small changes, reduces the need for parentheses by making operator precedence more like it is in OCaml.&lt;/li&gt;&lt;li&gt;A more divergent fork of Levy that adds datatypes in a familiar-but-as-yet-unmotivated way. This diverges from the goals of Levy - as a PL Zoo project, Levy aims to be a clean and uncluttered language implementation, and that's not the case for this more divergent fork. I'll call this new version of Levy... let's see... Levy#. Sure, that works.&lt;/li&gt;&lt;/ol&gt;Other things have been written about Levy at &lt;a href="http://math.andrej.com/2008/11/23/a-toy-call-by-push-value-language/"&gt;Andrej's blog&lt;/a&gt; and &lt;a href="http://lambda-the-ultimate.org/node/4314"&gt;LtU&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Basic concepts&lt;/h2&gt;The big idea of call-by-push-value, and, in turn, Levy, is that it is a programming language that is incredibly picky about the difference between code that builds data (I'll call this &lt;i&gt;value code&lt;/i&gt; as shorthand) and code that does stuff (I'll call this &lt;i&gt;computation code&lt;/i&gt;). Value code tends to be really boring: &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;3&lt;/span&gt;&lt;/tt&gt; builds an integer value and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;true&lt;/span&gt;&lt;/tt&gt; builds a boolean value. Levy also builds in a couple of total binary operations on integers, so &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;3 + x&lt;/span&gt;&lt;/tt&gt; and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;y &amp;lt; 12&lt;/span&gt;&lt;/tt&gt; are both viewed by Levy as value code. Variables are always value code. 
&lt;br /&gt;
&lt;br /&gt;Computation code is more interesting. If-statements are computation code: &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;if &lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt; then c1 else c2&lt;/span&gt;&lt;/tt&gt; examines the value built by &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt;&lt;/tt&gt; and then either does the stuff described by &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c1&lt;/span&gt;&lt;/tt&gt; or else does the stuff described by &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c2&lt;/span&gt;&lt;/tt&gt;. Functions are computation code: &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;fun &lt;span style="color:#0000ff; font-weight:bold"&gt;x&lt;/span&gt;: &lt;span style="color:#0000ff; font-weight:bold"&gt;ty&lt;/span&gt; -&gt; c&lt;/span&gt;&lt;/tt&gt; receives a value and then does the stuff described by &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/tt&gt;, possibly using the value it received. 
&lt;br /&gt;
&lt;br /&gt;The computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;return &lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; does a very simple thing: it takes the value built by &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt;&lt;/tt&gt; and says "look, I made you a value." If the value code &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt;&lt;/tt&gt; had value type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/tt&gt;, then the computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;return &lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; has computation type &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;F &lt;span style="color:#0000ff; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;. So yeah: I hadn't talked about types yet, but pieces of value code are given value types and pieces of computation code are given computation types.&lt;sup&gt;&lt;a href="#foot1x0"&gt;1&lt;/a&gt;&lt;/1&gt;&lt;/sup&gt; 
&lt;br /&gt;
&lt;br /&gt;Which brings us to an interesting kind of value code that I didn't mention before: &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;thunk &lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; wraps up (and suspends) the computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/tt&gt; in a value; if the computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/tt&gt; had computation type &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/tt&gt;, then the value code &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;thunk &lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; has value type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;U &lt;span style="color:#cc4020; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;.
&lt;br /&gt;
&lt;br /&gt;The typical type of a function that would be written as &lt;tt&gt;int -&gt; int&lt;/tt&gt; in ML is &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;U &lt;span style="color:#cc4020; font-weight:bold"&gt;(&lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff; font-weight:bold"&gt;int&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;. It has to be a value type (ML &lt;a href="http://existentialtype.wordpress.com/2011/04/02/functions-are-values/"&gt;functions are values&lt;/a&gt;), hence the "&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;U&lt;/span&gt;&lt;/tt&gt;", and the computation code in the function wants to take a value, do some stuff, and eventually return an integer. Here's an implementation of the absolute value function:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk &lt;span style="color:#cc4020"&gt;fun &lt;span style="color:#0000ff"&gt;n&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; -&gt; &lt;br/&gt;     if &lt;span style="color:#0000ff"&gt;n &lt; 0&lt;/span&gt;&lt;br/&gt;     then return &lt;span style="color:#0000ff"&gt;0 - n&lt;/span&gt;&lt;br/&gt;     else return &lt;span style="color:#0000ff"&gt;n&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;In order to use the absolute value function, we have to "un-thunk" the computation code inside of the value: the computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;force &lt;span style="color:#0000ff"&gt;v&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; does this. Where we'd write &lt;tt&gt;(abs 4)&lt;/tt&gt; in ML, we write &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;force &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; &lt;span style="color:#0000ff"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt; in Levy (&lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;force&lt;/span&gt;&lt;/tt&gt; binds more tightly than anything, including application).
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Evaluation order&lt;/h2&gt;A consequence of being persnickety about the difference between value code and computation code is that Levy is very explicit about sequencing. The SML/Haskell/OCaml code "&lt;tt&gt;foo(abs 4,abs 5)&lt;/tt&gt;" means "call &lt;tt&gt;foo&lt;/tt&gt; with the absolute values of 4 and 5&lt;/tt&gt;." One occasionally hard-learned lesson for people who have programmed in both SML and OCaml is that, if &lt;tt&gt;abs&lt;/tt&gt; contains effects, this code might do different things: SML has a specified left-to-right evaluation order, but OCaml's evaluation order is unspecified, and in practice it's right-to-left. 
&lt;br /&gt;
&lt;br /&gt;Such underspecification is impossible in Levy, since calling a function is a computation, and computations can't be included directly in values! Instead, if I have computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c&lt;/span&gt;&lt;/tt&gt; of type &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;F &lt;span style="color:#0000ff; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/span&gt;&lt;/tt&gt;, we expect it to do some stuff and then say "look, I made you a value (of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ty&lt;/span&gt;&lt;/tt&gt;)." The computation code &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c1 to &lt;span style="color:#0000ff; font-weight:bold"&gt;x&lt;/span&gt; in c2&lt;/span&gt;&lt;/tt&gt; does the stuff described by &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c1&lt;/span&gt;&lt;/tt&gt;, and when that stuff involves saying "look, I made you a value", that value is bound to &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;x&lt;/span&gt;&lt;/tt&gt; and used to do the stuff described by &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;c2&lt;/span&gt;&lt;/tt&gt;. Therefore, when translate our SML/Haskell/OCaml code above to Levy, we have to explicitly write either&lt;pre&gt;   &lt;span style="color:#cc4020; font-weight:bold"&gt;force &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; &lt;span style="color:#0000ff"&gt;4&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;x1&lt;/span&gt; in&lt;br/&gt;   force &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; &lt;span style="color:#0000ff"&gt;5&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt; in&lt;br/&gt;   force &lt;span style="color:#0000ff"&gt;foo&lt;/span&gt; &lt;span style="color:#0000ff"&gt;x1&lt;/span&gt; &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;or&lt;pre&gt;   &lt;span style="color:#cc4020; font-weight:bold"&gt;force &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; &lt;span style="color:#0000ff"&gt;5&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt; in&lt;br/&gt;   force &lt;span style="color:#0000ff"&gt;abs&lt;/span&gt; &lt;span style="color:#0000ff"&gt;4&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;x1&lt;/span&gt; in&lt;br/&gt;   force &lt;span style="color:#0000ff"&gt;foo&lt;/span&gt; &lt;span style="color:#0000ff"&gt;x1&lt;/span&gt; &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;That concludes the introduction of Levy, (my slightly de-parenthesized fork of) the language implemented by Bauer and Pretnar. There are two example files &lt;a href="https://github.com/robsimmons/levy/blob/modprec/example.levy"&gt;here&lt;/a&gt; (discusses basics) and &lt;a href="https://github.com/robsimmons/levy/blob/modprec/functions.levy"&gt;here&lt;/a&gt; (discusses functions).
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Matching&lt;/h2&gt;The first new feature in Levy# is the addition of a new kind of computation code, &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;match &lt;span style="color:#0000ff"&gt;v&lt;/span&gt; with | &lt;span style="color:#009900"&gt;pat1&lt;/span&gt; -&gt; c1 ...&lt;/span&gt;&lt;/tt&gt; that is a generalization of both let-expressions &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;let &lt;span style="color:#0000ff"&gt;x&lt;/span&gt; be &lt;span style="color:#0000ff"&gt;v&lt;/span&gt; in c&lt;/span&gt;&lt;/tt&gt; and if-expressions &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;if &lt;span style="color:#0000ff; font-weight:bold"&gt;v&lt;/span&gt; then c1 else c2&lt;/span&gt;&lt;/tt&gt; from Levy. Patterns like &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;pat1&lt;/span&gt;&lt;/tt&gt; are a refinement of value code: constants are patterns, variables are patterns (variables in patterns are binding occurrences, like in most functional languages), but addition is not a pattern, and variables can only appear once in a pattern. 
&lt;br /&gt;
&lt;br /&gt;The simplest new thing that we can do with this language construct is write computation code that mimics a &lt;tt&gt;switch&lt;/tt&gt; statement in C:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;f&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk&lt;/span&gt; &lt;span style="color:#cc4020"&gt;fun &lt;span style="color:#0000ff"&gt;x&lt;/span&gt;: &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; -&gt;&lt;br/&gt;     match x with&lt;br/&gt;       | &lt;span style="color:#009900"&gt;1&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;4&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#009900"&gt;2&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;3&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#009900"&gt;3&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;2&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#009900"&gt;4&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;1&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#009900"&gt;5&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;0&lt;/span&gt;&lt;br/&gt;       | &lt;span style="color:#0000ff"&gt;y&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;(x + y)&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;This function is included as an example in the "datatype" fork of Levy# on Github &lt;a href="https://github.com/robsimmons/levy/blob/datatype/switch.levy#L24-31"&gt;here&lt;/a&gt;; let's look at what it actually does in the interpreter:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;bash-3.2$ ./levy.byte switch.levy &lt;br/&gt;   ... snip ... &lt;br/&gt;   Levy. Press Ctrl-D to exit.&lt;br/&gt;   Levy&gt; &lt;span style="color:#cc4020"&gt;force &lt;span style="color:#0000ff"&gt;f&lt;/span&gt; &lt;span style="color:#0000ff"&gt;1&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   comp &lt;span style="color:#cc4020"&gt;F &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;&lt;/span&gt; = &lt;span style="color:#cc4020"&gt;return &lt;span style="color:#0000ff"&gt;4&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;   Levy&gt; &lt;span style="color:#cc4020"&gt;force &lt;span style="color:#0000ff"&gt;f&lt;/span&gt; &lt;span style="color:#0000ff"&gt;3&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   comp &lt;span style="color:#cc4020"&gt;F &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;&lt;/span&gt; = &lt;span style="color:#cc4020"&gt;return &lt;span style="color:#0000ff"&gt;2&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;   Levy&gt; &lt;span style="color:#cc4020"&gt;force &lt;span style="color:#0000ff"&gt;f&lt;/span&gt; &lt;span style="color:#0000ff"&gt;5&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   comp &lt;span style="color:#cc4020"&gt;F &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;&lt;/span&gt; = &lt;span style="color:#cc4020"&gt;return &lt;span style="color:#0000ff"&gt;0&lt;/span&gt;&lt;/span&gt;&lt;br/&gt;   Levy&gt; &lt;span style="color:#cc4020"&gt;force &lt;span style="color:#0000ff"&gt;f&lt;/span&gt; &lt;span style="color:#0000ff"&gt;7&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   comp &lt;span style="color:#cc4020"&gt;F &lt;span style="color:#0000ff"&gt;int&lt;/span&gt;&lt;/span&gt; = &lt;span style="color:#cc4020"&gt;return &lt;span style="color:#0000ff"&gt;14&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;That's what I expected to happen; hopefully it's what you expected to happen too. Let's declare victory and move on.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Using datatypes&lt;/h2&gt;The main innovation of Levy# is the introduction of an inductive datatype mechanism, which is basically a bedrock component of every functional programming language (that isn't a Lisp) ever. This should have been a relatively small change, but parser generators are &lt;i&gt;the worst&lt;/i&gt; and I'm bad at them so I basically had to rewrite the parser to have a new phase. Sigh. 
&lt;br /&gt;
&lt;br /&gt;I'll start with showing how datatypes are &lt;i&gt;used&lt;/i&gt;, because that's a little more standard than the way I declare them. It &lt;i&gt;would&lt;/i&gt; look exactly like the uses of ML datatypes, except that I curry them in a Haskell-ey fashion. The function &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;sumlist&lt;/span&gt;&lt;/tt&gt;, which sums up a list of integers, looks like this:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;val &lt;span style="color:#0000ff"&gt;sumlist&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;thunk&lt;/span&gt; &lt;span style="color:#cc4020"&gt;rec &lt;span style="color:#0000ff"&gt;sumlist&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;list&lt;/span&gt; -&gt; F &lt;span style="color:#0000ff"&gt;int&lt;/span&gt; is &lt;br/&gt;     fun &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;list&lt;/span&gt; -&gt;&lt;br/&gt;       match &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; with&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Nil&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;0&lt;/span&gt;&lt;br/&gt;         | &lt;span style="color:#009900"&gt;Cons &lt;span style="color:#0000ff"&gt;x&lt;/span&gt; &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;&lt;/span&gt; -&gt; force &lt;span style="color:#0000ff"&gt;sumlist&lt;/span&gt; &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt; to &lt;span style="color:#0000ff"&gt;y&lt;/span&gt; in return &lt;span style="color:#0000ff"&gt;x + y&lt;/span&gt;&lt;/span&gt; ;;&lt;/span&gt;&lt;/pre&gt;The other thing that's new in the above example is the use of Levy's fixedpoint operator, but there's nothing interesting there from the perspective of reading the code. This and other examples are in &lt;a href="https://github.com/robsimmons/levy/blob/datatype/datatype.levy#L36-40"&gt;datatype.levy&lt;/a&gt;, by the way.
&lt;br /&gt;
&lt;br /&gt;Side note: I'm lazy but still wanted a realistic execution model *and* coverage checking (redundant/non-exhaustive matches raise warnings), so I limited the current version of Levy# to depth-1 pattern matching:&lt;pre&gt;   &lt;span style="color:#000000; font-weight:bold"&gt;Levy&gt; &lt;span style="color:#cc4020"&gt;match &lt;span style="color:#0000ff"&gt;v4&lt;/span&gt; with | &lt;span style="color:#009900"&gt;Cons &lt;span style="color:#0000ff"&gt;x1&lt;/span&gt; (Cons &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt; &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;)&lt;/span&gt; -&gt; return &lt;span style="color:#0000ff"&gt;0&lt;/span&gt;&lt;/span&gt; ;;&lt;br/&gt;   Type error: &lt;span style="color:#009900"&gt;Cons &lt;span style="color:#0000ff"&gt;x2&lt;/span&gt; &lt;span style="color:#0000ff"&gt;xs&lt;/span&gt;&lt;/span&gt; not allowed in pattern (depth-1 pattern matching only)&lt;/span&gt;&lt;/pre&gt;If I was doing this for real I'd implement real coverage checking and pattern compilation as a code transformation, which would leave the depth-1 pattern matching interpreter unchanged.
&lt;br /&gt;
&lt;br /&gt;So that's the use of datatypes; one upshot is that my pieces of value code are maybe a bit more interesting than they used to be: I can make big piece value code like &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons 4 (Cons 9 (Cons 16 (Cons (-1) Nil)))&lt;/span&gt;&lt;/tt&gt; to create a big piece of data. I think that's kind of interesting, at least.
&lt;br /&gt;
&lt;br /&gt;&lt;h2&gt;Declaring datatypes&lt;/h2&gt;Datatypes are just a way of telling the computer that you want to work with a particular set of inductively defined structures (at least this is what &lt;i&gt;strictly positive datatypes&lt;/i&gt;, the only ones Levy# allows, are doing). A point that I've haltingly tried to make in a &lt;a href="http://requestforlogic.blogspot.com/2011/04/tell-me-story-of-logic.html"&gt;previous post&lt;/a&gt; was that, well, if you're going to write down a particular set of inductively defined terms, a canonical-forms based logical framework like Linear LF is a perfectly good language to write that in. 
&lt;br /&gt;
&lt;br /&gt;So our constants look basically like the declaration of constants in a Linear LF signature, except that we make the constants uppercase, following ML conventions:&lt;pre&gt;   &lt;span style="color:#009900; font-weight:bold"&gt;data Nil: &lt;span style="color:#0000ff"&gt;list&lt;/span&gt;&lt;br/&gt;      | Cons: &lt;span style="color:#0000ff"&gt;int -o list -o list&lt;/span&gt;&lt;/pre&gt;It's a little point, but it's kind of a big deal: we can understand all the values in Levy# as &lt;i&gt;canonical forms in a simply-typed linear lambda calculus with integers and some arithmetic operations&lt;/i&gt; - kind of like Twelf with the integer &lt;a href="http://twelf.plparty.org/wiki/Constraint_domain"&gt;constraint domain&lt;/a&gt; extension.&lt;sup&gt;&lt;a href="#foot2x0"&gt;2&lt;/a&gt;&lt;/sup&gt; 
&lt;br /&gt;
&lt;br /&gt;The reason it's a big deal is that we can now observe that the two kinds of "function types" we have in this language are way different. There's a &lt;i&gt;computational arrow&lt;/i&gt; &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ty1&lt;/span&gt; -&gt; ty2&lt;/span&gt;&lt;/tt&gt; that we inhereted from Levy, and then there's a Linear LF linear implication arrow, a &lt;i&gt;value arrow&lt;/i&gt; &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ty1 -o ty2&lt;/span&gt;&lt;/tt&gt; that we use in value code to construct patterns and values. I didn't invent this idea, it's actually a subset of what Licata and Harper propose in "A Universe of Binding and Computation" (ICFP 2009). Dan Licata would call the Linear LF arrow a "representational arrow," which is probably a better name than "value arrow."
&lt;br /&gt;
&lt;br /&gt;Of course, the values that we actually use are, without exception, at atomic type; if we try to even write down &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Cons 4&lt;/span&gt;&lt;/tt&gt;, which seems like it would have type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;list -o list&lt;/span&gt;&lt;/tt&gt;, we get a type error from Levy#: &lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;constructor Cons expects 2 arg(s), given 1&lt;/span&gt;&lt;/tt&gt;. So by requiring that all the Linear LF terms (i.e. value code) be canonical (beta-normal and eta-long), I've effectively excluded any values of type &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;ty1 -o ty2&lt;/span&gt;&lt;/tt&gt; from the syntax of the language.
&lt;br /&gt;
&lt;br /&gt;What would it mean to introduce value code whose type was a linear implication to Levy#? Well, that's the thing I really wanted to write about.
&lt;br /&gt;
&lt;br /&gt;&lt;hr&gt;&lt;small&gt;&lt;sup&gt;&lt;a name="foot1x0"&gt;&lt;/a&gt;1&lt;/sup&gt; Focusing and polarization-aware readers will notice that this has something to do with focusing. In particular: positive types are value types, negative types are computation types, &lt;tt&gt;&lt;span style="color:#cc4020; font-weight:bold"&gt;F&lt;/span&gt;&lt;/tt&gt; is "upshift," and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;U&lt;/span&gt;&lt;/tt&gt; is "downshift."
&lt;br /&gt;&lt;sup&gt;&lt;a name="foot2x0"&gt;&lt;/a&gt;2&lt;/sup&gt; Technical note: Boolean values, from the perspective of the value language, are just two defined constants, as explained &lt;a href="https://github.com/robsimmons/levy/blob/datatype/switch.levy#L58-65"&gt;here&lt;/a&gt;. That's important: we have Boolean constants that are values, but the elimination form for Booleans is &lt;i&gt;computation code&lt;/i&gt; not value code. If we had an "if" statement at the level of values, all sorts of crazy (and interesting) stuff could potentially happen. At least for the moment, I'm not considering that.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-1456587253223940309?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/HjiD5hihAcY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/1456587253223940309/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/1456587253223940309?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/1456587253223940309?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/HjiD5hihAcY/embracing-and-extending-levy-language.html" title="Embracing and extending the Levy language" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/embracing-and-extending-levy-language.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEIHRXc9eyp7ImA9WhdQEEs.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-5937173441676332744</id><published>2011-08-11T08:23:00.000-04:00</published><updated>2011-08-11T08:42:14.963-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-11T08:42:14.963-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="constructive provability logic" /><category scheme="http://www.blogger.com/atom/ns#" term="youtube" /><title>Video Lecture on Constructive Provability Logic</title><content type="html">I've previously blogged about &lt;a href="http://requestforlogic.blogspot.com/2010/12/principles-of-constructive-provability_08.html"&gt;the principles of constructive provability logic&lt;/a&gt; and about &lt;a href="http://requestforlogic.blogspot.com/2011/01/two-new-papers.html"&gt;our paper on the topic being accepted to IMLA&lt;/a&gt;. Since then (in fact, since my last blog post), I've given three versions of a talk on the logic: first at CMU before I left for my internship at Microsoft Research, the second at the workshop on Intuitionistic Modal Logic and Applications in Nancy, France,&lt;sup&gt;1&lt;/sup&gt; and the third the next day at LIX in Saclay (south of Paris) France.&lt;sup&gt;2&lt;/sup&gt; After tweaking that talk three times, I decided to tweak it once more and put it on the web on my &lt;a href="http://cpl.hyperkind.org/"&gt;page of resources about Constructive Provability Logic&lt;/a&gt;.
&lt;br /&gt;
&lt;br /&gt;&lt;iframe width="425" height="349" src="http://www.youtube.com/embed/feuVH8Saq0Q" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;br /&gt;
&lt;br /&gt;This was actually quite a bit harder than I'd expected! It didn't seem quite as difficult when I did it for the &lt;a href="http://www.cs.cmu.edu/~rjsimmon/papers/simmons08linlogalg.html"&gt;Linear Logical Algorithms&lt;/a&gt; presentation a few years ago, but I guess I was forcing myself to be less perfectionist there (requiring one take instead of 4 definitely forces you to be less perfectionist). Especially in the first two videos, the number of repeated takes comes across in my rather affected tone of voice - which is what you get when you over-rehearse something, at least if "you" is a person who (like me) has forgotten anything he ever learned about the "&lt;a href="http://books.google.com/books/about/The_illusion_of_the_first_time_in_acting.html?id=GS0LAAAAIAAJ"&gt;illusion of the first time&lt;/a&gt;".
&lt;br /&gt;
&lt;br /&gt;The effort required was such that I don't realistically see myself doing this too often again, but hopefully this will be at least moderately helpful to someone.
&lt;br /&gt;
&lt;br /&gt;&lt;hr&gt;&lt;small&gt;&lt;sup&gt;1&lt;/sup&gt; While in Nancy, I took a picture out of the window of the dorm where I was staying, and thereby &lt;a href="http://andrewsullivan.thedailybeast.com/2011/08/the-view-from-your-window-contest-winner-61.html"&gt;whittled away a few more of my 15 minutes of fame&lt;/a&gt;.
&lt;br /&gt;&lt;sup&gt;2&lt;/sup&gt; Nothing famous happened there, but I did have excellent fondue.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-5937173441676332744?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/aOKPhhBs6HI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/5937173441676332744/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/08/video-lecture-on-constructive.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/5937173441676332744?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/5937173441676332744?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/aOKPhhBs6HI/video-lecture-on-constructive.html" title="Video Lecture on Constructive Provability Logic" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://img.youtube.com/vi/feuVH8Saq0Q/default.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://requestforlogic.blogspot.com/2011/08/video-lecture-on-constructive.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0cNSXwycSp7ImA9WhZVFk4.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-8262612216459341772</id><published>2011-05-28T09:55:00.000-04:00</published><updated>2011-05-28T23:18:18.299-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-28T23:18:18.299-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="storytelling" /><category scheme="http://www.blogger.com/atom/ns#" term="navel-gazing" /><category scheme="http://www.blogger.com/atom/ns#" term="focusing" /><category scheme="http://www.blogger.com/atom/ns#" term="synthetic rules" /><category scheme="http://www.blogger.com/atom/ns#" term="links" /><title>Party like it's 1995</title><content type="html">It is humbling but enlightening when you're struggling to figure out how to describe something and you realize someone already nailed the exposition two decades ago. That's how I felt when I stumbled across this invited paper by Dale Miller, "&lt;a href="ftp://ftp.cis.upenn.edu/pub/papers/miller/GulpProde95.html"&gt;Observations about using logic as a specification language&lt;/a&gt;." Still a good paper!&lt;br /&gt;&lt;br /&gt;I wonder if the late eighties and early nineties felt as exciting at the time as they look in retrospect for the logic community. I guess the answer is "yes" - I recall &lt;a href="http://existentialtype.wordpress.com/"&gt;Bob Harper&lt;/a&gt; talking about one informal European workshop in that period where he was presenting LF, Girard was presenting linear logic, and maybe one of the uniform proofs people were presenting uniform proofs too? Maybe someone who's spending the summer in Pittsburgh can prod Bob into blogging about that meeting, it's a good story. (This reminds me, I need to add Bob's blog to the sidebar!).&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Also: completeness of focusing via cut and identity&lt;/h3&gt;&lt;br /&gt;Speaking of uniform proofs: I've been fiddling for some time with this view of that the completeness of a focused sequent calculus can be proven more-or-less directly from the standard metatheory of the focused sequent calculus: cut admissibility and identity expansion. (The completeness of focusing, if you recall, is good for many reasons. It gives us logic programming, and it allows us to think in terms of &lt;a href="http://requestforlogic.blogspot.com/2010/09/focusing-and-synthetic-rules.html"&gt;synthetic inference rules&lt;/a&gt; in our logical frameworks.) Frank first observed this way back when, I cleaned up and Twelfed up his proof a long time ago and wrote up a version of the argument for ordered linear logic in a tech report recently. the main weakness of our strategy is that, in its current version, it doesn't deal with inversion on positive types, which is why I call it "weak focusing" instead of "focusing." &lt;br /&gt;&lt;br /&gt;A recent MathOverflow question asked (in a slightly convoluted way) about the completeness of focusing with respect to a Prolog-like language. Since Prolog-like languages don't run into the problem with positive types, "our" strategy* works fine, so I used this as an excuse to finally &lt;a href="http://mathoverflow.net/questions/65776/how-establish-conversion-of-cut-free-proof-into-uniform-proof/65854#65854"&gt;write out the full argument&lt;/a&gt; in a setting that didn't have a lot of other extraneous stuff going on.&lt;br /&gt;&lt;br /&gt;* I'd like to know if someone came up with this strategy before us!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-8262612216459341772?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/r3O_z-5SZqY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/8262612216459341772/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/05/party-like-its-1995.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8262612216459341772?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/8262612216459341772?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/r3O_z-5SZqY/party-like-its-1995.html" title="Party like it's 1995" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/05/party-like-its-1995.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkUDRHo5eyp7ImA9WhZXGE8.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-4737922081963077349</id><published>2011-05-07T16:14:00.000-04:00</published><updated>2011-05-08T00:17:55.423-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-08T00:17:55.423-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="shell scripting" /><category scheme="http://www.blogger.com/atom/ns#" term="hacks" /><category scheme="http://www.blogger.com/atom/ns#" term="standard ml" /><category scheme="http://www.blogger.com/atom/ns#" term="off-topic" /><title>Hacky post: binary, where do you live?</title><content type="html">This is a problem that's come up various times in the past year, and I wanted to write it up quickly. Much more about hacking (Standard ML in particular, though I don't think it's a problem unique to Standard ML), I thought about putting it on my more personal blog, but it seemed out of place there too. &lt;br /&gt;&lt;br /&gt;Problem description: oftentimes when you have a binary file, you want to distribute it along with some other resource files (think images and whatnot). You expect that some collection of files containing these images will be distributed together, but you want to be able to move them around on your own system or to a friend's system as one atomic block without breaking everything. This means, effectively, that you have to be able to have the program start with any current directory and understand how to change directories to the directory where "it lives". The easiest way of doing this in Standard ML is to change directories &lt;tt&gt;(OS.FileSys.chdir)&lt;/tt&gt; to whichever directory the commandline argument that ran the program appeared to live in &lt;tt&gt;(OS.Path.dir (CommandLine.name ()))&lt;/tt&gt;.&lt;br /&gt; &lt;br /&gt;&lt;h2&gt;So far so good&lt;/h2&gt;We can illustrate how this works and fails to work with a one-line test program that we compile in MLton.&lt;pre&gt;structure Foo = struct val () = print ("I'm " ^ CommandLine.name () ^ "\n") end&lt;/pre&gt;Let's save this in /tmp, compile it, and run it:&lt;pre&gt;$ cd /tmp&lt;br /&gt;$ mlton foo.sml&lt;/pre&gt;Okay, now wherever we go, the directory part of &lt;tt&gt;(CommandLine.name ())&lt;/tt&gt; is going to be proper for getting from the current directory of the user into the directory where the binary lives:&lt;pre&gt;$ ./foo&lt;br /&gt;I'm ./foo&lt;br /&gt;$ cd ..&lt;br /&gt;$ /tmp/foo&lt;br /&gt;I'm /tmp/foo&lt;br /&gt;$ cd /tmp/baz&lt;br /&gt;$ ../foo&lt;br /&gt;I'm /tmp/baz&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Symlinks and paths and lying, lying command lines&lt;/h2&gt;The problem's gonna come when we want to execute our file from the path or from a symlink: then, the apparent working directory given by &lt;tt&gt;(CommandLine.name ())&lt;/tt&gt; will *not* necessarily be the place where the executable itself lives.&lt;pre&gt;$ pwd&lt;br /&gt;/tmp/baz&lt;br /&gt;$ export PATH=$PATH:/tmp&lt;br /&gt;$ foo&lt;br /&gt;I'm foo&lt;br /&gt;$ cd /tmp&lt;br /&gt;$ mkdir baz&lt;br /&gt;$ cd baz&lt;br /&gt;$ ln -s ../foo foo2&lt;br /&gt;$ ./foo2&lt;br /&gt;I'm ./foo2&lt;/pre&gt;The solution adopted by the group of us that wrote the C0 compiler is to notice that if you call something from a shell script it gets its path expanded. Therefore, if we have a shell script doing nothing but calling our program, the program will get called with its absolute path and therefore the program's attempts to chdir into the directory where its binary (and associated resources) live will succeed.&lt;pre&gt;$ pwd&lt;br /&gt;/tmp/baz&lt;br /&gt;$ mv ../foo ../foo.exe&lt;br /&gt;$ echo '$0.exe $*' &gt; ../foo&lt;br /&gt;$ chmod a+x ../foo&lt;br /&gt;$ foo&lt;br /&gt;I'm /tmp/foo.exe&lt;br /&gt;&lt;/pre&gt;However, this solution only works for things on the $PATH, not for symlinks:&lt;pre&gt;$ ./foo2&lt;br /&gt;./foo2:1: ./foo2.exe: No such file or directory&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Wrapping up&lt;/h2&gt;Can anyone think of a better way to do this? The shell script is simple, but it seems unnecessary. Perhaps I really should be asking this on StackOverflow, but the Standard ML conversations on StackOverflow are depressing to say the least.&lt;br /&gt;&lt;br /&gt;P.S. - If you're distributing your program by way of a SML/NJ heap image, &lt;tt&gt;(CommandLine.name ())&lt;/tt&gt; will always be &lt;tt&gt;sml&lt;/tt&gt;. To defeat this, when you issue the command that reloads the heap image, add the argument &lt;tt&gt;@SMLcmdname=$0&lt;/tt&gt;. That is, of course assuming you're reloading the heap image from within a shell script, which is the common way to make an executable using SML/NJ. So, in effect, with SML/NJ this problem is "automatically solved" because you're already redirecting through a shell script.&lt;br /&gt;&lt;br /&gt;P.P.S. - After I wrote this post, I realized it was probably a language-independent concern. Sure enough, there's StackOverflow posts about this problem from the perspective of &lt;a href="http://stackoverflow.com/questions/758018/path-to-binary-in-c"&gt;C&lt;/a&gt; and &lt;a href="http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe"&gt;C++&lt;/a&gt;. Seems like it's just a hard problem; crud.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-4737922081963077349?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/A6FsF_NlrJo" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/4737922081963077349/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/05/hacky-post-binary-where-do-you-live.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4737922081963077349?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4737922081963077349?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/A6FsF_NlrJo/hacky-post-binary-where-do-you-live.html" title="Hacky post: binary, where do you live?" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/05/hacky-post-binary-where-do-you-live.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUAHQ3w5eCp7ImA9WhdQEU0.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-7147083184838054833</id><published>2011-04-18T00:15:00.000-04:00</published><updated>2011-08-11T19:02:12.220-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-11T19:02:12.220-04:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="logical frameworks" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="judgmental reconstruction" /><title>Tell me a story of logic</title><content type="html">I have a little technical note that I'm working on, in which I tell a story about linear logic that I tried to work out a year ago and finally returned to with Bernardo Toninho and Yuxin Deng last week. But as I tried to write the introduction, the two-year-old voice in my head kept asking "why?" Why do I need to tell this story? What's the point? The resulting thoughts don't really belong in the technical note I wanted to write, but I hope they're just barely coherent enough that they're worth putting here. (Note: there is a similar discussion to this one in Section 3 of my thesis proposal.)
&lt;br /&gt;
&lt;br /&gt;Big picture: before we can contemplate any discussion of the formal correctness of any system (a logic, type theory, programming language, cryptographic protocol, or self-driving car) - before we can even ask ourself what "correctness'' means - we have to have a way of formally specifying the system itself. Mathematicians do this by defining sets, category theorists by enumerating universal mapping properties. However, if you're writing down theorems to be checked by a computer, there's almost exactly one game in town: systems for mechanized mathematics have a built-in facility for directly giving (co)inductive specifications of systems. 
&lt;br /&gt;
&lt;br /&gt;A tool's interface for describing inductive specifications is, therefore, a matter of some importance. In most systems, the statement of an inductive specification looks something like a datatype declaration in a programming language in ML or Haskell. One system for mechanized mathematics, Twelf, takes a rather different approach. Rather than &lt;i&gt;directly&lt;/i&gt; specifying an inductive structure, Twelf users specify a signature of type families and constants in the dependent type theory LF. If you asked someone about this while they were in a hurry to catch a plane, they'd probably respond "oh, that's what adequacy theorems are for" and run away.
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;A word on adequacy&lt;/h3&gt;In the &lt;a href="http://dx.doi.org/10.1145/138027.138060"&gt;first paper on LF&lt;/a&gt;, Harper, Honsell, and Plotkin discuss &lt;i&gt;adequacy theorems&lt;/i&gt;. When we write down a bunch of type families and constants in an LF signature, that means that we can form a certain (inductively-defined!) set of terms. To use a standard example, given the LF signature&lt;pre style="color:#060"&gt;  nat: type.
&lt;br /&gt;  z: nat.
&lt;br /&gt;  s: nat -&gt; nat.&lt;/pre&gt;we can create well-typed terms of type &lt;tt style="color:#060"&gt;nat&lt;/tt&gt; that look like &lt;tt style="color:#060"&gt;z&lt;/tt&gt;, &lt;tt style="color:#060"&gt;(s z)&lt;/tt&gt;, &lt;tt style="color:#060"&gt;(s (s z))&lt;/tt&gt;, and &lt;tt style="color:#060"&gt;((λx. s x) (s z))&lt;/tt&gt;. That fourth example has a β-redex that, when we reduce it, turns it into the third example. We usually say that the above LF specification is adequate because there is a one-one-correspondence between natural numbers and normal terms of type &lt;tt style="color:#060"&gt;nat&lt;/tt&gt; in this signature.&lt;sup&gt;1&lt;/sup&gt; In general, to quote Harper and Licata's 2007 "&lt;a href="http://dx.doi.org/10.1017/S0956796807006430"&gt;Mechanizing metatheory in a logical framework&lt;/a&gt;",&lt;blockquote&gt;&lt;i&gt;An LF representation of a language is adequate iﬀ it is isomorphic to the informal deﬁnition of the language.&lt;/i&gt;&lt;/blockquote&gt;I'm currently thinking that this might be the wrong slogan, because the imprecision of "informal" leads to seemingly inevitable misunderstandings. Another slogan that I might consider in its place is that an LF specification is adequate iff it is isomorphic to the &lt;i&gt;inductive specification&lt;/i&gt; of the language. It's just really very deeply ingrained in our collective heads that when we're writing down horizontal lines on paper, that &lt;i&gt;means&lt;/i&gt; an inductive specification. But perhaps that's not giving LF enough credit! There's no reason to cede that my scratches on a whiteboard have any special spiritual relationship with inductive definitions and not LF signatures (or sets in ZFC or constructions in category theory, for that matter).
&lt;br /&gt;
&lt;br /&gt;Taking the view that adequacy relates the canonical forms of LF to some inductively defined structure ("on paper" or otherwise) has two advantages that I see. First, it turns adequacy into something that takes place entirely &lt;i&gt;within&lt;/i&gt; formal mathematics. In fact, we have a pretty clear understanding of how to write "first-order" or "concrete" LF types that encode inductive definitions (hint: never allow left-nested arrows). But this means that we can prove adequacy theorems &lt;i&gt;in&lt;/i&gt; Twelf. My &lt;a href=""&gt;Twelf code&lt;/a&gt; proving a bijection between de Bruijn lambda calculus terms and HOAS lambda calculus terms is, in this view, part of an adequacy theorem.&lt;sup&gt;2&lt;/sup&gt; The second advantage, in my mind, is it clarifies why we never formally prove adequacy with respect to our "informal definitions" (a point that Daniel Lee and I poked a bit of fun in our SIGBOVIK 2007 paper &lt;a href="http://sigbovik.org/2007/papers/manifestadequacy.pdf"&gt;Manifest Adequacy&lt;/a&gt;). When I've been using Adga for awhile, I think of my on-paper notation as corresponding to inductive definitions (or, occasionally, inductive-recursive definitions, the more powerful variant of inductive definitions available in Agda). When I've been using Twelf for awhile, I think of my on-paper notation as corresponding to LF signatures that use &lt;a href="http://en.wikipedia.org/wiki/Higher-order_abstract_syntax"&gt;higher-order abstract synatx&lt;/a&gt;. It's only in the event that I want to know that these two ways of formalizing the same system coincide that I would actually think about adequacy in practice. To reempahsize, in this event adequacy is an entirely formal concept.
&lt;br /&gt;
&lt;br /&gt;&lt;h3&gt;Why logical frameworks?&lt;/h3&gt;There's no contrarian impulse that lead to LF being used to encode systems. Harper, Honsell, and Plotkin made the point as well as I could hope to:&lt;blockquote&gt;&lt;i&gt;The structure of the LF type system provides for the uniform extension of the basic judgment forms to two higher-order forms introduced by Martin-Löf, the &lt;b&gt;hypothetical&lt;/b&gt;, representing consequence, and the &lt;b&gt;schematic&lt;/b&gt;, representing generality.&lt;/i&gt;&lt;/blockquote&gt;There are two important points to make about the above quote. The more obvious one is that LF, compared to "raw" inductive definitions, gives a clean notion of hypothetical reasoning and uniform substitution (the basis of what was later termed "higher-order abstract syntax"). The less obvious point is that, in the above quote, Harper, Honsell, and Plotkin are referencing Martin-Löf's  "&lt;a href="http://www.cs.cmu.edu/afs/cs/Web/People/crary/819-f09/Martin-Lof83.pdf"&gt;On the meaning of logical constants and the justification of the logical laws&lt;/a&gt;," which isn't actually about LF. Rather, it's a story about how we understand the meaning of propositions and how we establish that a logic's definition makes sense in the presence of a uniform notion of hypothetical judgments. 
&lt;br /&gt;
&lt;br /&gt;Martin-Löf's discussion, which Pfenning and Davies termed the "judgmental methodology" in their their &lt;a href="http://dx.doi.org/10.1017/S0960129501003322"&gt;judgmental reconstruction of modal logic&lt;/a&gt;, is important for people who write systems in Twelf because it sets up a particular world-view that maps quite well onto formalization in LF. To put it another way, the judgmental methodology is one important source of intuitions that guide the mental process of mapping between our "on-paper" notation and LF signatures. And so it's no accident that 1) we use Twelf a lot at Carnegie Mellon 2) our student reading group usually reads &lt;i&gt;On the meaning of logical constants and the justification of the logical laws&lt;/i&gt; at least once every other year. The judgmental properties underlying LF and Martin Löf's reconstruction are the same, so understanding the judgmental methodology is a good way of understanding LF formalization. 
&lt;br /&gt;
&lt;br /&gt;This continues to be the case in the Linear LF extension to LF, where linear hypothetical assumptions are understood to be &lt;i&gt;resources&lt;/i&gt; that will be consumed in the service of building a goal. The underlying story here, which Wikipedia originally attributes to Lafont, is called the &lt;i&gt;resource interpretation&lt;/i&gt;, and it allows us to understand how to do things like represent programming languages with state conveniently, because "a bunch of memory" is a concept that can be represented as "a bunch of resources." The story that we tell about linear logic - the resource interpretation - is important in part because it gives us intuitions for understanding LLF formalizations.
&lt;br /&gt;
&lt;br /&gt;I don't know that I can speak for where my intuitions about inductive definitions come from - as I've said before, computer scientists tend to treat them as pretty foundational. On the other hand, it's difficult to &lt;i&gt;really&lt;/i&gt; use the "raw" inductive definitions provided natively by most non-Twelf provers to reason about programming languages, which is why there has been much recent (and, from an outside perspective, seemingly quite successful) work aimed at providing the right tool support for specifying and reasoning about programming languages in highly-developed proof assistants like Coq. The only danger here is, as soon as you start adding layers of interface between yourself and inductive definitions, the question of adequacy (the informal version, at least) again raises its head: there's not necessarily the same Martin-Löfian story guiding you, so where are your intuitions about the correctness of your system coming from? How would you actually prove that it corresponds to an ostensibly equivalent LF signature?
&lt;br /&gt;
&lt;br /&gt;This, in turn, is one reason why &lt;i&gt;two-level approach&lt;/i&gt; have been recently popularized by Felty's &lt;a href="http://hybrid.dsi.unimi.it/"&gt;Hybrid&lt;/a&gt; system and Gacek's &lt;a href="http://abella.cs.umn.edu/"&gt;Abella&lt;/a&gt;. In these systems, there's a specially supported logical layer where one can use the same kind of intuitions we use in LF encodings. LF or LLF could, in fact be used for this logical layer, though these two systems use different variations on that theme. The second layer is a separate facility for reasoning about these encodings. 
&lt;br /&gt;
&lt;br /&gt;I'll stop here, though one argument I might be interested in trying to make in the future is that Twelf itself is actually the &lt;i&gt;original&lt;/i&gt; two-level approach. There's an even stronger argument to be made in the case of HLF, Jason Reed's implementation of meta-reasoning for LLF on top of Twelf. However 
&lt;br /&gt;
&lt;br /&gt;&lt;sup&gt;1&lt;/sup&gt; We usually say &lt;i&gt;canonical terms&lt;/i&gt; or &lt;i&gt;canonical forms&lt;/i&gt;, not &lt;i&gt;normal terms&lt;/i&gt;. The canonical forms are the β-normal η-long terms. However, η-expansion doesn't mean anything for this example.
&lt;br /&gt;
&lt;br /&gt;&lt;sup&gt;2&lt;/sup&gt; It would be a full adequacy theorem if I'd shown that the bijection was compositional - that substitution on the de Bruijn terms means the same thing as substitution that LF gives us for free - but I didn't prove that part. Perhaps I should.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-7147083184838054833?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/DvcAGxIc45s" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/7147083184838054833/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/04/tell-me-story-of-logic.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/7147083184838054833?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/7147083184838054833?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/DvcAGxIc45s/tell-me-story-of-logic.html" title="Tell me a story of logic" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/04/tell-me-story-of-logic.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cCRnk6fip7ImA9Wx9aF0o.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-4929330613425767789</id><published>2011-03-08T15:09:00.000-05:00</published><updated>2011-03-10T11:37:47.716-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-10T11:37:47.716-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="request for typestate" /><category scheme="http://www.blogger.com/atom/ns#" term="linearml" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><category scheme="http://www.blogger.com/atom/ns#" term="f-pop" /><category scheme="http://www.blogger.com/atom/ns#" term="alms" /><title>Request for Typestate, Part 2: Linear Types, Now!</title><content type="html">&lt;i&gt;Part 2 in a &lt;a href="http://requestforlogic.blogspot.com/search/label/request%20for%20typestate"&gt;series&lt;/a&gt;. &lt;a href="http://requestforlogic.blogspot.com/2011/01/request-for-typestate-part-1.html"&gt;Part 1&lt;/a&gt; began with a discussion hypothetical discussion of a ML-like language with linear types.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;So in my previous post, I used the REPL loop of an "Imaginary Future Linear ML." In the following month, I've learned that there are no less than three different proposals of Imaginary Future Linear ML. Two of them, &lt;a href="http://www.ccs.neu.edu/home/tov/pubs/alms/"&gt;Alms&lt;/a&gt; and &lt;a href="https://github.com/pikatchu/LinearML"&gt;LinearML&lt;/a&gt;, are implemented systems that you can presumably download and run onto the device that you're using to read this very blog post!&lt;sup&gt;1&lt;/sup&gt; The third, &lt;a href="http://portal.acm.org/citation.cfm?id=1708016.1708027 "&gt;F-Pop&lt;/a&gt; by Mazurak et al, is, I believe, less seriously implemented but is formalized in Coq (which is also awesome: three cheers for mechanized metatheory!). &lt;br /&gt;&lt;br /&gt;I was actually pleased with how much I "guessed correctly" in my discussion. For instance, Alms is a serious implementation of a language with affine, not linear, types: if you recall, affine functions can't use their arguments twice, but they can avoid using them at all. One argument from the Alms designers, which I had not considered, is that requiring a linear type discipline - where all variables get used &lt;i&gt;exactly&lt;/i&gt; once along every "control path" - can make it rather difficult to work with handled exceptions. &lt;br /&gt;&lt;br /&gt;Another thing that I "guessed" was in Take 3, when I suggested that we might want some syntactic sugar to make code look more like "methods" - the &lt;tt&gt;print&lt;/tt&gt; method takes a string and a linear reference to a string and returns a new linear reference to that string, so why don't we have syntax that supports writing (&lt;tt&gt;print "Hello World" outstream&lt;/tt&gt;) instead of (&lt;tt&gt;let outstream = print "Hello World" outstream&lt;/tt&gt;). The F-Pop paper explicitly discusses this kind of notation in Section 5.2. I like that this is something they considered, though I'm still a little unsure how I feel about it "in practice." What it's doing is capturing a common intuition, that &lt;i&gt;an argument, passed by reference, is both an input and an output.&lt;/i&gt; But how much of this intuition is fundamental, and how much is it based on path dependence - we happened to start out with languages like C and Java that force functions to have only one "official" output, so are we just used to being forced into using this unnatural design pattern?&lt;br /&gt;&lt;br /&gt;&lt;sup&gt;1&lt;/sup&gt; Caveat 1: well, as long as you're not using iOS. (I just got an iPad. I am not proud of this but yes, it is shiny.) Caveat 2: I couldn't get either Alms or LinearML to run on my laptop.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-4929330613425767789?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/e-gME3TWRYQ" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/4929330613425767789/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/03/request-for-typestate-part-2-linear.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4929330613425767789?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4929330613425767789?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/e-gME3TWRYQ/request-for-typestate-part-2-linear.html" title="Request for Typestate, Part 2: Linear Types, Now!" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/03/request-for-typestate-part-2-linear.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEAHSHk-eCp7ImA9Wx9aF04.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-7643918321468169820</id><published>2011-02-08T15:16:00.000-05:00</published><updated>2011-03-10T00:58:59.750-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-10T00:58:59.750-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="typestate" /><category scheme="http://www.blogger.com/atom/ns#" term="request for typestate" /><category scheme="http://www.blogger.com/atom/ns#" term="linear logic" /><title>Request for Typestate, Part 1</title><content type="html">&lt;i&gt;Part 1 of a &lt;a href="http://requestforlogic.blogspot.com/search/label/request%20for%20typestate"&gt;series&lt;/a&gt;. If you're interested in Imaginary Future ML, a number of proposals exist: see &lt;a href="http://requestforlogic.blogspot.com/2011/03/request-for-typestate-part-2-linear.html"&gt;Part 2&lt;/a&gt;.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Recently I have been trying to understand typestate, since a lot of my friends, hallmates, and fellow distance runners have written implementations, papers, Ph.D. theses, and SIGBOVIK presentations on the topic. A conversation with Ron Garcia helped me get the first idea of what is going on and how it relates to linear type systems, a topic I do feel like I understand.&lt;br /&gt;&lt;br /&gt;Some background, as I understand it. The word "typestate" was introduced by Strom and Yemini way back a long time ago in 1984 in a paper entitled "Typestate: A Programming Language Concept for Enhancing Software Reliability" (Jonathan Aldritch has posted the PDF &lt;a href="http://www.cs.cmu.edu/~aldrich/papers/classic/tse12-typestate.pdf"&gt;here&lt;/a&gt;). It was an attempt to capture the fact that function calls often have a "do this, then do that, then don't do that anymore" kind of flavor. The most obvious and simple example is one that most every programmer has encountered, thanks to C's ubiquity:&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;img src="http://typesafety.net/rfl/typestate-alloc.png" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;In other words, we create a pointer by mallocing it, and then we can use that pointer as long as we want to, but if we free it we can't use that pointer anymore. (Well, we can, but we're not supposed to, C sucks, whatever.) Okay, but now you're scratching your head thinking that this is basically why modern humans use garbage collection. Well, sure, but while this solves a particular problem, the problem is really a pattern of problems, and the pattern just re-asserts itself in different ways. For instance, take this interaction with SML/NJ's toplevel:&lt;pre style="color:#060"&gt;  $ sml&lt;br /&gt;  Standard ML of New Jersey v110.70 [built: Wed Jun 17 16:24:00 2009]&lt;br /&gt;  - val FILE = TextIO.openOut("foo.txt");&lt;br /&gt;  val FILE = - : TextIO.outstream&lt;br /&gt;  - TextIO.output(FILE, "Hello world\n");&lt;br /&gt;  val it = () : unit&lt;br /&gt;  - TextIO.closeOut(FILE);&lt;br /&gt;  val it = () : unit&lt;br /&gt;  - TextIO.output(FILE, "I've got a bad feeling about this\n");&lt;br /&gt;&lt;br /&gt;  uncaught exception Io [Io: output failed on "foo.txt", closed stream]&lt;br /&gt;    raised at: Basis/Implementation/IO/text-io-fn.sml:443.14-443.56&lt;/pre&gt;What's happened here is that we've run afoul of exactly the same pattern that we know from C.&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;img src="http://typesafety.net/rfl/typestate-file.png" /&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;Because we're in a safe language, the results are less dire; a dynamic exception gets thrown rather than memory being silently corrupted. However, the problem remains: it seems like this is the sort of thing we should be able to statically preclude (using a type system), or at &lt;i&gt;least&lt;/i&gt; warn programmers about ahead of time (using a static analysis).&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Typestate-oriented programming&lt;/h2&gt;Both of these approaches (type systems and static analyses) have been investigated thoroughly by my friends in Jonathan Aldrich's group, such as Kevin Bierhoff, Nels Beckman, Ciera Jaspan, Karl Naden, Roger Wolff, and Ron Garcia. The following example is a way of taking that doomed ML snippet above and making it a piece of typestate-checked code; it's mostly copied from &lt;a href="http://www.cs.cmu.edu/~aldrich/papers/onward2009-state.pdf"&gt;Typestate Oriented Programming&lt;/a&gt; by Jonathan Aldrich, Joshua Sunshine, Darpan Saini, and Zachary Sparks and was presented at ONWARD 2009.&lt;pre style="color:#006"&gt;  state File {&lt;br /&gt;    public final String filename;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  state OpenFile extends File {&lt;br /&gt;    private CFilePtr filePtr;&lt;br /&gt;    public void write(str : String) { ... }&lt;br /&gt;    public void close() [OpenFile&gt;&gt;ClosedFile]&lt;br /&gt;    { ... }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  state ClosedFile extends File {&lt;br /&gt;    public void open() [ClosedFile&gt;&gt;OpenFile]&lt;br /&gt;  }&lt;/pre&gt;The idea here is that a &lt;tt&gt;File&lt;/tt&gt; is a file that might be open or closed; you can only read from an &lt;tt&gt;OpenFile&lt;/tt&gt;, which is a subtype of &lt;tt&gt;File&lt;/tt&gt;. That annotation on the &lt;tt&gt;close()&lt;/tt&gt; and &lt;tt&gt;open()&lt;/tt&gt; methods is telling us that those functions actually &lt;i&gt;change the type&lt;/i&gt; of the object they're acting upon; the typesystem has to work accordingly to make sure you only close or read from an &lt;tt&gt;OpenFile&lt;/tt&gt;, even if though, after you close it, the object has "become" exactly the thing - a &lt;tt&gt;ClosedFile&lt;/tt&gt; - that you were making sure it wasn't before.&lt;br /&gt;&lt;br /&gt;I have some particular questions about the nature of the thing called "subtyping" in typestate oriented programming that I hope to get to in a separate post, but I hope this gives a decent overview of how typestate intuitively works even if it doesn't give much intuition as to how the typing rules "actually" work. As it turns out, the type theory behind typestate-oriented programming uses ideas from &lt;i&gt;linear logic&lt;/i&gt;, which can also be used to directly solve the motivating problem. What I really hope to explore in this series of posts is the way in which typestate - which is mostly being investigated in object oriented settings - can (or can't) be understood as a linear type discipline in a functional programming language.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Linear Types&lt;/h2&gt;From a programmer's perspective, linear logic is a functional programming language where all variables only get to be mentioned &lt;i&gt;once&lt;/i&gt;. There's an additional requirement, which is that every variable &lt;i&gt;must&lt;/i&gt; be used once, but sometimes people ignore this requirement: the system where variables are mentioned no more than once is technically an "affine" system and not a "linear" one, but it's common to call affine systems linear anyway, because the more general term is "substructural" and "substructural" is for some reason a word that people get scared by. (This turns out to be pretty problematic for me, but that's a different blog post.)&lt;br /&gt;&lt;br /&gt;So, nothing to be scared of, can't use variables twice. Let's see what happens with our interaction with SML:&lt;pre style="color:#600"&gt;  $ smlinear&lt;br /&gt;  Imaginary Future Linear ML [built: IN THE FUTURE]&lt;br /&gt;  - val FILE = TextIO.openOut("foo.txt");&lt;br /&gt;  val FILE = - : TextIO.outstream&lt;br /&gt;  - TextIO.output(FILE, "Hello world\n");&lt;br /&gt;  val it = () : unit&lt;br /&gt;  - TextIO.closeOut(FILE);&lt;br /&gt;  stdIn:1.17-1.21 Error: unbound variable or constructor: FILE&lt;br /&gt;  Variable "FILE" was previously in scope as a linear resource,&lt;br /&gt;    but that resource already consumed&lt;/pre&gt;Oh dear, that doesn't work at all - we can't close the file or even write to it twice! This is our fault; when we ported the SML Basis Library from SML/NJ to Imaginary Future Linear ML, we needed to make some changes to the way we deal with &lt;tt&gt;TextIO&lt;/tt&gt;. Here's (part of) the old signature for &lt;tt&gt;TextIO&lt;/tt&gt;, with the arrows &lt;/tt&gt;-&gt;&lt;/tt&gt; turned into lollipops &lt;tt&gt;-o&lt;/tt&gt; to emphasize that we're in linear logic now. (Again, nothing scary, it just means that variables can only be mentioned once.)&lt;pre style="color:#006"&gt;  signature OLD_TEXT_IO = sig&lt;br /&gt;    type outstream&lt;br /&gt;    val openOut : string -o outstream&lt;br /&gt;    val output : outstream * string -o unit&lt;br /&gt;    val close : outstream -o unit&lt;br /&gt;  end&lt;/pre&gt;This signature had just the right type when we could reuse the variable &lt;tt&gt;FILE&lt;/tt&gt; that we got from &lt;tt&gt;openOut&lt;/tt&gt;, but now, in Imaginary Future Linear ML, we can't.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Take 1: Restoring the old behavior&lt;/h3&gt;It's ridiculous, however, to make the output stream go away forever whenever we write to it! So what do we do? Well, all we need is for the functions that currently return &lt;tt&gt;unit&lt;/tt&gt; to give us &lt;i&gt;back&lt;/i&gt; a new object of type &lt;tt&gt;outstream&lt;/tt&gt;, and then we can use it again!&lt;pre style="color:#006"&gt;  signature NEW_TEXT_IO_1 = sig&lt;br /&gt;    type outstream&lt;br /&gt;    val openOut : string -o outstream&lt;br /&gt;    val output : outstream * string -o outstream&lt;br /&gt;    val close : outstream -o outstream&lt;br /&gt;  end&lt;/pre&gt;With this new signature for &lt;tt&gt;TextIO&lt;/tt&gt;, we could have exactly the same (failed) interaction with the toplevel that we had before, the difference is that, now, we always bind a new variable when we run a function so that we have an &lt;tt&gt;outstream&lt;/tt&gt; object to use in the future.&lt;pre style="color:#600"&gt;  $ smlinear&lt;br /&gt;  Imaginary Future Linear ML [built: IN THE FUTURE]&lt;br /&gt;  - val FILE1 = TextIO.openOut("foo.txt");&lt;br /&gt;  val FILE1 = - : TextIO.outstream&lt;br /&gt;  - val FILE2 = TextIO.output(FILE1, "Hello world\n");&lt;br /&gt;  val FILE2 = - : TextIO.outstream&lt;br /&gt;  - val FILE3 = TextIO.closeOut(FILE2);&lt;br /&gt;  val FILE3 = - : TextIO.outstream&lt;br /&gt;  - TextIO.output(FILE3, "I've got a bad feeling about this\n");&lt;br /&gt;&lt;br /&gt;  uncaught exception Io [Io: output failed on "foo.txt", closed stream]&lt;br /&gt;    raised at: Basis/Implementation/IO/text-io-fn.sml:443.14-443.56&lt;/pre&gt;Okay, well, why did I show an example that didn't solve the problem &lt;i&gt;at all&lt;/i&gt;? Because it's important to realize that we haven't really lost any expressiveness in the language: even though we have a more restrictive system that prevents us from using variables twice, we can still express most of the things we could before. &lt;br /&gt;&lt;br /&gt;(Side note: in the case of the strictly-linear variant of Gödel’s System &lt;i&gt;T&lt;/i&gt;, it's actually been proven that we lose &lt;a href="http://dx.doi.org/10.1016/j.tcs.2009.11.014"&gt;exactly nothing&lt;/a&gt; in terms of mathematical expressiveness by using the more restrictive type system, which is neat.)&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Take 2: Actually fixing the problem&lt;/h3&gt;So, intuitively, we know what to do here: once we've closed an &lt;tt&gt;outstream&lt;/tt&gt; we shouldn't be able to re-close it or output to it. The easiest solution is to make the function &lt;tt&gt;close&lt;/tt&gt; have the type &lt;tt&gt;outstream -o unit&lt;/tt&gt; - that way, closing an &lt;tt&gt;outstream&lt;/tt&gt; consumes the variable representing the output stream and leaves us with no way to even mention it.&lt;pre style="color:#006"&gt;  signature NEW_TEXT_IO_1 = sig&lt;br /&gt;    type outstream&lt;br /&gt;    val openOut : string -o outstream&lt;br /&gt;    val output : outstream * string -o outstream&lt;br /&gt;    val close : outstream -o unit&lt;br /&gt;  end&lt;/pre&gt;This suffices to turn our original dynamic exception into a static type error like the &lt;tt&gt;Variable...already consumed&lt;/tt&gt; error I made up earlier.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Take 3: Matching the typestate example&lt;/h3&gt;For the sake of completeness, let's think about how our example looks different from the typestate example. The big difference is that all the functions in the typestate example are &lt;tt&gt;void&lt;/tt&gt;: they don't output anything, they just change the type of their argument. But I believe that this is actually something that it would be reasonable to mimic in a linear system like "Imaginary Future Linear ML." The first step is to say: well, when I consumed &lt;tt&gt;FILE&lt;/tt&gt; there was no longer a &lt;tt&gt;FILE&lt;/tt&gt; hanging around, so why don't I just reuse that variable name?&lt;pre style="color:#600"&gt;  $ smlinear&lt;br /&gt;  Imaginary Future Linear ML [built: IN THE FUTURE]&lt;br /&gt;  - val FILE = TextIO.openOut("foo.txt");&lt;br /&gt;  val FILE = - : TextIO.outstream&lt;br /&gt;  - val FILE = TextIO.output(FILE, "Hello world\n");&lt;br /&gt;  val FILE = - : TextIO.outstream&lt;br /&gt;  - val FILE = TextIO.closeOut(FILE);&lt;br /&gt;  val FILE = - : TextIO.outstream&lt;br /&gt;  - TextIO.output(FILE, "I've got a bad feeling about this\n");&lt;br /&gt;  stdIn:1.17-1.21 Error: unbound variable or constructor: FILE&lt;br /&gt;  Variable "FILE" was previously in scope as a linear resource,&lt;br /&gt;    but that resource already consumed&lt;/pre&gt;The second step is to consider that the typestate-oriented examples really do have "outputs" - their outputs are the new states of the &lt;tt&gt;this&lt;/tt&gt; object. This would be easy syntactic sugar to whip up, just let &lt;tt&gt;val output : [outOpen &gt;&gt; outOpen] * string -o unit&lt;/tt&gt; mean &lt;tt&gt;val output : outOpen * string -o outOpen&lt;/tt&gt; and give the following signature&lt;pre style="color:#006"&gt;  signature NEW_TEXT_IO_2 = sig&lt;br /&gt;    openOut : string -o outOpen&lt;br /&gt;    output : [outOpen &gt;&gt; outOpen] * string -o unit&lt;br /&gt;    closeOut : [outOpen &gt;&gt; outClosed] -o unit&lt;br /&gt;    reopenOut : [outClosed &gt;&gt; outOpen] -o unit&lt;br /&gt;  end&lt;/pre&gt;With this use of syntactic sugar, we could support the following interaction with our pretend ML:&lt;pre style="color:#600"&gt;  $ smlinear&lt;br /&gt;  Imaginary Future Linear ML [built: IN THE FUTURE]&lt;br /&gt;  - val FILE = TextIO.openOut("foo.txt");&lt;br /&gt;  val FILE = - : TextIO.outOpen&lt;br /&gt;  - TextIO.output(FILE, "Hello world\n");&lt;br /&gt;  val it = () : unit&lt;br /&gt;  - TextIO.closeOut(FILE);&lt;br /&gt;  val it = () : unit&lt;br /&gt;  - TextIO.output(FILE, "I've got a bad feeling about this\n");&lt;br /&gt;  stdIn:6.1-6.59 Error: operator and operand don't agree [tycon mismatch]&lt;br /&gt;    operator domain: TextIO.openOut * string&lt;br /&gt;    operand:         TextIO.closeOut * string&lt;br /&gt;    in expression:&lt;br /&gt;      TextIO.output (FILE,"I've got a bad feeling about this\n")&lt;/pre&gt;I think that's pretty nice.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;I think the lesson of this first discussion is that, when relating linear functional programming languages to imperative programming languages, it's useful to think of object passed to functions as being "lost" to that function and then automatically "re-bound" with the same name when the function returns. Once we make this step, the notion that the re-bound variable can have a different type - which is one key insight of typestate-oriented programming - seems quite natural.&lt;br /&gt;&lt;br /&gt;It's important to note that none of the stuff I said about linearity and state is at all novel; for further reading see Wadler's paper &lt;a href="http://homepages.inf.ed.ac.uk/wadler/papers/linear/linear.ps"&gt;Linear Types Can Change The World!&lt;/a&gt; (warning: .ps) or David Walker's chapter "Substructural Type Systems" in Advanced Topics in Types and Programming Languages. Those two sources just about cover the background reading; if anyone has other suggestions please feel free to put them in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-7643918321468169820?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/Mq3U_4d0mYc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/7643918321468169820/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/01/request-for-typestate-part-1.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/7643918321468169820?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/7643918321468169820?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/Mq3U_4d0mYc/request-for-typestate-part-1.html" title="Request for Typestate, Part 1" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/01/request-for-typestate-part-1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQDQXo5eSp7ImA9Wx9VE0k.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-6847599022760192326</id><published>2011-01-29T17:17:00.000-05:00</published><updated>2011-01-29T18:06:10.421-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-01-29T18:06:10.421-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="logical frameworks" /><category scheme="http://www.blogger.com/atom/ns#" term="constructive provability logic" /><category scheme="http://www.blogger.com/atom/ns#" term="papers" /><category scheme="http://www.blogger.com/atom/ns#" term="approximation" /><title>Two new papers</title><content type="html">I have a post on typestate that has been languishing while I've been spending a lot of time on CMU's admissions committe, but now that that's over I hopefully will be able to get back to it. But first, two papers:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Logical Approximation for Program Analysis&lt;/h3&gt;My paper with Frank Pfenning, &lt;i&gt;Logical Approximation for Program Analysis&lt;/i&gt;, has been accepted to HOSC. This paper extends of the work from the PEPM 2009 paper &lt;i&gt;Linear logical approximations&lt;/i&gt; [&lt;a href="http://portal.acm.org/citation.cfm?id=1480949"&gt;ACM Link&lt;/a&gt;] - the acceptance is actually to a HOSC special issue on PEPM 2009. However, this paper also synthesizes a lot of stuff from our LICS 2009 paper &lt;i&gt;Substructural Operational Semantics as Ordered Logic Programming&lt;/i&gt;. The point of this journal paper is to provide a story about allowing substructural operational semantics specifications of programming language, written in the style of the LICS 2009 paper/my thesis proposal, to be approximated. The approximation process lets us derive program analyses like control flow and alias analysis in the style of the PEPM 2009 paper.&lt;br /&gt;&lt;br /&gt;Anyway: &lt;a href="http://www.cs.cmu.edu/~rjsimmon/papers/simmons11logical.pdf"&gt;PDF&lt;/a&gt;, which I'm still polishing for final submission this weekend. &lt;br /&gt;&lt;br /&gt;It occurs to me that I should write some more substructural operational semantics posts on this blog, seeing as that's my thesis topic and all.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Constructive Provability Logic&lt;/h3&gt;Since Bernardo and I got the &lt;a href="http://requestforlogic.blogspot.com/2010/12/principles-of-constructive-provability_08.html"&gt;principles of constructive provability logic&lt;/a&gt; nailed down, we've done a little more exploring. The most important thing about this paper, relative to the technical report, is that it presents a less restricted version of constructive provability logic (the "de-tethered variant" &lt;b&gt;CPL*&lt;/b&gt;); I think this less restricted version is going to be critical to understanding logic programming through the lens of constructive provability logic, which is my ultimate goal for the project. The second new thing about the paper is that we nailed down (with one perplexing exception) which of the "normal" axioms of intuitionistic modal logic do or don't hold.&lt;br /&gt;&lt;br /&gt;What does this mean? Well, any classical logician will tell you that, in order to be a modal logic, you have to obey one axiom - the "K" axiom, &lt;tt&gt;□(A → B) → □A → □B&lt;/tt&gt; - and one rule, which is that if you can prove &lt;tt&gt;A&lt;/tt&gt; with no assumptions then you can also prove &lt;tt&gt;□A&lt;/tt&gt; ("necessitation"). And any intuitionistic modal logic worth its salt is going to do the same, so far so good. However, intuitionstic modal logic also has a possibility modality &lt;tt&gt;◇A&lt;/tt&gt;. In classical logic saying something is possible is the same as saying that it's not necessarily false, so &lt;tt&gt;◇A&lt;/tt&gt; is defined as &lt;tt&gt;¬□¬A&lt;/tt&gt;. But in intuitionistic logic we tend to think of possibility as a genuinely different thing, and that's where stuff gets complicated. The two most important proof theories for intuitionistic modal logic are probably Alex Simpson's &lt;b&gt;IK&lt;/b&gt; - which describes a whole bunch of intuitionistic modal logics - and Pfenning-Davies &lt;b&gt;S4&lt;/b&gt;, which describes &lt;b&gt;S4&lt;/b&gt;. Some of the axioms that Simpson claims are fundamental to intuitionistic modal logics, like &lt;tt&gt;(◇A → □B) → □(A → B)&lt;/tt&gt;, don't hold in Pfenning-Davies &lt;b&gt;S4&lt;/b&gt;; it turns out that particular axiom doesn't hold in constructive provability logic, either. &lt;br /&gt;&lt;br /&gt;As we discuss in the paper, it seems like the de-tethered variant, &lt;b&gt;CPL*&lt;/b&gt;, lies between Pfenning-Davies &lt;b&gt;S4&lt;/b&gt; and Simpson-style &lt;b&gt;S4&lt;/b&gt; on the "which axioms hold" meter, whereas &lt;b&gt;CPL&lt;/b&gt; (the tethered version of constructive provability logic from the tech report) may or may not have the same "normal" axioms as Pfenning-Davies; we are currently stuck on whether the &lt;tt&gt;◇◇A → ◇A&lt;/tt&gt; holds in &lt;b&gt;CPL&lt;/b&gt; - it definitely holds in &lt;b&gt;CPL*&lt;/b&gt;, Simpson-style &lt;b&gt;S4&lt;/b&gt;, and Pfenning-Davies &lt;b&gt;S4&lt;/b&gt;, but we are a bit perplexed by our inability to prove or disprove it in &lt;b&gt;CPL&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;Here's the &lt;a href="http://cdn.bitbucket.org/robsimmons/constructive-provability-logic/downloads/imla11.pdf"&gt;PDF&lt;/a&gt;, and here's the &lt;a href="http://bitbucket.org/robsimmons/constructive-provability-logic"&gt;bitbucket repository with all our Agda&lt;/a&gt;. As a side note, "oh, all these proofs are in Agda so we're not discussing them" makes the whole "omitted due to space" thing feel way, way less sketchy. This is just a submission at this point, so comments are especially welcome!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-6847599022760192326?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/Xq1zuEv2hmI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/6847599022760192326/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2011/01/two-new-papers.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/6847599022760192326?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/6847599022760192326?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/Xq1zuEv2hmI/two-new-papers.html" title="Two new papers" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2011/01/two-new-papers.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkcCQH87fyp7ImA9Wx9QGEw.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-4953048461404506242</id><published>2010-12-22T06:32:00.000-05:00</published><updated>2010-12-31T11:47:41.107-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-31T11:47:41.107-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="weighted logic programming" /><category scheme="http://www.blogger.com/atom/ns#" term="logic programming" /><category scheme="http://www.blogger.com/atom/ns#" term="focusing" /><category scheme="http://www.blogger.com/atom/ns#" term="complexity" /><category scheme="http://www.blogger.com/atom/ns#" term="search" /><category scheme="http://www.blogger.com/atom/ns#" term="forward-chaining" /><title>Two twists on a graph</title><content type="html">So, something that shouldn't be terribly surprising is that one can take a graph (edges and vertices) and represent it as a set of vertices. This innocent-looking cube will be our example:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;img src="http://typesafety.net/rfl/cube.png"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/td&gt;&lt;td valign="top"&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;edge(a, b)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(a, c)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(c, d)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(b, d)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(a, e)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(b, f)&lt;/tt&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;edge(c, g)&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(d, h)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(e, f)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(e, g)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(g, h)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(f, h)&lt;/tt&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;vertex(a)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(b)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(c)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(d)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(e)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(f)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(g)&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(h)&lt;/tt&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;We'll collect this set of facts and call the collection of propositions (20 atomic propositions in all) &lt;tt&gt;SQUARE&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Also not terribly interesting, but maybe ever-so-slightly interesting, is that one can take this representation of a graph and do forward-chaining logic programming with it. Consider, for example, the following forward-chaining logic program made up of two rules.&lt;pre style="color: #000000;"&gt;  edge(Y,X) &lt;- edge(X,Y).&lt;br /&gt;  reachable(Y) &lt;- edge(X,Y), reachable(X), vertex(Y).&lt;/pre&gt;These are just logical propositions; the upper-case identifiers are implicitly universally quantified, the comma represents conjunction, and (following common convention for logic programming) we write implication backwards as &lt;tt&gt;B &lt;- A&lt;/tt&gt; instead of &lt;tt&gt;A -&gt; B&lt;/tt&gt;. We'll call this collection of two rules &lt;tt&gt;REACH&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;Recall that the behavior of a forward chaining logic program is to take facts that it has and learn more facts. If we just throw the graph at this program, it will use the first rule to derive all the backwards edges (&lt;tt&gt;edge(b,a)&lt;/tt&gt;, &lt;tt&gt;edge(c,a)&lt;/tt&gt;, and so on) but nothing else. If we add an additional single fact &lt;tt&gt;reachable(a)&lt;/tt&gt;, then our forward chaining logic program will furiously learn that &lt;tt&gt;b&lt;/tt&gt;, &lt;tt&gt;c&lt;/tt&gt;, and indeed all the other vertices are reachable. We can rephrase this in the following way: for a &lt;i&gt;specific choice&lt;/i&gt; of &lt;tt&gt;X&lt;/tt&gt; and &lt;tt&gt;Y&lt;/tt&gt;, there is a path from &lt;tt&gt;X&lt;/tt&gt; to &lt;tt&gt;Y&lt;/tt&gt; if and only if there is a derivation of this sequent:&lt;pre style="color: #000000"&gt;  GRAPH, REACH &amp;vdash; reachable(X) -&gt; reachable(Y)&lt;/pre&gt;In fact, the forward chaining logic programming engine, given &lt;tt&gt;reachable(X)&lt;/tt&gt; for some specific &lt;tt&gt;X&lt;/tt&gt;, will derive a fact of the form &lt;tt&gt;reachable(Y)&lt;/tt&gt; for &lt;i&gt;every&lt;/i&gt; reachable &lt;tt&gt;Y&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Twist 1: weighted logic programming&lt;/h2&gt;The first interesting twist on our boring program is this: we consider those proofs of the sequent&lt;pre style="color: #000000;"&gt;  GRAPH, REACH &amp;vdash; reachable(X) -&gt; reachable(Y)&lt;/pre&gt;and we ask, what if some proofs are &lt;i&gt;better&lt;/i&gt; than others? One way to introduce a metric for "what is better" is to say that every one of those atomic propositions has a &lt;i&gt;cost&lt;/i&gt;, and every time we use that atomic proposition in a proof we have to pay that cost: we want the cheapest proof:&lt;table&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;img src="http://typesafety.net/rfl/cubeweights.png"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/td&gt;&lt;td valign="top"&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;edge(a, b) = 66&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(a, c) = 53&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(c, d) = 12&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(b, d) = 57&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(a, e) = 19&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(b, f) = 53&lt;/tt&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;edge(c, g) = 92&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(d, h) = 6&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(e, f) = 8&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(e, g) = 84&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(g, h) = 162&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;edge(f, h) = 4&lt;/tt&gt;&lt;/td&gt;&lt;td valign="top"&gt;&lt;tt&gt;vertex(a) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(b) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(c) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(d) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(e) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(f) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(g) = 0&lt;/tt&gt;&lt;br /&gt;&lt;tt&gt;vertex(h) = 0&lt;/tt&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;This sort of problem is amenable to what is called &lt;i&gt;weighted logic programming&lt;/i&gt;, a declarative way of specifying dynamic programming problems. In this case, if the edge weights are all positive, this is a declarative way of specifying &lt;a href="http://en.wikipedia.org/wiki/Dijkstra's_algorithm"&gt;Dijkstra's algorithm&lt;/a&gt; for single-source shortest path. Before, our forward-chaining logic programming engine took a single fact &lt;tt&gt;reachable(X)&lt;/tt&gt; and computed all the nodes reachable from &lt;tt&gt;X&lt;/tt&gt;. Now, our weighted logic programming engine takes a single fact &lt;tt&gt;reachable(X)&lt;/tt&gt; with cost 0 and computes the minimum-cost route to every node reachable from &lt;tt&gt;X&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Related work&lt;/h3&gt;In fact we can play the same game on any &lt;a href="http://en.wikipedia.org/wiki/Semiring"&gt;semiring&lt;/a&gt; as long as the "score" of a proof is the semiring product of the score of the axioms (in this case, "plus" was the semiring product) and the way we combine the scores of different proofs is the semiring sum of the scores of the two proofs (in this case, "min" was the semiring sum). This sort of generalization-to-an-arbitrary semiring is something that isn't noticed as much as it probably should be. If you're interested in learning or thinking more about weighted logic programming, the first eleven pages of the paper I coauthored with Shay Cohen and Noah Smith, &lt;a href="http://arxiv.org/abs/1006.3035v1"&gt;Products of Weighted Logic Programs&lt;/a&gt;, were written specifically as a general audience/programming languages audience introduction to weighted logic programming. Most of the other literature on weighted logic programming is by &lt;a href="http://www.cs.jhu.edu/~jason"&gt;Jason Eisner&lt;/a&gt;, though the semiring generalization trick was first extensively covered by Goodman in the paper &lt;a href="http://portal.acm.org/citation.cfm?id=973230"&gt;Semiring Parsing&lt;/a&gt;; that paper was part of what inspired Eisner's work on weighted logic programming, at least as I understand it.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Twist 2: linear logic programming&lt;/h2&gt;Another direction that we can "twist" this initially graph discussion is by adding linearity. Linear facts (in the sense of linear logic) are unlike "regular" facts - regular facts can be used any number of times or used not at all - they are &lt;i&gt;persistent&lt;/i&gt;. Linear facts can only be used once in a proof - and in fact, they &lt;i&gt;must&lt;/i&gt; be used once in a proof. &lt;br /&gt;&lt;br /&gt;We've had the &lt;tt&gt;vertex&lt;/tt&gt; propositions hanging around all this time and not doing much; one thing we can do is make these vertex propositions linear, and we'll make the &lt;tt&gt;reachable&lt;/tt&gt; propositions linear as well. In this example, we'll designate linear propositions by &lt;span style="text-decoration: underline;"&gt;underlining&lt;/span&gt; them and coloring them &lt;span style="color:#CC0000"&gt;red&lt;/span&gt;; our program before turns into this:&lt;pre style="color: #000000;"&gt;  edge(Y,X) &lt;- edge(X,Y).&lt;br /&gt;  &lt;span style="text-decoration: underline; color:#CC0000;"&gt;reachable&lt;/span&gt;(Y) &lt;- edge(X,Y), &lt;span style="text-decoration: underline; color:#CC0000;"&gt;reachable&lt;/span&gt;(X), &lt;span style="text-decoration: underline; color:#CC0000;"&gt;vertex&lt;/span&gt;(Y).&lt;/pre&gt;By the way, if you're familiar with linear logic, the logical meaning of this formula is captured by the following two propositions written properly in linear logic:&lt;pre style="color: #0000CC;"&gt;  &amp;forall;x. &amp;forall;y. !edge(x,y) -o edge(y,x).&lt;br /&gt;  &amp;forall;x. &amp;forall;y. !edge(x,y) -o reachable(x) -o vertex(y) -o reachable(y).&lt;/pre&gt;We'll talk a little bit more about this specification (call it &lt;tt&gt;LREACH&lt;/tt&gt;) shortly; for the moment let's switch to a different train of thought.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Greedy logic programming with linear logic&lt;/h3&gt;When we talked before about the cost of using a fact in a proof, we were actually assuming a little bit about proofs being focused; we'll talk a little bit about focusing and synthetic rules in this section (see &lt;a href="http://requestforlogic.blogspot.com/2010/09/focusing-and-synthetic-rules.html"&gt;this old blog post&lt;/a&gt; for background). &lt;br /&gt;&lt;br /&gt;If we make all of our atomic propositions positive, then the synthetic rule associated with the critical second rule above ends up looking like this:&lt;pre style="color: #000000;"&gt;  Γ, edge(X,Y); &lt;span style="color:#CC0000;"&gt;Δ, &lt;span style="text-decoration: underline;"&gt;reachable&lt;/span&gt;(Y)&lt;/span&gt; &amp;vdash; C&lt;br /&gt;  ---------------------------------------------&lt;br /&gt;  Γ, edge(X,Y); &lt;span style="color:#CC0000;"&gt;Δ, &lt;span style="text-decoration: underline;"&gt;reachable&lt;/span&gt;(X), &lt;span style="text-decoration: underline;"&gt;vertex&lt;/span&gt;(Y)&lt;/span&gt; &amp;vdash; C&lt;/pre&gt;Recall that we like to read forward chaining rules from the bottom to the top. If we assume that the context only ever contains a single &lt;tt&gt;&lt;span style="text-decoration: underline; color:#CC0000;"&gt;reachable&lt;/span&gt;(X)&lt;/tt&gt; proposition, then we can think of the linear context as a resource consuming automaton that is in state &lt;tt&gt;X&lt;/tt&gt;. At each step, the automaton consumes an available resource &lt;tt&gt;&lt;span style="text-decoration: underline; color:#CC0000;"&gt;vertex&lt;/span&gt;(Y)&lt;/tt&gt; with the constraint that there must be an edge from &lt;tt&gt;X&lt;/tt&gt; to &lt;tt&gt;Y&lt;/tt&gt;; the automaton then transitions to state &lt;tt&gt;Y&lt;/tt&gt;.&lt;br /&gt;&lt;br /&gt;One efficient way to give a logic programming semantics to these kind of forward-chaining linear logical specifications is to just implement an arbitrary run of the automaton without ever backtracking. This is a greedy strategy, and it can be used to efficiently implement some greedy algorithms. This was the point of &lt;a href="http://www.cs.cmu.edu/~rjsimmon/papers/simmons08linlogalg.html"&gt;Linear Logical Algorithms&lt;/a&gt;, a paper I coauthored with Frank Pfenning. One neat example from that paper was the following graph program, which computes a spanning tree for a graph rooted at the vertex &lt;tt&gt;a&lt;/tt&gt;:&lt;pre style="color:#000000;"&gt;  edge(Y,X) &lt;- edge(X,Y).&lt;br /&gt;  intree(a) &lt;- &lt;span style="text-decoration: underline; color:#CC0000;"&gt;vertex&lt;/span&gt;(a).&lt;br /&gt;  tree(X,Y), intree(Y) &lt;- edge(X, Y), intree(X), &lt;span style="text-decoration: underline; color:#CC0000;"&gt;vertex&lt;/span&gt;(Y).&lt;/pre&gt;This program works like another little resource-consuming automaton that, at each step, consumes a &lt;tt&gt;&lt;span style="text-decoration: underline; color:#CC0000;"&gt;vertex&lt;/span&gt;&lt;/tt&gt; resource to add a non-tree vertex to the tree along a newly added tree edge. This is, incidentally, the same way &lt;a href="http://en.wikipedia.org/wiki/Prim's_algorithm"&gt;Prim's algorithm&lt;/a&gt; for minimum spanning trees progresses.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Hamiltonian paths in linear logic&lt;/h3&gt;The greedy strategy where we look at one possible set of choices is very different than the behavior of our briefly-sketched forward-chaining persistent and weighted logic programming engines. The latter worked by taking some initial information (&lt;tt&gt;reachable(X)&lt;/tt&gt; for some &lt;tt&gt;X&lt;/tt&gt;) and finding, &lt;i&gt;all at once&lt;/i&gt; and with reasonable efficiency, every single &lt;tt&gt;Y&lt;/tt&gt; for a given &lt;tt&gt;X&lt;/tt&gt; such that the following sequent holds:&lt;pre style="color: #000000"&gt;  GRAPH, REACH &amp;vdash; reachable(X) -&gt; reachable(Y)&lt;/pre&gt;Call the (persistent) edges &lt;tt&gt;EDGE&lt;/tt&gt;, and the (linear) vertices &lt;tt&gt;&lt;span style="color:#CC0000;"&gt;VERT&lt;/span&gt;&lt;/tt&gt;. Now we can look at the (seemingly) analogous problem stated in linear logic to see why it is in practice, so different:&lt;pre style="color: #000000"&gt;  LREACH, EDGE; &lt;span style="color:#CC0000;"&gt;VERT&lt;/span&gt; &amp;vdash; &amp;vdash; &lt;span style="text-decoration: underline; color:#CC0000;"&gt;reachable&lt;/span&gt;(X) -o &lt;span style="text-decoration: underline; color:#CC0000;"&gt;reachable&lt;/span&gt;(Y)&lt;/pre&gt;Because linear logic requires that we eventually use every resource in &lt;tt&gt;&lt;span style="color:#CC0000;"&gt;VERT&lt;/span&gt;&lt;/tt&gt;, this derivation corresponds to a run of the automaton where the automaton visited every single node and then ended at &lt;tt&gt;Y&lt;/tt&gt;. If we consider just the case where &lt;tt&gt;X&lt;/tt&gt; and &lt;tt&gt;Y&lt;/tt&gt; are the same, complete derivations correspond to &lt;a href="http://en.wikipedia.org/wiki/Hamiltonian_path"&gt;Hamiltonian tours&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;By adding linearity, we've made the forward chaining language more expressive, but in doing so we created a big gulf between the "existential" behavior (here's one way the automaton might work, which we found by being greedy) and the "universal" behavior (the automaton can, potentially, follow a Hamiltonian path, which we learned by calling a SAT solver). This gap did not exist, at least for our running example, in the persistent or weighted cases.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Combining the twists?&lt;/h2&gt;Both linear logic programming and weighted logic programming arise start from a simple observation: &lt;i&gt;the shape of proofs can capture interesting structures&lt;/i&gt;. The "structure" in this case was a path through a graph; in weighted logic programming the structures are often parse trees - you know, "boy" is a noun, "fast" is an adverb, "the" is a demonstrative adjective, and the two combined are a noun phrase, until you get a tree that looks something like this:&lt;pre style="color: #000000;"&gt;    Sentence &lt;br /&gt;      /  \&lt;br /&gt;     NP  VP&lt;br /&gt;    /|   | \&lt;br /&gt;  /  |   |  \&lt;br /&gt; D   N   V   A&lt;br /&gt; |   |   |   |&lt;br /&gt;the boy ran fast&lt;/pre&gt;(More on this in the "Products of Weighted Logic Programs" paper.)&lt;br /&gt;&lt;br /&gt;Weighted logic programming enriches this observation by allowing us to &lt;i&gt;measure&lt;/i&gt; structures and talk about the combined measure of a whole class of structures; linear logic, on the other hand, greatly improves on the things that we &lt;i&gt;can&lt;/i&gt; measure. But what about using the observations of weighted logic programming to assign scores in the richer language of linear logic programming? What would that look like?  I'll give a couple of sketches. These are questions I don't know the answers to, don't know that I'll have time to think about in the near future, but would love to talk further about with anybody who was interested. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Minimum spanning tree&lt;/h3&gt;I commented before that the logic programming engine described in Linear Logical Algorithms implements something a bit like Prim's algorithm to produce a graph spanning tree. In fact, the engine we described does so with provably optimal complexity - &lt;i&gt;O(|E| + |V|)&lt;/i&gt;, time proportional to the number of edges in the graph or the number of vertices in the graph (whichever is larger). What's more, we have a good &lt;i&gt;cost semantics&lt;/i&gt; for this class of weighted logic programs; this means you don't actually have to understand how the interpreter works, you can reason about the runtime behavior of linear logical algorithms on a much more abstract level. The recorded presentation on Linear Logical Algorithms, as well as the paper, discuss this.&lt;br /&gt;&lt;br /&gt;If we replace a queue inside the engine with an appropriately configured priority queue, then the logic programming engine &lt;i&gt;actually&lt;/i&gt; implements Prim's algorithm for the low cost of an &lt;i&gt;log(|V|)&lt;/i&gt; factor. But can this be directly expressed as a synthesis of weighted logic programming and linear logic programming? And can we do so while still maintaining a reasonable cost semantics? I don't know.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Traveling salesman problem&lt;/h3&gt;While minimum spanning tree is a greedy "existential" behavior of linear logic proof search, the weighted analogue of the Hamiltonian Path problem is just the Traveling Salesman problem - we not only want a Hamiltonian path, we want the &lt;i&gt;best&lt;/i&gt; Hamiltonian path as measured by a straightforward extension of the notion of weight from weighted logic programming. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Not-linear logics?&lt;/h3&gt;Adding some linearity turned a single-source shortest path problem into a Hamiltonian path problem - when we turned vertices from persistent facts into linear resources, we essentially required each vertex to be "visited" exactly once. However, an &lt;i&gt;affine logic&lt;/i&gt; interpretation of the same program would preserve the resource interpretation (vertices cannot be revisited) while removing the obligation - vertices can be visited once &lt;i&gt;or they can be ignored altogether&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;This makes the problem much more like the shortest path problem again. If edge weights are positive, then the shortest path never revisits a node, so it's for all intents and purposes &lt;i&gt;exactly&lt;/i&gt; the shortest path problem again. If edge weights are negative, then disallowing re-visiting is arguably the only sensible way to specify the problem at all. Can this observation be generalized? Might it be possible to solve problems in (weighted) affine logic more easily than problems in weighted linear logic?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-4953048461404506242?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/UgkY5j6wVZI" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/4953048461404506242/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2010/12/two-twists-on-graph.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4953048461404506242?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/4953048461404506242?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/UgkY5j6wVZI/two-twists-on-graph.html" title="Two twists on a graph" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2010/12/two-twists-on-graph.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEMHRn07fSp7ImA9Wx9REEw.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-2040749217152623626</id><published>2010-12-08T19:49:00.000-05:00</published><updated>2010-12-10T16:27:17.305-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-12-10T16:27:17.305-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Agda" /><category scheme="http://www.blogger.com/atom/ns#" term="constructive provability logic" /><category scheme="http://www.blogger.com/atom/ns#" term="natural deduction" /><category scheme="http://www.blogger.com/atom/ns#" term="judgmental reconstruction" /><category scheme="http://www.blogger.com/atom/ns#" term="sequent calculus" /><title>Principles of Constructive Provability Logic</title><content type="html">So I think Bernardo and I have finally finished slaying the beast of a technical report we've been working on on-and-off all semester. I previously mentioned this tech report &lt;a href="http://requestforlogic.blogspot.com/2010/09/background-to-constructive-provability.html"&gt;here&lt;/a&gt;. The intended &lt;i&gt;audience&lt;/i&gt; for this paper is anyone who has read &lt;a href="http://www.cs.cmu.edu/~fp/papers/mscs00.pdf"&gt;"A Judgmental Reconstruction of Modal Logic"&lt;/a&gt; (also known ubiquitously to CMUers as "Pfenning-Davies") and/or who has tasteful ideas about natural deduction and some notion of how modal logic works.&lt;br /&gt;&lt;br /&gt;Unlike this blog post, which I wrote in 15 minutes while tired, Bernardo and I have worked very, very hard on trying making this report foundational and clear, and I'd definitely appreciate any feedback people have (large and small) since hopefully this won't be the last time I talk about constructive provability logic. Even if the feedback is that my jokes are really dumb and don't add anything to the paper (I should mention for Bernardo's sake that all the dumb jokes are my fault).&lt;blockquote&gt;&lt;b&gt;Principles of Constructive Provability Logic&lt;/b&gt;&lt;br/&gt;Robert J. Simmons and Bernardo Toninho.&lt;br/&gt;[&lt;a href="http://reports-archive.adm.cs.cmu.edu/anon/2010/CMU-CS-10-151.pdf"&gt;PDF&lt;/a&gt;], [&lt;a href="http://reports-archive.adm.cs.cmu.edu/anon/2010/constructive-provability-logic.tgz"&gt;Agda tarball&lt;/a&gt;], and [&lt;a href="http://typesafety.net/rfl/cpl-tr"&gt;Agda HTML&lt;/a&gt;]&lt;br/&gt;&lt;br/&gt;&lt;i&gt;Abstract:&lt;/i&gt; We present a novel formulation of the modal logic &lt;b&gt;CPL&lt;/b&gt;, a &lt;i&gt;constructive logic of provability&lt;/i&gt; that is closely connected to the G&amp;ouml;del-L&amp;ouml;b logic of provability. Our logical formulation allows modal operators to talk about both &lt;i&gt;provability&lt;/i&gt; and &lt;i&gt;non-provability&lt;/i&gt; of propositions at reachable worlds. We are interested in the applications of &lt;b&gt;CPL&lt;/b&gt; to logic programming; however, this report focuses on the presentation of a minimal fragment (in the sense of minimal logic) of &lt;b&gt;CPL&lt;/b&gt; and on the formalization of minimal &lt;b&gt;CPL&lt;/b&gt; and its metatheory in the Agda programming language. We present both a natural deduction system and a sequent calculus for minimal &lt;b&gt;CPL&lt;/b&gt; and show that the presentations are equivalent.&lt;/blockquote&gt;The &lt;i&gt;topic&lt;/i&gt; of the paper is "constructive provability logic" (&lt;b&gt;CPL&lt;/b&gt;), a rich vein of logic that we've only just begun exploring.&lt;sup&gt;1&lt;/sup&gt; The abstract and the introduction point out our primary reason for being interested in this logic: we want to give a general, satisfying, and proof-theoretic account for negation in logic programming. In fact, I've already gone out on a limb and &lt;a href="http://robsimmons.bitbucket.org/l10"&gt;written out the design of a distributed logic programming language&lt;/a&gt; based on a variant of &lt;b&gt;CPL&lt;/b&gt; that I haven't quite-just-yet gotten around to entirely writing down. But I'm also just starting to implement the logic programming language, so it's not like I'm &lt;i&gt;that&lt;/i&gt; far ahead of myself. The classical modal logic (which has about a dozen names but let's call it &lt;b&gt;GL&lt;/b&gt; for G&amp;ouml;del-L&amp;ouml;b) that we're intuitionisticing&lt;sup&gt;2&lt;/sup&gt; about with has deep connections to everything from G&amp;ouml;del's incompleteness theorems to the denotational semantics of programming languages (it's the "modal" in the &lt;a href="http://portal.acm.org/citation.cfm?id=1190235"&gt;very modal models&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;What's so special about this logic? Well, when you're working in the Kripke semantics of a modal logic, you should think of yourself as standing and a particular &lt;i&gt;world&lt;/i&gt; and looking at some other worlds (these worlds are called &lt;i&gt;accessible&lt;/i&gt;, and an accessibility relation determines which worlds are accessible). Maybe there aren't any! Maybe there are. Maybe you can see the world you're standing on, like being in a hall of mirrors. Maybe you can see one other world, and then beyond that world you can see back to the world you're standing on, like being in Pac-Man. The situation for &lt;b&gt;GL&lt;/b&gt; and &lt;b&gt;CPL&lt;/b&gt; is that not only can you not see yourself, you can't see forever - you can look past the accessible worlds to the worlds accessible from those (the "2-accessible" worlds, say) and then to the 3-accessible worlds... but this can't go on forever (jargon: the accessibility relation is "converse well-founded," there are no infinite ascending chains). &lt;br /&gt;&lt;br /&gt;If you find yourself in a planetary system with a converse well-founded accessibility relation such as this one, the key is that, if you ever find your spaceship and go to one of those accessible worlds, there's now &lt;i&gt;strictly less to see&lt;/i&gt;. Put another way, there's necessarily a little more going on where you're standing than in the places you're looking at. If this leads you to think that the places you can see are kind of an approximation of the place where you are, you're heading towards the approximation ("modal model"-esque) interpretation of &lt;b&gt;GL&lt;/b&gt;. If you think "oh, the &lt;i&gt;little more going on&lt;/i&gt; could refer to logical consistency," then you're heading towards the "provability" interpretation of &lt;b&gt;GL&lt;/b&gt;. Perhaps the provability interpretation will inspire you to send a  logician on every world and allow each logician to reason about the logical consistency of &lt;i&gt;all the logicians he can see&lt;/i&gt;.&lt;sup&gt;3&lt;/sup&gt; Sure, you'll never get enough watchers for all the watchmen, but that is an occupational hazard of modern mathematics. &lt;br /&gt;&lt;br /&gt;Anyway, I'll stop there: hopefully the details in the tech report are much, much clearer than the discussion in the preceding few paragraphs. &lt;br /&gt;&lt;br /&gt;&lt;hr&gt;&lt;small&gt;&lt;sup&gt;1&lt;/sup&gt; I don't know when I started referring to my life as "working in the logic mines," it's really not fair to miners who have a really hard job that often isn't fun, unlike me. Maybe I'm just jealous of &lt;a href="http://www.flickr.com/photos/30686429@N07/3954694814/in/set-72157622330082619/"&gt;Mary's hat&lt;/a&gt;&lt;br/&gt;&lt;sup&gt;2&lt;/sup&gt; &lt;b&gt;Intuitionisticing.&lt;/b&gt; &lt;i&gt;v.&lt;/i&gt; To experimentally take a classical logic and try to deduce constructive, intuitionistic principles and proof theories out of it: &lt;i&gt;Rowan and Alex were intuitionisticing about with propositional S4, and they both came up with things that seemed internally consistent but that were oddly incompatible.&lt;/i&gt;&lt;br/&gt;&lt;sup&gt;3&lt;/sup&gt; Hey! It's a bad idea to use male pronouns to describe mathematicians! Okay, would you rather me be &lt;i&gt;shooting female logicians into space for no compelling reason?&lt;/i&gt; Alright then.&lt;/small&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-2040749217152623626?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/bhZpe8fCcDc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/2040749217152623626/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2010/12/principles-of-constructive-provability_08.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2040749217152623626?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/2040749217152623626?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/bhZpe8fCcDc/principles-of-constructive-provability_08.html" title="Principles of Constructive Provability Logic" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2010/12/principles-of-constructive-provability_08.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EGSHo7eip7ImA9Wx5aGEo.&quot;"><id>tag:blogger.com,1999:blog-827419514217130218.post-6421868563013322419</id><published>2010-11-14T22:18:00.000-05:00</published><updated>2010-11-15T22:53:49.402-05:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-15T22:53:49.402-05:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="binding" /><category scheme="http://www.blogger.com/atom/ns#" term="Agda" /><category scheme="http://www.blogger.com/atom/ns#" term="Twelf" /><category scheme="http://www.blogger.com/atom/ns#" term="constructive provability logic" /><category scheme="http://www.blogger.com/atom/ns#" term="logic" /><title>Totally nameless representation</title><content type="html">&lt;i&gt;[Note: I am unaware of any truly original content in this post; when I say "we picked this up from Dan" it doesn't imply Dan worked it out himself; when I say "we worked this out" I don't have any reason to believe we were the first. Dan Licata in a comment lists some of the references to things we generally absorbed from him.]&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This post is about two things. The first topic is a style of formalization in Agda that &lt;a href="http://www.cs.cmu.edu/~btoninho/"&gt;Bernardo Toninho&lt;/a&gt; and I picked up on from &lt;a href="http://www.cs.cmu.edu/~drl/"&gt;Dan Licata&lt;/a&gt;. The second topic is a way of establishing termination arguments that Bernardo and I worked out and used extensively in the Agda formalizaiton of several variants of Constructive Provability Logic, which I've &lt;a href="http://requestforlogic.blogspot.com/2010/09/background-to-constructive-provability.html"&gt;mentioned before&lt;/a&gt;. Because I'm a bit perverse, I'll be using my &lt;a href="http://bitbucket.org/robsimmons/agda-lib"&gt;own Agda Standard Library&lt;/a&gt; as the basis for this post; the code for this post can be found &lt;a href="http://bitbucket.org/robsimmons/agda-lib/src/tip/Demo/STLC.agda"&gt;here&lt;/a&gt; - since it's a demo bound together with my library, technically I guess I'm supposed to keep the file at that link (though maybe not this post) in sync with the library as the library evolves.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Starting point: the simply-typed lambda calculus&lt;/h2&gt;This is a pretty standard Agda formalization of "Church-style" simply-typed lambda calculus terms. "Church-style," as opposed to "Curry-style," encodings only allow for the existence of well-typed terms.&lt;a href="#shamelessplug"&gt;*&lt;/a&gt;&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold;"&gt;   &lt;span style="color:#cc4020"&gt;open import&lt;/span&gt; &lt;span style="color:#9900ff"&gt;Prelude&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#cc4020"&gt;infixr&lt;/span&gt; &lt;span style="color:#9900ff"&gt;5&lt;/span&gt; _⊃_&lt;br /&gt;   &lt;span style="color:#cc4020"&gt;data&lt;/span&gt; &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Set&lt;/span&gt; &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;con&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;String&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;_⊃_&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;List Type&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#cc4020"&gt;infixl&lt;/span&gt; &lt;span style="color:#9900ff"&gt;5&lt;/span&gt; _·_&lt;br /&gt;   &lt;span style="color:#cc4020"&gt;data&lt;/span&gt; &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (Γ : &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt;) : &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Set&lt;/span&gt; &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;var&lt;/span&gt; : ∀{A} → A &lt;span style="color:#0000ff"&gt;∈&lt;/span&gt; Γ → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A&lt;br /&gt;      &lt;span style="color:#009900"&gt;_·_&lt;/span&gt; : ∀{A B} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ (A ⊃ B) → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ B&lt;br /&gt;      &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; : ∀{A B} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) B → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ (A ⊃ B)&lt;/pre&gt;The only non-obvious part of this encoding is that variables are represented by "dependent de Bruijn indices" - instead of a de Bruijn index being just a natural number, it's the pointer into its type in the context. The nice part about doing it this way is that you can define a very powerful notion of "generalized weakening" that is based on the "subset" partial order on contexts (&lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;Γ &lt;span style="color:#0000ff"&gt;⊆&lt;/span&gt; Δ&lt;/span&gt;&lt;/tt&gt; is a function mapping all the indices &lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;A &lt;span style="color:#0000ff"&gt;∈&lt;/span&gt; Γ&lt;/span&gt;&lt;/tt&gt; to indices &lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;A &lt;span style="color:#0000ff"&gt;∈&lt;/span&gt; Δ&lt;/span&gt;&lt;/tt&gt;).&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;_⊆_&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Set&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;_⊆_&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;LIST.SET.Sub&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; : ∀{Γ Δ A} → Γ &lt;span style="color:#0000ff"&gt;⊆&lt;/span&gt; Δ → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Δ A &lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ (&lt;span style="color:#009900"&gt;var&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;var&lt;/span&gt; (θ n)&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ (n1 &lt;span style="color:#009900"&gt;·&lt;/span&gt; n2) = &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ n1 &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ n2&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;LIST.SET.sub-cons-congr&lt;/span&gt; θ) n)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;The nice part about this definition, and one of the things I picked up on from Dan, is that we can then define the usual weakening, exchange, and contraction properties directly by using generalized weakening and the corresponding facts about the subset relation on lists (which are defined in my standard library).&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;wken&lt;/span&gt; : ∀{Γ A C} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ C → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wken&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;wk LIST.SET.sub-wken&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;exch&lt;/span&gt; : ∀{Γ A B C} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; B &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (B &lt;span style="color:#009900"&gt;::&lt;/span&gt; A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;exch&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;wk LIST.SET.sub-exch&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;cntr&lt;/span&gt; : ∀{Γ A C} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C &lt;br /&gt;   &lt;span style="color:#0000ff"&gt;cntr&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;wk LIST.SET.sub-cntr&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;With that out of the way, we can talk about substitution, both the "obvious way" and the metric-indexed way Bernardo and I have used extensively.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Straightforward substitution&lt;/h2&gt;The obvious (for some value of obvious) and direct definition of substitution involves 1) generalizing the induction hypothesis to allow for even more additions (&lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;tm-subst&lt;/span&gt;&lt;/tt&gt;) and 2) writing a variable substitution lemma that handles the case where the substituted-into term is a variable and we either perform the substitution, lower the de Bruijn index, or leaving the de Bruijn index alone (&lt;tt&gt;&lt;span style="color:#0000ff ; font-weight:bold"&gt;var-subst&lt;/span&gt;&lt;/tt&gt;). The main theorem is inductive on the structure of the first term.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;subst&lt;/span&gt; : ∀{Γ A C} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ C&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;subst&lt;/span&gt; = &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; [] _&lt;br /&gt;    &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; : ∀{A C} (Γ Γ' : &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt;)&lt;br /&gt;         → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ' A&lt;br /&gt;         → C &lt;span style="color:#0000ff"&gt;∈&lt;/span&gt; (Γ &lt;span style="color:#0000ff"&gt;++ [&lt;/span&gt; A &lt;span style="color:#0000ff"&gt;] ++&lt;/span&gt; Γ') &lt;br /&gt;         → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (Γ &lt;span style="color:#0000ff"&gt;++&lt;/span&gt; Γ') C&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; &lt;span style="color:#009900"&gt;[]&lt;/span&gt; Γ' n1 &lt;span style="color:#009900"&gt;Z&lt;/span&gt; = n1&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; &lt;span style="color:#009900"&gt;[]&lt;/span&gt; Γ' n1 (&lt;span style="color:#009900"&gt;S&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;var&lt;/span&gt; n&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; (_ &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) Γ' n1 &lt;span style="color:#009900"&gt;Z&lt;/span&gt; = &lt;span style="color:#009900"&gt;var&lt;/span&gt; &lt;span style="color:#009900"&gt;Z&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; (_ &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) Γ' n1 (&lt;span style="color:#009900"&gt;S&lt;/span&gt; n) = &lt;span style="color:#0000ff"&gt;wken&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; Γ Γ' n1 n)&lt;br /&gt; &lt;br /&gt;      &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; : ∀{A C} (Γ Γ' : &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt;) &lt;br /&gt;         → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ' A&lt;br /&gt;         → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (Γ &lt;span style="color:#0000ff"&gt;++ [&lt;/span&gt; A &lt;span style="color:#0000ff"&gt;] ++&lt;/span&gt; Γ') C &lt;br /&gt;         → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (Γ &lt;span style="color:#0000ff"&gt;++&lt;/span&gt; Γ') C &lt;br /&gt;      &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; Γ Γ' n1 (&lt;span style="color:#009900"&gt;var&lt;/span&gt; n) = &lt;span style="color:#0000ff"&gt;var-subst&lt;/span&gt; Γ Γ' n1 n&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; Γ Γ' n1 (n &lt;span style="color:#009900"&gt;·&lt;/span&gt; n') = &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; Γ Γ' n1 n &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; Γ Γ' n1 n'&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; Γ Γ' n1 (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;tm-subst&lt;/span&gt; (_ &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) Γ' n1 n)&lt;/span&gt;&lt;/pre&gt;To motivate the next step, I'll point out that the only reason we had to generalize the induction hypothesis is because of the lambda case - if we try to prove the theorem directly, we find ourselves in the position of having a &lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A&lt;/span&gt;&lt;/tt&gt; and a &lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;&lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (B &lt;span style="color:#009900"&gt;::&lt;/span&gt; A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C&lt;/span&gt;&lt;/tt&gt;; we can't apply the induction hypothesis directly on these two terms. We can apply &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;wken&lt;/span&gt;&lt;/tt&gt; to the first subterm and apply &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;exch&lt;/span&gt;&lt;/tt&gt; to the second subterm and call &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;subst&lt;/span&gt;&lt;/tt&gt; recursively, but now we can't establish termination on the structure of the second term, since we've passed it to the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;exch&lt;/span&gt;&lt;/tt&gt; function, which changed its structure by replacing &lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;Z&lt;/span&gt;&lt;/tt&gt;s with (&lt;tt&gt;&lt;span style="color:#009900; font-weight:bold"&gt;S Z&lt;/span&gt;&lt;/tt&gt;)s and vice versa.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Setting up a metric&lt;/h2&gt;The alternate solution I intend to present involves setting up a metric; this metric expresses the "shape" of a term, disregarding all binding. This is a three-step process: first we define a generic "tree" piece of data that can capture the shape of a term (disregarding binding), and second we define a copy of the &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Term&lt;/span&gt;&lt;/tt&gt; datatype, called &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;MTerm&lt;/span&gt;&lt;/tt&gt;, that has a &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;Metric&lt;/span&gt;&lt;/tt&gt; as one of its indices.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#cc4020"&gt;data&lt;/span&gt; &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Set&lt;/span&gt; &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;○&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;_●_&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;&gt;&lt;/span&gt; : &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#cc4020"&gt;data&lt;/span&gt; &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; (Γ : &lt;span style="color:#0000ff"&gt;Ctx&lt;/span&gt;) : &lt;span style="color:#0000ff"&gt;Type&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Metric&lt;/span&gt; → &lt;span style="color:#0000ff"&gt;Set&lt;/span&gt; &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;var&lt;/span&gt; : ∀{A} → A &lt;span style="color:#0000ff"&gt;∈&lt;/span&gt; Γ → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ A &lt;span style="color:#009900"&gt;○&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#009900"&gt;_·_&lt;/span&gt; : ∀{A B m m'} → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ (A &lt;span style="color:#009900"&gt;⊃&lt;/span&gt; B) m → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ A m' → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ B (m &lt;span style="color:#009900"&gt;●&lt;/span&gt; m')&lt;br /&gt;      &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; : ∀{A B m} → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) B m → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ (A &lt;span style="color:#009900"&gt;⊃&lt;/span&gt; B) (&lt;span style="color:#009900"&gt;&gt;&lt;/span&gt; m)&lt;/span&gt;&lt;/pre&gt;The third step is to show that we can freely get into and out of the metric; potentially we should also show that these two actions are an isomorphism, but I haven't run across the need to actually prove that. It really turns out that Agda does most of the work here...&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; : ∀{Γ A m} → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ A m → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; (&lt;span style="color:#009900"&gt;var&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;var&lt;/span&gt; n&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; (n1 &lt;span style="color:#009900"&gt;·&lt;/span&gt; n2) = &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; n1 &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; n2&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; n)&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; : ∀{Γ A} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → ∃ λ m → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ A m&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; (&lt;span style="color:#009900"&gt;var&lt;/span&gt; n) = &lt;span style="color:#0000ff"&gt;,&lt;/span&gt; &lt;span style="color:#009900"&gt;var&lt;/span&gt; n&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; (n1 &lt;span style="color:#009900"&gt;·&lt;/span&gt; n2) = &lt;span style="color:#0000ff"&gt;,&lt;/span&gt; &lt;span style="color:#0000ff"&gt;snd&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; n1) &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;snd&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; n2)&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#0000ff"&gt;,&lt;/span&gt; &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;snd&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; n))&lt;/span&gt;&lt;/pre&gt;Now that we have our metric, we can prove a stronger and more useful version of the generalized weakening lemma: not only can we apply generalized weakening to terms, but the resulting term has the exact same shape (as shown by the fact that the same metric "&lt;tt&gt;&lt;span style="color:#000000; font-weight:bold"&gt;m&lt;/span&gt;&lt;/tt&gt;" appears as an index both to the function's argument and its conclusion.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; : ∀{Γ Δ A m} → Γ &lt;span style="color:#0000ff"&gt;⊆&lt;/span&gt; Δ → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Γ A m → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; Δ A m&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ (&lt;span style="color:#009900"&gt;var&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;var&lt;/span&gt; (θ n)&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ (n &lt;span style="color:#009900"&gt;·&lt;/span&gt; n') = &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ n &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ n'&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;LIST.SET.sub-cons-congr&lt;/span&gt; θ) n)&lt;/span&gt;&lt;/pre&gt;We don't need to prove weakening twice; our previous weakening lemma is just a simple consequence of this new, stronger one:&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; : ∀{Γ Δ A} → Γ &lt;span style="color:#0000ff"&gt;⊆&lt;/span&gt; Δ → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Δ A &lt;br /&gt;   &lt;span style="color:#0000ff"&gt;wk&lt;/span&gt; θ n = &lt;span style="color:#0000ff"&gt;tm→&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;wkM&lt;/span&gt; θ (&lt;span style="color:#0000ff"&gt;snd&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; n)))&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Substitution with the metric&lt;/h2&gt;With the metric in tow, substitution is straightforward. Termination is established by induction on the metric of the second term. Note the use of both &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;wken&lt;/span&gt;&lt;/tt&gt; (weakening outside of the metric) and &lt;tt&gt;&lt;span style="color:#0000ff; font-weight:bold"&gt;exchM&lt;/span&gt;&lt;/tt&gt; (exchange inside the metric) in the lambda case.&lt;pre&gt;&lt;span style="color:#000000; font-weight:bold"&gt;   &lt;span style="color:#0000ff"&gt;subst&lt;/span&gt; : ∀{Γ A C} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ C&lt;br /&gt;   &lt;span style="color:#0000ff"&gt;subst&lt;/span&gt; n1 n2 = &lt;span style="color:#0000ff"&gt;&lt;span style="color:#0000ff"&gt;substM&lt;/span&gt;&lt;/span&gt; n1 (&lt;span style="color:#0000ff"&gt;snd&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;→tm&lt;/span&gt; n2))&lt;br /&gt;    &lt;span style="color:#cc4020"&gt;where&lt;/span&gt;&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; : ∀{Γ A C m} → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ A → &lt;span style="color:#0000ff"&gt;MTerm&lt;/span&gt; (A &lt;span style="color:#009900"&gt;::&lt;/span&gt; Γ) C m → &lt;span style="color:#0000ff"&gt;Term&lt;/span&gt; Γ C&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 (&lt;span style="color:#009900"&gt;var&lt;/span&gt; &lt;span style="color:#009900"&gt;Z&lt;/span&gt;) = n1&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 (&lt;span style="color:#009900"&gt;var&lt;/span&gt; (&lt;span style="color:#009900"&gt;S&lt;/span&gt; n)) = &lt;span style="color:#009900"&gt;var&lt;/span&gt; n&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 (n &lt;span style="color:#009900"&gt;·&lt;/span&gt; n') = &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 n &lt;span style="color:#009900"&gt;·&lt;/span&gt; &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 n'&lt;br /&gt;      &lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; n1 (&lt;span style="color:#009900"&gt;Λ&lt;/span&gt; n) = &lt;span style="color:#009900"&gt;Λ&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;substM&lt;/span&gt; (&lt;span style="color:#0000ff"&gt;wken&lt;/span&gt; n1) (&lt;span style="color:#0000ff"&gt;exchM&lt;/span&gt; n))&lt;/span&gt;&lt;/pre&gt;In this example, it's not clear that we've saved much work: setting up the metric was a lot of boilerplate, though it is straightforward; the benefit that we gained in terms of proof simplicity was primarily an artifact of Agda's pattern matching: either a variable was the first variable in the context (and therefore represented by the de Bruijn index &lt;tt&gt;&lt;span style="color:#009900"&gt;Z&lt;/span&gt;&lt;/tt&gt;), or it was later in the context. So this example isn't the world's best argument for this style, but in the more complex logics that Bernardo and I dealt with, we found that this technique seemed, of all the approaches we could think of, to be the one least likely to fail on us.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Comments&lt;/h2&gt;Dan's said on a couple of occasions that he thinks there are less painful ways of doing this sort of thing, existing Agda techniques that avoid the annoying duplication of data types. My understanding is also that there is a not-totally-integrated notion of "sized types" in Agda that could maybe handle this sort of thing, but that the way it works is by defining metrics that are only natural numbers. It seems like a step backwards, somehow, if we go from structural induction to natural number induction. Furthermore, sized types based on natural numbers would almost certainly fail to handle the vaguely insane termination arguments that come up in constructive provability logic.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Totally nameless representations?&lt;/h3&gt;The germ of this post comes from a conversation with &lt;a href="http://www.seas.upenn.edu/~ccasin/"&gt;Chris Casinghino&lt;/a&gt; at UPenn back in May. He was working on extending this sort of simple representation in a way that was similarly-insane but mostly unrelated to constructive provability logic. Our problems were different; he placed the blame for some of the difficulties he encountered on the "sillyness of using all de bruijn indices instead of a &lt;a href="http://www.cis.upenn.edu/~baydemir/papers/lngen/"&gt;locally nameless encoding&lt;/a&gt;," which was a response that I initially found puzzling. I've since decided that my puzzlement was the result of the fact that he was thinking of the specific thing he was doing in terms of programming languages, and I was thinking about the thing I was doing (constructive provability logic) in terms of logic - my guess is that we're both so used to working on both sides of the Curry-Howard correspondence that it wouldn't have occurred to us that this might make a difference!&lt;br /&gt;&lt;br /&gt;From a programming languages perspective, we have programs and typing derivations that show programs to be well typed; the locally nameless encoding gives you the ability to apply the exchange or weakening lemma and get a &lt;i&gt;new typing derivation&lt;/i&gt; that says that the &lt;i&gt;same term is still well typed&lt;/i&gt;. That wasn't the case for our original "Church-style" lambda calculus terms. In my current view, that's because &lt;b&gt;&lt;i&gt;a "Church-style" lambda calculus term is more like the typing derivation than it is like a term&lt;/i&gt;&lt;/b&gt;. It's a typing derivation without the term it's typing; in other words, it's a proof in natural deduction form! And what Bernardo and I was using was something that, for our purposes, was just as good as a derivation that the same term was well typed in the exchanged context - we got that the same &lt;i&gt;metric&lt;/i&gt; was associated with the exchanged &lt;i&gt;proof term&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;In other words, it seems that, for the purposes of termination arguments, the metric serves the same purpose a locally nameless proof term does. Certainly it avoids the "silliness of using all de Bruijn indices," as it uses none whatsoever, hence the mostly-joking title of this post. However, it's quite possible I'm off base; I'd be interested in what people more versed in locally nameless representation thought. I should add that I certainly think it is possible to do an intrinsically typed locally nameless representation; you'd just have to have (at minimum) the free variables be aware of their type. If you were interested primarily in representing a programming language that might even be the right thing to do; but the totally nameless metrics seem to be an easier fit for developments where the primary interest is in the logic side of the correspondence.&lt;br /&gt;&lt;br /&gt;&lt;a name="shamelessplug"&gt;*&lt;/a&gt; Shameless plug for my advisor Frank Pfenning's excellent essay, "&lt;a href="http://www.cs.cmu.edu/~fp/papers/andrews08.pdf"&gt;Church and Curry, Combining Intrinsic and Extrinsic Typing&lt;/a&gt;" which talks about properties of Church-style versus Curry-style encodings and relates them to subtyping and work by William Lovas.&lt;br /&gt;&lt;br /&gt;P.S. This blog post has been about Agda; the first time I used this kind of tree structural metric on terms was in Twelf, when (on a challenge from John Boyland) I showed a &lt;a href="http://twelf.plparty.org/wiki/Concrete_representation"&gt;bijection between HOAS and de Bruijn form representations&lt;/a&gt; of the terms of an untyped (or, if you prefer, "Curry-style") lambda calculus terms.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/827419514217130218-6421868563013322419?l=requestforlogic.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/RequestForLogic/~4/CCi-IQc2uec" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://requestforlogic.blogspot.com/feeds/6421868563013322419/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://requestforlogic.blogspot.com/2010/11/totally-nameless-representation.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/6421868563013322419?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/827419514217130218/posts/default/6421868563013322419?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/RequestForLogic/~3/CCi-IQc2uec/totally-nameless-representation.html" title="Totally nameless representation" /><author><name>Rob</name><uri>http://www.blogger.com/profile/05106663398227635415</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><feedburner:origLink>http://requestforlogic.blogspot.com/2010/11/totally-nameless-representation.html</feedburner:origLink></entry></feed>

