<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-24975746</id><updated>2010-03-13T16:32:26.341+01:00</updated><title type='text'>Everything Scheme</title><subtitle type='html'>- a blog on all things Scheme</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.scheme.dk/blog/atom.xml'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>41</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-24975746.post-2742353879062649585</id><published>2009-06-15T21:23:00.004+02:00</published><updated>2009-06-15T21:31:14.987+02:00</updated><title type='text'>Planet Scheme Upgrade - Please check that your blog still works on Planet Scheme</title><content type='html'>&lt;div&gt;Dear Planet Scheme Bloggers,&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The software behind Planet Scheme has gotten a long due upgrade. &lt;/div&gt;&lt;div&gt;After writing your next blog entry, please make sure your blog entry&lt;/div&gt;&lt;div&gt;arrives correctly at the front page of Planet Scheme. (Planet Scheme&lt;/div&gt;&lt;div&gt;updates every 3 hours, so be patient).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Details: Before Planet Scheme used Planet Planet (but despite the &lt;/div&gt;&lt;div&gt;text on its web site, it is no longer maintained). The replacement&lt;/div&gt;&lt;div&gt;software is Planet Venus - which understood the old configuration&lt;/div&gt;&lt;div&gt;and template files with no (known) problems.&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-2742353879062649585?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/2742353879062649585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=2742353879062649585' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/2742353879062649585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/2742353879062649585'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2009/06/planet-scheme-upgrade-please-check-that.html' title='Planet Scheme Upgrade - Please check that your blog still works on Planet Scheme'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-8289643036183093139</id><published>2008-11-17T19:23:00.003+01:00</published><updated>2008-11-17T19:35:04.357+01:00</updated><title type='text'>Solving a Museum of the evening, I coffee.</title><content type='html'>Scheme is thriving in Japan. As proof I offer a link to a Japanese version of Planet Scheme, namely &lt;a href="http://scheme-users.jp/planet/"&gt;Planet Scheme Japan&lt;/a&gt; . I couldn't resist reading the site with a little help from Google Translate, and the &lt;a href="http://translate.google.com/translate?u=http%3A%2F%2Fscheme-users.jp%2Fplanet%2F&amp;amp;hl=en&amp;amp;ie=UTF-8&amp;amp;sl=ja&amp;amp;tl=en"&gt;translation&lt;/a&gt; is at times quite amusing. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hopefully one of Planet Scheme's Japanese readers can help us get with the real translation of: "Solving a Museum of the evening, I coffee."  (Search for "571" in order to find the post on the Japanese site).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-8289643036183093139?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://scheme-users.jp/planet/' title='Solving a Museum of the evening, I coffee.'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/8289643036183093139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=8289643036183093139' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/8289643036183093139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/8289643036183093139'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2008/11/solving-museum-of-evening-i-coffee.html' title='Solving a Museum of the evening, I coffee.'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-4984593225781160846</id><published>2008-07-30T12:49:00.002+02:00</published><updated>2008-07-30T12:53:55.143+02:00</updated><title type='text'>Never turn your back on an unused email-account.</title><content type='html'>&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Never turn your back on an unused email-account.&lt;/span&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div&gt;The past month no new blog entries appeared at Planet Scheme. At first I thought the summer was to blame on the lack of blog activity. Today I found out that the web server had run out of disk space. An out of use email-account had received unmentionable amounts of spam. Sigh.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Bloggers: If you discover that your posts are missing on Planet Scheme, please give me a hint by email or by posting a note here.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And now I am off to figure out to impose a limit on mail accounts...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-4984593225781160846?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/4984593225781160846/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=4984593225781160846' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/4984593225781160846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/4984593225781160846'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2008/07/never-turn-your-back-on-unused-email.html' title='Never turn your back on an unused email-account.'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-7335077469335642810</id><published>2007-12-01T20:35:00.000+01:00</published><updated>2007-12-02T01:33:47.038+01:00</updated><title type='text'>Ikarus - The new Scheme on the Block</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;A new Scheme on the Block&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Congratulations to Abdulaziz Ghuloum with the release of his new Scheme compiler &lt;a href="http://www.cs.indiana.edu/%7Eaghuloum/ikarus/"&gt;Ikarus&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Getting traction for a new Scheme implementation have never been easy due to the astonishingly number of existing &lt;span style="font-style: italic;"&gt;quality&lt;/span&gt; implementations. It would however be surprised not to see Ikarus become one of the usual suspects. The reason for this is not the rather large number of features Ikarus has for a first release, but rather that all the hard parts of a quality implementation already are present.&lt;br /&gt;&lt;br /&gt;The work on the compiler has already produced three papers. The first "&lt;a href="http://scheme2006.cs.uchicago.edu/11-ghuloum.pdf"&gt;An     Incremental Approach to Compiler Construction&lt;/a&gt;" describes in 24 small steps how to implement a compiler capable of running environment-passing interpreter for core Scheme. The idea is to a fully working compiler before and after each step. This implies that the one must write the backend first. At this years ICFP in Freiburg Aziz told me, that Ikarus in fact grew in this way.&lt;br /&gt;&lt;br /&gt;The second is "Implicit phasing for R6RS libraries" by Abdulaziz Ghuloum, and R. Kent Dybvig  describe the design and implementation of "&lt;a href="https://launchpad.net/r6rs-libraries"&gt;The portable R6RS library and syntax-case system&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;The third "Generation-Friendly Eq Hash Tables" also by Ghuloum and Dybvig describe an implemention of eq hash tables were only objects that actually move during a collection is rehashed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Native Compilation&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;Ikarus is a native compiler, which means that it compiles directly to x86 machine code, more specifially the resulting code runs on Intel compatible processors supporting SSE2 extentions. In order words it will run on any reasonable new computer.&lt;br /&gt;&lt;br /&gt;The native compilation niche Ikarus joins, includes Chez Scheme, Larceny, and MIT/GNU Scheme.&lt;br /&gt;&lt;br /&gt;The drawback of native compilation have so far been that more than one backend were needed to support both PCs and Macs. After Apple switched to Intel processors that problem (for the time being at least) has gone. Ikarus supports the big three: Windows, OS X, and Linux.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Incremental Compilation&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Ikarus is an &lt;span style="font-style: italic;"&gt;incremental&lt;/span&gt; compiler. This means that programs at runtime can use the compiler to compile (an link and run)  programs "on-the-fly" without using any external tools. I'll leave it to the curious, to find the intel assembler in the Ikarus source.&lt;br /&gt;&lt;br /&gt;A pleasant side-effect of  using an incremental compiler is that  &lt;span style="font-family:courier new;"&gt;eval&lt;/span&gt; can use  the compiler, which means that there are good chances that &lt;span style="font-family:courier new;"&gt;eval&lt;/span&gt; will be both efficient and give results consistent with normal compilation. For non-incremental compilers such as the compile-to-C variety, &lt;span style="font-family:courier new;"&gt;eval&lt;/span&gt; is often implementation via a compile-to-closures approach, which introduces an extra source of bugs.&lt;br /&gt;&lt;br /&gt;Not that I ever use &lt;span style="font-family:courier new;"&gt;eval&lt;/span&gt;...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Optimizing Compiler&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;div&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;span class="Apple-style-span" style="border-collapse: separate; border-spacing: 0px; color: rgb(0, 0, 0); font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; text-indent: 0px; text-transform: none; orphans: 2; white-space: normal; widows: 2; word-spacing: 0px;font-family:Helvetica;font-size:12;"  &gt;&lt;div&gt;... there is a fine line between “optimization” and “not being stupid.”&lt;br /&gt;-- R. Kent Dybvig&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;So what exactly does it mean that Ikarus is an optimizing compiler?&lt;br /&gt;&lt;br /&gt;For one it means that the code produced in value-, boolean- and effect-contexts are different. See the paper &lt;a href="http://citeseer.ist.psu.edu/dybvig90destinationdriven.html"&gt;"Destination-Driven Code Generation"&lt;/a&gt; by &lt;span class="m"&gt;&lt;span class="l"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;R. Kent Dybvig, Robert Hieb, Tom Butler.&lt;br /&gt;&lt;br /&gt;Machine registers are used to hold function call arguments and local variables. Mapping variables to machine registers in a optimal way is unfortunately a NP-hard problem, but nevertheless efficient algorithms exists that work well in practise. Ikarus uses a version of Chaitin's graph-coloring algorithm.&lt;br /&gt;&lt;br /&gt;Needless to say, Ikarus also does constant folding.&lt;br /&gt;&lt;br /&gt;As far as I can tell, control flow analysis based optimizations are yet to come.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Modern generational garbage collector&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The generational garbage collector was inspired by the paper: &lt;a href="http://citeseer.ist.psu.edu/5693.html"&gt;Don't Stop the BIBOP: Flexible and Efficient Storage Management for Dynamically-Typed Languages&lt;/a&gt; by R. Kent Dybvig, David Eby, and Carl Bruggeman.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;R6RS Compliance&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The immediate goal for Ikarus to become 100% R6RS compliant. Rapid progress is made to achieve this goal, and as far I can tell, there no potential show-stoppers ahead - it is "just" a matter of implementing "more of the same".&lt;br /&gt;&lt;br /&gt;Opinions of R6RS are many, but R6RS compliance means at least two things: a decent module system and documentation for free.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-7335077469335642810?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cs.indiana.edu/~aghuloum/ikarus/' title='Ikarus - The new Scheme on the Block'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/7335077469335642810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=7335077469335642810' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/7335077469335642810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/7335077469335642810'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/12/ikarus-new-scheme-on-block.html' title='Ikarus - The new Scheme on the Block'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-6996146453603665430</id><published>2007-08-15T23:51:00.000+02:00</published><updated>2007-08-16T23:21:40.803+02:00</updated><title type='text'>An Introduction to Web Development with PLT Scheme - The Control</title><content type='html'>&lt;h2&gt;Resume&lt;/h2&gt;This is the fourth post in a series of posts on programming web&lt;br /&gt;&lt;p&gt;applications with PLT Scheme. In part one and two the model and view of a small Reddit-like application were discussed. Part three were about the basic operation of the PLT Scheme web-server. Here in part four we will finish the discussion of the controller. Finally I'll explain how to get this code from PLaneT, so you can run it on your own machine.&lt;br /&gt;&lt;br /&gt;Don't forget to leave a comment, if you have questions or suggestions.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;The Controller&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;The controller handles user interactions. The concrete actions in our application are:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt; Viewing the front-page&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Up- and down-voting a link&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Viewing the page for submitting new links&lt;br /&gt;&lt;/li&gt;&lt;li&gt; Submitting a new link&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For each action, we'll have a function that invokes the appropriate function in the model, receives data back, and then let the view generate a web-page based on the data. The function handling the viewing of the front-page is simply:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;do-front-page&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;html-front-page&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; (&lt;span class="variable"&gt;page&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The function page is from the model and html-front-page in the view (see earlier posts).&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Implementing the controller&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;An user interaction is sent to the web-server in the form of a request. Given a request, the web-server determines which servlet is to handle the request, and then calls the servlet's start function. &lt;/p&gt;&lt;p&gt;Here we have a choice. Even though the controller conceptually is one entity, a common way to implement controllers is to have separate servlets for each action. In this tutorial however I'll implement the controller as a single servlet, and let it dispatch on the action. The url for the servlet will be:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt; http://localhost/servlets/control.scm&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;The action will be given as a parameter. One way to send the parameter is to include it as part of the link:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt; http://localhost/servlets/control.scm?action=submitnew&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Another is to let action be a hidden field in a form.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;The Start Function&lt;/h2&gt;&lt;p&gt;After the receipt of a request the web-server starts the control-servlet by calling the start function with the request in&lt;br /&gt;question. The web-framework provides us with a special form servlet, that allows us to to define the start function simply as: &lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"web.scm"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"web.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;start&lt;/span&gt;&lt;br /&gt; (&lt;span class="variable"&gt;servlet&lt;/span&gt;&lt;br /&gt;   (&lt;span class="variable"&gt;dispatch-on-action&lt;/span&gt;)))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here the servlet form evaluates to a function that&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt; receives a request&lt;br /&gt;&lt;/li&gt;&lt;li&gt; stores the information in the request in various parameters&lt;br /&gt;&lt;/li&gt;&lt;li&gt; evaluates its bodies, the result of the last body must be an x-expr&lt;br /&gt;&lt;/li&gt;&lt;li&gt; construct a response based upon the x-expr and the contents of the various response parameters&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;During development it is mighty convenient to see any errors directly&lt;br /&gt;in the browser. Therefore, let's introduce the form, &lt;span style="font-family:courier new;"&gt;with-errors-to-browser&lt;/span&gt;:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;start&lt;/span&gt;&lt;br /&gt; (&lt;span class="variable"&gt;servlet&lt;/span&gt;&lt;br /&gt;   (&lt;span class="variable"&gt;with-errors-to-browser&lt;/span&gt;&lt;br /&gt;     &lt;span class="variable"&gt;send/finish&lt;/span&gt;&lt;br /&gt;     &lt;span class="variable"&gt;dispatch-on-action&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Dispatching on actions&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;Any parameters sent as part of the request, are saved as bindings in current-bindings by the servlet-form in start. The dispatch code is therefore very simple:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;dispatch-on-action&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;with-binding&lt;/span&gt; (&lt;span class="variable"&gt;current-bindings&lt;/span&gt;) (&lt;span class="variable"&gt;action&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="variable"&gt;match&lt;/span&gt; &lt;span class="variable"&gt;action&lt;/span&gt;&lt;br /&gt;     [&lt;span class="selfeval"&gt;"updown"&lt;/span&gt;     (&lt;span class="variable"&gt;do-updown&lt;/span&gt;)]&lt;br /&gt;     [&lt;span class="selfeval"&gt;"submitnew"&lt;/span&gt;  (&lt;span class="variable"&gt;do-submit-new&lt;/span&gt;)]&lt;br /&gt;     [&lt;span class="selfeval"&gt;"submit"&lt;/span&gt;     (&lt;span class="variable"&gt;do-submit&lt;/span&gt;)]&lt;br /&gt;     [&lt;span class="variable"&gt;else&lt;/span&gt;         (&lt;span class="variable"&gt;do-front-page&lt;/span&gt;)])))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the action is missing, the front page is shown.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Submital of new links&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;The action "submitnew" simply shows a page with a form, where a new url and title can be entered:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;do-submit-new&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;html-submit-new-page&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hitting "submit" will POST the data to our servlet, and the action will be "submit". The controller must send the data to the model in order to add the new link. The user should return to the frontpage. One way to achieve this is as follows:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;do-submit&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;with-binding&lt;/span&gt; (&lt;span class="variable"&gt;current-bindings&lt;/span&gt;) (&lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;and&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="selfeval"&gt;10&lt;/span&gt;)))&lt;br /&gt; (&lt;span class="variable"&gt;do-front-page&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Can you spot a problem?&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;The problem and its solution&lt;/h2&gt;&lt;p&gt;What happens if the user hits the refresh button in their browser? The same data will be posted again. This is often referred to as the "Double Submit problem". The solution is to redirect the browser to the frontpage. If the user now hits refresh, then they'll just get the frontpage again.&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;do-submit&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;with-binding&lt;/span&gt; (&lt;span class="variable"&gt;current-bindings&lt;/span&gt;) (&lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;when&lt;/span&gt; (&lt;span class="keyword"&gt;and&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="selfeval"&gt;10&lt;/span&gt;)))&lt;br /&gt; &lt;span class="comment"&gt;; to make sure a reload doesn't resubmit, we redirect to the front page&lt;br /&gt;&lt;/span&gt;    (&lt;span class="variable"&gt;current-redirect-temporarily&lt;/span&gt; &lt;span class="selfeval"&gt;"http://localhost/servlets/control.scm"&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;html-redirect-page&lt;/span&gt; &lt;span class="selfeval"&gt;"Redirecting to frontpage"&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The redirection is put in place, by setting the parameter current-redirect-temporarily. When the servlet form constructs the reponse it checks whether any redirection parameters are set, if not it produces a normal "200 OK" response; however, if set, it produces a redirection response; e.g., in the case of current-redirect-temporarily, a "302 Found".&lt;/p&gt;&lt;p&gt;Note: You can also use current-redirect-see-other to get a "303 See Other" response.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Note: See&lt;br /&gt;&lt;a href="http://www.theserverside.com/tt/articles/article.tss?l=RedirectAfterPost"&gt;Redirect after Post&lt;/a&gt; by Michael Jouravlev for a thorough discussion of the POST-Redirect-GET technique.&lt;br /&gt;&lt;/p&gt;&lt;h2&gt;Up- and Down-voting&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;The up- and down-arrows could be simple links, but if they were we would run into a similar problem with refresh. We therefore turn each link into a form, and handle its submital with the POST-Redirect-GET technique as before. The only complication is that big submital buttons aren't pretty; images of arrows are much prettier. This is solved with a little JavaScript (see the post on the view).&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;do-updown&lt;/span&gt;)&lt;br /&gt; &lt;span class="comment"&gt;; an arrow was clicked&lt;br /&gt;&lt;/span&gt;    (&lt;span class="variable"&gt;with-binding&lt;/span&gt; (&lt;span class="variable"&gt;current-bindings&lt;/span&gt;) (&lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="variable"&gt;arrowitem&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="variable"&gt;match&lt;/span&gt; &lt;span class="variable"&gt;arrowitem&lt;/span&gt;&lt;br /&gt;     [&lt;span class="selfeval"&gt;"down"&lt;/span&gt; (&lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt;&lt;br /&gt;               (&lt;span class="variable"&gt;decrease-score&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt;))]&lt;br /&gt;     [&lt;span class="selfeval"&gt;"up"&lt;/span&gt;   (&lt;span class="keyword"&gt;when&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt;&lt;br /&gt;               (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt;))]&lt;br /&gt;     [&lt;span class="variable"&gt;else&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;do-nothing&lt;/span&gt;]))&lt;br /&gt; &lt;span class="comment"&gt;; to make sure a reload doesn't resubmit, we redirect to the front page&lt;br /&gt;&lt;/span&gt;    (&lt;span class="variable"&gt;current-redirect-temporarily&lt;/span&gt; (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"http://localhost:~a/servlets/control.scm"&lt;/span&gt; &lt;span class="variable"&gt;port&lt;/span&gt;))&lt;br /&gt; (&lt;span class="variable"&gt;html-redirect-page&lt;/span&gt; &lt;span class="selfeval"&gt;"Redirecting to frontpage"&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Downloading the code&lt;br /&gt;&lt;/h2&gt;&lt;p&gt;To download the code and try it, open DrScheme and enter the following in the interaction window:&lt;br /&gt;&lt;/p&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"install.scm"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"listit.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then call install to copy the web-site to a&lt;br /&gt;folder of your choice:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt; &gt; (install "c:/tmp/my-listit")&lt;br /&gt;Copying the web-site to c:/tmp/my-listit .&lt;br /&gt;Please wait...&lt;br /&gt;The web-site has now been copied to c:/tmp/my-listit .&lt;br /&gt;To test it, open "launch.scm" in DrScheme and run it.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Have fun!&lt;br /&gt;&lt;br /&gt;Leave a comment, if you have questions or suggestions.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-6996146453603665430?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/6996146453603665430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=6996146453603665430' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/6996146453603665430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/6996146453603665430'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/08/introduction-to-web-development-with.html' title='An Introduction to Web Development with PLT Scheme - The Control'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-2744801486763104598</id><published>2007-08-05T23:27:00.000+02:00</published><updated>2007-08-05T23:55:02.524+02:00</updated><title type='text'>Number Theory</title><content type='html'>Today I released a &lt;a href="http://planet.plt-scheme.org/display.ss?package=math.plt&amp;owner=soegaard"&gt;collection of number theory&lt;/a&gt; functions through PLaneT.&lt;br /&gt;&lt;br /&gt;The code began as an experiment. I grabbed a book on number theory from the shelve (&lt;a href="http://www.amazon.com/Elementary-Number-Theory-Gareth-Jones/dp/3540761977"&gt;"Elementary Number Theory"&lt;/a&gt; by Gareth A. Jones and J. Mary Jones) and began illustrating each definition and each theorem with Scheme code. The first half of the &lt;a href="http://planet.plt-scheme.org/package-source/soegaard/math.plt/1/0/number-theory.ss"&gt;source code&lt;/a&gt; is thus a well commented mix of definitions, theorems and code.&lt;br /&gt;&lt;br /&gt;The second half contains more sophisticated algorithms mostly from the excellent book &lt;a href="http://www-math.uni-paderborn.de/mca/"&gt;"Modern Computer Algebra"&lt;/a&gt; by  Joachim von zur Gathen and Jürgen Gerhard. The algorithms for factorizing large integers come from this book.&lt;br /&gt;&lt;br /&gt;Finally there are some definitions of special functions, mostly inspired by the problems of the &lt;a href="http://projecteuler.net/"&gt;Euler Project&lt;/a&gt;. The revival of the code is due to the Euler Project, which is a collection of small problems of very varying difficulty. The tools I have used to solve the problems (apart from the number theory library) are &lt;a href="http://www.ccs.neu.edu/home/dherman/"&gt;David Herman&lt;/a&gt;'s &lt;a href="http://planet.plt-scheme.org/display.ss?package=memoize.plt&amp;amp;owner=dherman"&gt;memoize&lt;/a&gt; package (don't forget to use &lt;span style="font-family:courier new;"&gt;memoize*&lt;/span&gt; when working with numbers) and the eager comprehensions from &lt;a href="http://scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts.html"&gt;srfi 42&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://planet.plt-scheme.org/package-source/soegaard/math.plt/1/0/doc.txt"&gt;documentation&lt;/a&gt; of the number theory library lists all the available functions.&lt;br /&gt;&lt;br /&gt;Please write with bugs, suggestions, and improvements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-2744801486763104598?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://planet.plt-scheme.org/display.ss?package=math.plt&amp;owner=soegaard' title='Number Theory'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/2744801486763104598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=2744801486763104598' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/2744801486763104598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/2744801486763104598'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/08/number-theory.html' title='Number Theory'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-599151801877225771</id><published>2007-05-02T00:09:00.000+02:00</published><updated>2007-05-13T12:45:53.134+02:00</updated><title type='text'>Know your implementation</title><content type='html'>How well do you know your language implementation? Below you'll see four different implementations of the same function.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;    Can you &lt;span style="font-style: italic;"&gt;predict&lt;/span&gt; which version is fastest?&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Too easy? Well, then try not only to pick the fastest, but also to rank them according to speed.&lt;br /&gt;&lt;br /&gt;You are welcome to leave a comment, if you try the snippets.&lt;br /&gt;&lt;br /&gt;The task is simple: we want to append two linked lists. That is, we'll reimplement the builtin function append, although we'll restrict our-selves to two arguments. The four versions are of course not allowed to use the builtin &lt;span style="font-family:courier new;"&gt;append&lt;/span&gt;.&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;First version: Building the list in reverse&lt;/span&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append1&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;append-rev&lt;/span&gt; (&lt;span class="builtin"&gt;reverse&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append-rev&lt;/span&gt; &lt;span class="variable"&gt;rev-xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;    [(&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;rev-xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;]&lt;br /&gt;    [&lt;span class="variable"&gt;else&lt;/span&gt;           (&lt;span class="variable"&gt;append-rev&lt;/span&gt; (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;rev-xs&lt;/span&gt;) &lt;br /&gt;                                (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;car&lt;/span&gt; &lt;span class="variable"&gt;rev-xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;))]))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Second version: Naïve recursion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A naïve, non-tail-recursive solution.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append2&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;    [(&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;]&lt;br /&gt;    [&lt;span class="variable"&gt;else&lt;/span&gt; (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;result&lt;/span&gt; (&lt;span class="variable"&gt;append2&lt;/span&gt; (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;)])&lt;br /&gt;            (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;car&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;result&lt;/span&gt;))]))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Third version: Continuation passing style&lt;/span&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append3&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append3-k&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;      [(&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) (&lt;span class="variable"&gt;k&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)]&lt;br /&gt;      [&lt;span class="variable"&gt;else&lt;/span&gt; (&lt;span class="variable"&gt;append3-k&lt;/span&gt; (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;ys&lt;/span&gt;&lt;br /&gt;                       (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;tail&lt;/span&gt;) (&lt;span class="variable"&gt;k&lt;/span&gt; (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;car&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="variable"&gt;tail&lt;/span&gt;))))]))&lt;br /&gt;  (&lt;span class="variable"&gt;append3-k&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt; (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;x&lt;/span&gt;) &lt;span class="variable"&gt;x&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;&lt;br /&gt;Using side-effects&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's avoid any unnecessary consing.&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;for-each-reverse!&lt;/span&gt; &lt;span class="variable"&gt;f&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;  [(&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;done&lt;/span&gt;]&lt;br /&gt;  [&lt;span class="variable"&gt;else&lt;/span&gt; (&lt;span class="variable"&gt;for-each-reverse!&lt;/span&gt; &lt;span class="variable"&gt;f&lt;/span&gt; (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;))&lt;br /&gt;        (&lt;span class="variable"&gt;f&lt;/span&gt; (&lt;span class="builtin"&gt;car&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;))]))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;append4&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;result&lt;/span&gt; &lt;span class="variable"&gt;ys&lt;/span&gt;])&lt;br /&gt;  (&lt;span class="variable"&gt;for-each-reverse!&lt;/span&gt;&lt;br /&gt;    (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;x&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;set!&lt;/span&gt; &lt;span class="variable"&gt;result&lt;/span&gt; (&lt;span class="builtin"&gt;cons&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="variable"&gt;result&lt;/span&gt;)))&lt;br /&gt;      &lt;span class="variable"&gt;xs&lt;/span&gt;)&lt;br /&gt;  &lt;span class="variable"&gt;result&lt;/span&gt;))&lt;/pre&gt;&lt;/div&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Benchmarking&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And now for the bencmarking. Before each timing,  I invoke the garbage collector. In this way garbage produced by test one, doesn't affect the timings of test two.&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;xs&lt;/span&gt; (&lt;span class="builtin"&gt;vector-&amp;gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;make-vector&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;))])&lt;br /&gt;   (&lt;span class="builtin"&gt;collect-garbage&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;begin&lt;/span&gt; (&lt;span class="variable"&gt;append1&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;done&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="builtin"&gt;collect-garbage&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;begin&lt;/span&gt; (&lt;span class="variable"&gt;append2&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;done&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="builtin"&gt;collect-garbage&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;begin&lt;/span&gt; (&lt;span class="variable"&gt;append3&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;done&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="builtin"&gt;collect-garbage&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;time&lt;/span&gt; (&lt;span class="keyword"&gt;begin&lt;/span&gt; (&lt;span class="variable"&gt;append4&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;done&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;100&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;1000&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;10000&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;100000&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;1000000&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;test&lt;/span&gt; &lt;span class="selfeval"&gt;2000000&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-599151801877225771?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/599151801877225771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=599151801877225771' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/599151801877225771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/599151801877225771'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/05/know-your-implementation.html' title='Know your implementation'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-7544711823329293070</id><published>2007-04-29T17:26:00.000+02:00</published><updated>2007-05-07T15:30:39.128+02:00</updated><title type='text'>Writing a Spelling Corrector in PLT Scheme</title><content type='html'>[Remember to leave a comment: Was this post silly? Enlightning? Old news?]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Peter Norvig recently wrote a great piece on &lt;a href="http://www.norvig.com/spell-correct.html"&gt;How to Write a Spelling Corrector&lt;/a&gt;. Since Norvig used Python, &lt;a href="http://practical-scheme.net/wiliki/wiliki.cgi?Shiro&amp;l=en"&gt;Shiro&lt;/a&gt; decided to write a &lt;a href="http://practical-scheme.net/wiliki/wiliki.cgi?Gauche%3aSpellingCorrection&amp;l=en"&gt;version&lt;/a&gt; in &lt;a href="http://www.shiro.dreamhost.com/scheme/gauche/"&gt;Gauche&lt;/a&gt; Scheme. In the following I'll present a solution in PLT Scheme. But first let's look at string manipulations.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;String Manipulations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Scheme offers the usual operations on strings: string concatenation (string-append), referencing a character in a string (string-ref), extracting a substring (substring) and converting characters to strings (string). Compared to other languages code for string manipulations tend to become verbose, unless one "cheats" and uses some sort of utility such as format. [The advantage of this verboseness is that Scheme compilers can generate efficient code.]&lt;br /&gt;&lt;br /&gt;As an example consider this expression from Norvig's spelling corrector:&lt;br /&gt;&lt;pre  class="prettyprint" style="font-family:courier new;"&gt;&lt;span class="pun"&gt;  [&lt;/span&gt;&lt;span class="pln"&gt;word&lt;/span&gt;&lt;span class="pun"&gt;[&lt;/span&gt;&lt;span class="lit"&gt;0&lt;/span&gt;&lt;span class="pun"&gt;:&lt;/span&gt;&lt;span class="pln"&gt;i&lt;/span&gt;&lt;span class="pun"&gt;]+&lt;/span&gt;&lt;span class="pln"&gt;c&lt;/span&gt;&lt;span class="pun"&gt;+&lt;/span&gt;&lt;span class="pln"&gt;word&lt;/span&gt;&lt;span class="pun"&gt;[&lt;/span&gt;&lt;span class="pln"&gt;i&lt;/span&gt;&lt;span class="pun"&gt;:]&lt;/span&gt;&lt;/pre&gt;Here word[0:i] is the substring from index 0 (inclusive) to index i (exclusive).&lt;br /&gt;The c is a character, and word[i:] is the substring from index i to the end.&lt;br /&gt;The concatenation operator + converts automatically the character c to a string before the strings are concatenated.&lt;br /&gt;&lt;br /&gt;A literal translation to Scheme reads as follows:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; (&lt;span class="builtin"&gt;string-append&lt;/span&gt; (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;) (&lt;span class="builtin"&gt;string&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt;) (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Ouch!&lt;br /&gt;&lt;br /&gt;A utility is clearly needed. Below follows my shot at one such utility, namely, concat. It allows us to write the expression as:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;  &lt;span class="variable"&gt;c&lt;/span&gt;  &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;A string followed by two numbers is a substring, so   word 0 i   is short for (substring word 0 i). An underscore is allowed instead of a number either to indicate the beginning or the end. Thus word i _ is short for (substring word i (string-length word)). Finally a character is automatically converted to a string, so c is short for (string c). Not used in the example, but useful in general: A string followed by a single number, like word i, is short for (string-ref word i).&lt;br /&gt;&lt;br /&gt;The code for concat is found at the bottom of this post.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Spelling Corrector&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are two parts of the spelling corrector. The first part reads in correctly spelled words from a corpus, and counts the number of occurences of each word. The second part uses the training data to check whether a given word is known, or if it is incorrectly spelled to find the intended word.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reading words from a file&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We can split a string in words with the help of regexp-split.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; &lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;regexp-split&lt;/span&gt; &lt;span class="selfeval"&gt;#rx&lt;/span&gt;&lt;span class="selfeval"&gt;"[^a-zA-Z]"&lt;/span&gt; &lt;span class="selfeval"&gt;"foo bar baz"&lt;/span&gt;)&lt;br /&gt; (&lt;span class="selfeval"&gt;"foo"&lt;/span&gt; &lt;span class="selfeval"&gt;"bar"&lt;/span&gt; &lt;span class="selfeval"&gt;"baz"&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Taking advantage of the fact that PLT Scheme's regular  expression functions work both on strings as well as directly on input ports, we can call regexp-split directly on the port.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; words : port -&amp;gt; list-of-strings&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;words&lt;/span&gt; &lt;span class="variable"&gt;text&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;list-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="variable"&gt;regexp-split&lt;/span&gt; &lt;span class="selfeval"&gt;#rx&lt;/span&gt;&lt;span class="selfeval"&gt;"[^a-zA-Z]"&lt;/span&gt; &lt;span class="variable"&gt;text&lt;/span&gt;))&lt;br /&gt;              (&lt;span class="builtin"&gt;string-downcase&lt;/span&gt; (&lt;span class="builtin"&gt;bytes-&amp;gt;string/latin-1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Counting words&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now we'll count how many times each word is seen. We'll use a hash table to hold words and counts.&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; train : list-of-strings -&amp;gt; hash-table-from-strings-to-numbers&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;train&lt;/span&gt; &lt;span class="variable"&gt;features&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;model&lt;/span&gt; (&lt;span class="builtin"&gt;make-hash-table&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;equal&lt;/span&gt;)])&lt;br /&gt;   (&lt;span class="variable"&gt;do-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;features&lt;/span&gt;)&lt;br /&gt;          (&lt;span class="builtin"&gt;hash-table-put!&lt;/span&gt; &lt;span class="variable"&gt;model&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;add1&lt;/span&gt; (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;model&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))))&lt;br /&gt;   &lt;span class="variable"&gt;model&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Let's read in the data from the small corpus, and at the same time define word-count that returns the count of a word, and known? that checks whether a word was seen in the training set.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; (&lt;span class="variable"&gt;train&lt;/span&gt; (&lt;span class="variable"&gt;words&lt;/span&gt; (&lt;span class="builtin"&gt;open-input-file&lt;/span&gt; &lt;span class="selfeval"&gt;"small.txt"&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;word-count&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The set of strings with edit distance 1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;When a word is incorrectly spelled, we want to suggest a "similar" word known to be correctly spelled.&lt;br /&gt;&lt;br /&gt;Given a word w, the set of words with edit distance 1 consists of the words, we can generate from w by either deleting one character, or transposing to character, or altering one character, or inserting one character.&lt;br /&gt;&lt;br /&gt;Deleting the character with index i from a word is easy with the help of concat:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;   (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;If n is the length of w, then the set of strings generated by deleting a single character is given by:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Here (: i n) makes i run through the numbers 0, 1, ... n-1. For each i the string (concat word 0 i     word (+ i 1) _) is calculated, and all strings are collected in a set.&lt;br /&gt;&lt;br /&gt;All words with edit distance 1 is given by:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt; (&lt;span class="variable"&gt;string-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="selfeval"&gt;#\a&lt;/span&gt; &lt;span class="selfeval"&gt;#\z&lt;/span&gt;) &lt;span class="variable"&gt;c&lt;/span&gt;))&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt; (&lt;span class="variable"&gt;union*&lt;/span&gt;&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)                (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))          (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;)     &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;   &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt;) (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;  &lt;span class="variable"&gt;c&lt;/span&gt;  &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt;) (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;  &lt;span class="variable"&gt;c&lt;/span&gt;  &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;union*&lt;/span&gt; . &lt;span class="variable"&gt;sets&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;foldl&lt;/span&gt; &lt;span class="variable"&gt;union&lt;/span&gt; (&lt;span class="variable"&gt;empty&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;) &lt;span class="variable"&gt;sets&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The set of strings with edit distance 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Given a word w, the set of words with edit distance 2 is the set generated by 2 deletions, transponations, alterations, or insertions. Luckily we have done the hard work in edits1.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;&lt;br /&gt;         (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;         (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;)))&lt;br /&gt;         &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;There is just one catch. The set is awfully large, so instead, we'll concentrate on correctly spelled (known) words with a edit distance of two:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; known : set-of-strings -&amp;gt; set-of-strings&lt;br /&gt;&lt;/span&gt;&lt;span class="comment"&gt;;   remove the unknown words in words&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; &lt;span class="variable"&gt;words&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;&lt;br /&gt;         (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;w&lt;/span&gt; &lt;span class="variable"&gt;words&lt;/span&gt;) (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;w&lt;/span&gt;)) &lt;span class="variable"&gt;w&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known-edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;&lt;br /&gt;         (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt;         (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;))&lt;br /&gt;         (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;         &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Maximum&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;If we have more than one suggestion for an incorrectly spelled word, we want to find the most common of them - that is the one with the largest word count in the training set. Python's max has a nice feature, where given a list of xs, it finds the x that maximizes f(x), for a function f. Here is a Scheme version:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;maximum&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;key&lt;/span&gt;)&lt;br /&gt; &lt;span class="comment"&gt;; return the x with the largest key&lt;br /&gt;&lt;/span&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt; &lt;span class="selfeval"&gt;-inf.0&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;max-x&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;do-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;)&lt;br /&gt;        (&lt;span class="selfeval"&gt;:let&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt; (&lt;span class="variable"&gt;key&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;))&lt;br /&gt;        (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt;))&lt;br /&gt;        (&lt;span class="keyword"&gt;begin&lt;/span&gt;&lt;br /&gt;          (&lt;span class="keyword"&gt;set!&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt;)&lt;br /&gt;          (&lt;span class="keyword"&gt;set!&lt;/span&gt; &lt;span class="variable"&gt;max-x&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;)))&lt;br /&gt; &lt;span class="variable"&gt;max-x&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Correcting a word&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To correct a word, we first check whether it is known. We try to find a known word with edit distance 1. If unsuccessful we try to find one with edit distance 2.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;correct&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;falsify&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;empty?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) &lt;span class="selfeval"&gt;#f&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;))&lt;br /&gt; (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;candidates&lt;/span&gt;&lt;br /&gt;        (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; (&lt;span class="variable"&gt;set&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;            (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;            (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known-edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt;            (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))])&lt;br /&gt;   (&lt;span class="variable"&gt;maximum&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; &lt;span class="variable"&gt;candidates&lt;/span&gt;) &lt;span class="variable"&gt;word-count&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Let's try it:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; &lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;correct&lt;/span&gt; &lt;span class="selfeval"&gt;"hose"&lt;/span&gt;)&lt;br /&gt; &lt;span class="selfeval"&gt;"house"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Last Remarks&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Were it not for the concat macro, the function edits1 would have been clumsy. I am not sure concat is the answer. Thanks to macros, one can at least experiment with language extensions in Scheme.&lt;br /&gt;&lt;br /&gt;Remember to read Norvig's piece, where he explains the math behind.&lt;br /&gt;[Hmm. Should I turn it into a math exercise for my class?]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;Remember to leave a comment&lt;/span&gt;: Was this post silly? Enlightning? Old news?]&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;A Spelling Corrector in PLT Scheme&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;lib&lt;/span&gt; &lt;span class="selfeval"&gt;"42.ss"&lt;/span&gt; &lt;span class="selfeval"&gt;"srfi"&lt;/span&gt;)&lt;br /&gt;         (&lt;span class="variable"&gt;lib&lt;/span&gt; &lt;span class="selfeval"&gt;"67.ss"&lt;/span&gt; &lt;span class="selfeval"&gt;"srfi"&lt;/span&gt;)&lt;br /&gt;         (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"set.scm"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"galore.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; words : port -&amp;gt; list-of-strings&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;words&lt;/span&gt; &lt;span class="variable"&gt;text&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;list-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="variable"&gt;regexp-split&lt;/span&gt; &lt;span class="selfeval"&gt;#rx&lt;/span&gt;&lt;span class="selfeval"&gt;"[^a-zA-Z]"&lt;/span&gt; &lt;span class="variable"&gt;text&lt;/span&gt;))&lt;br /&gt;           (&lt;span class="builtin"&gt;string-downcase&lt;/span&gt; (&lt;span class="builtin"&gt;bytes-&amp;gt;string/latin-1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; train : list-of-strings -&amp;gt; hash-table-from-strings-to-numbers&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;train&lt;/span&gt; &lt;span class="variable"&gt;features&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;model&lt;/span&gt; (&lt;span class="builtin"&gt;make-hash-table&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;equal&lt;/span&gt;)])&lt;br /&gt;    (&lt;span class="variable"&gt;do-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;features&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="builtin"&gt;hash-table-put!&lt;/span&gt; &lt;span class="variable"&gt;model&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;add1&lt;/span&gt; (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;model&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))))&lt;br /&gt;    &lt;span class="variable"&gt;model&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;file&lt;/span&gt; &lt;span class="selfeval"&gt;"small.txt"&lt;/span&gt;)&lt;br /&gt;&lt;span class="comment"&gt;;(define file "big.txt")&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; (&lt;span class="variable"&gt;train&lt;/span&gt; (&lt;span class="variable"&gt;words&lt;/span&gt; (&lt;span class="builtin"&gt;open-input-file&lt;/span&gt; &lt;span class="variable"&gt;file&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;word-count&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="builtin"&gt;hash-table-get&lt;/span&gt; &lt;span class="variable"&gt;NWORDS&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; &lt;span class="variable"&gt;words&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;&lt;br /&gt;          (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;w&lt;/span&gt; &lt;span class="variable"&gt;words&lt;/span&gt;) (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;w&lt;/span&gt;)) &lt;span class="variable"&gt;w&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;concat-it&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;underscore?&lt;/span&gt; &lt;span class="variable"&gt;o&lt;/span&gt;) (&lt;span class="builtin"&gt;eq?&lt;/span&gt; &lt;span class="variable"&gt;o&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;  &lt;span class="comment"&gt;; spec :: = '()  | ( string num num  . spec ) | (string num _) | |&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="variable"&gt;match&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;&lt;br /&gt;      [() &lt;span class="keyword"&gt;'&lt;/span&gt;()]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;string?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;n1&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;n2&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt; &lt;span class="variable"&gt;n1&lt;/span&gt; &lt;span class="variable"&gt;n2&lt;/span&gt;) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;string?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;n1&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="variable"&gt;underscore?&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt; &lt;span class="variable"&gt;n1&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;)) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;string?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="variable"&gt;underscore?&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;n2&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;n2&lt;/span&gt;) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;string?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;string&lt;/span&gt; (&lt;span class="builtin"&gt;string-ref&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;symbol?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;char?&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;string&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt;) (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [((&lt;span class="variable"&gt;?&lt;/span&gt; &lt;span class="builtin"&gt;string?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) . &lt;span class="variable"&gt;spec&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="builtin"&gt;cons&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt; (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;))]&lt;br /&gt;      [&lt;span class="variable"&gt;else&lt;/span&gt; (&lt;span class="builtin"&gt;error&lt;/span&gt;)]))&lt;br /&gt;  (&lt;span class="builtin"&gt;apply&lt;/span&gt; &lt;span class="builtin"&gt;string-append&lt;/span&gt; (&lt;span class="variable"&gt;subs&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; (&lt;span class="variable"&gt;_&lt;/span&gt;)&lt;br /&gt;    [(&lt;span class="variable"&gt;string-it&lt;/span&gt; &lt;span class="variable"&gt;spec&lt;/span&gt; ...)&lt;br /&gt;     &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;concat-it&lt;/span&gt;&lt;br /&gt;        (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,@&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;so&lt;/span&gt;)&lt;br /&gt;                       (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;so&lt;/span&gt; (&lt;span class="variable"&gt;_&lt;/span&gt;)&lt;br /&gt;                         [&lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;_&lt;/span&gt;]&lt;br /&gt;                         [&lt;span class="variable"&gt;else&lt;/span&gt; &lt;span class="variable"&gt;so&lt;/span&gt;]))&lt;br /&gt;                     (&lt;span class="builtin"&gt;syntax-&amp;gt;list&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;spec&lt;/span&gt; ...)))))]))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;union*&lt;/span&gt; . &lt;span class="variable"&gt;sets&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;foldl&lt;/span&gt; &lt;span class="variable"&gt;union&lt;/span&gt; (&lt;span class="variable"&gt;empty&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;) &lt;span class="variable"&gt;sets&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt; (&lt;span class="variable"&gt;string-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="selfeval"&gt;#\a&lt;/span&gt; &lt;span class="selfeval"&gt;#\z&lt;/span&gt;) &lt;span class="variable"&gt;c&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="variable"&gt;union*&lt;/span&gt; &lt;br /&gt;   (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)                (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))          (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;     &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;)     &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;   &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt;) (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;  &lt;span class="variable"&gt;c&lt;/span&gt;  &lt;span class="variable"&gt;word&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) &lt;span class="variable"&gt;_&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt; &lt;span class="variable"&gt;alphabet&lt;/span&gt;) (&lt;span class="variable"&gt;concat&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;  &lt;span class="variable"&gt;c&lt;/span&gt;  &lt;span class="variable"&gt;word&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt; &lt;br /&gt;          (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;          (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;)))&lt;br /&gt;          &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;known-edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;set-ec&lt;/span&gt; &lt;span class="variable"&gt;string-compare&lt;/span&gt;&lt;br /&gt;          (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="selfeval"&gt;:set&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;known?&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;          &lt;span class="variable"&gt;e2&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;maximum&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt; &lt;span class="variable"&gt;key&lt;/span&gt;)&lt;br /&gt;  &lt;span class="comment"&gt;; return the x with the largest key&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt; &lt;span class="selfeval"&gt;-inf.0&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;max-x&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;do-ec&lt;/span&gt; (&lt;span class="selfeval"&gt;:&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="variable"&gt;xs&lt;/span&gt;)&lt;br /&gt;         (&lt;span class="selfeval"&gt;:let&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt; (&lt;span class="variable"&gt;key&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;))&lt;br /&gt;         (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt;))&lt;br /&gt;         (&lt;span class="keyword"&gt;begin&lt;/span&gt;&lt;br /&gt;           (&lt;span class="keyword"&gt;set!&lt;/span&gt; &lt;span class="variable"&gt;max-key&lt;/span&gt; &lt;span class="variable"&gt;k&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="keyword"&gt;set!&lt;/span&gt; &lt;span class="variable"&gt;max-x&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;)))&lt;br /&gt;  &lt;span class="variable"&gt;max-x&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;correct&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;falsify&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;empty?&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;) &lt;span class="selfeval"&gt;#f&lt;/span&gt; &lt;span class="variable"&gt;s&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;candidates&lt;/span&gt; &lt;br /&gt;         (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; (&lt;span class="variable"&gt;set&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;             (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known&lt;/span&gt; (&lt;span class="variable"&gt;edits1&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;)))&lt;br /&gt;             (&lt;span class="variable"&gt;falsify&lt;/span&gt; (&lt;span class="variable"&gt;known-edits2&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))&lt;br /&gt;             (&lt;span class="variable"&gt;falsify&lt;/span&gt; (list-&gt;set (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;word&lt;/span&gt;))))])&lt;br /&gt;    (&lt;span class="variable"&gt;maximum&lt;/span&gt; (&lt;span class="variable"&gt;elements&lt;/span&gt; &lt;span class="variable"&gt;candidates&lt;/span&gt;) &lt;span class="variable"&gt;word-count&lt;/span&gt;)))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-7544711823329293070?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/7544711823329293070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=7544711823329293070' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/7544711823329293070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/7544711823329293070'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/04/writing-spelling-corrector-in-plt.html' title='Writing a Spelling Corrector in PLT Scheme'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-5277670548420149962</id><published>2007-04-25T19:38:00.000+02:00</published><updated>2007-04-25T23:12:06.247+02:00</updated><title type='text'>An Introduction to Web Development with PLT Scheme - An Intermezzo</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Intermezzo&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is the third post in a series programming web applications with PLT Scheme. In part one and two the &lt;a href="http://www.scheme.dk/blog/2007/01/introduction-to-web-development-with.html"&gt;model&lt;/a&gt; and &lt;a href="http://www.scheme.dk/blog/2007/01/introduction-to-web-development-with_29.html"&gt;view&lt;/a&gt; of a small reddit-like application were discussed. Before turning to the control part of this application, we need to look at the basic operation of the PLT  Scheme web server.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Requests and responses - the big picture&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What happens when a user clicks on a link to your web-site? The browser sends a &lt;span style="font-style: italic;"&gt;request&lt;/span&gt; to the web-server. The request holds among other information the protocol version and the uri (uniform resource identifier) of the requested resource. The web-server must now compute a &lt;span style="font-style: italic;"&gt;response&lt;/span&gt; and send it back.&lt;br /&gt;&lt;br /&gt;How the response is computed depends on the requested resource. In the case of static content, the response of the web-server consists of a few headers (including the mime-type of the file) and a verbatim copy of the file.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Servlets&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Dynamic content is handled by servlets. A servlet is a small program that given a representation of a request computes a response, which the web-server then sends back. The standard "Hello World"-servlet reads as follows:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;hello-world&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;provide&lt;/span&gt; &lt;span class="variable"&gt;interface-version&lt;/span&gt; &lt;span class="variable"&gt;timeout&lt;/span&gt; &lt;span class="variable"&gt;start&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;interface-version&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;v1&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;timeout&lt;/span&gt; &lt;span class="selfeval"&gt;+inf.0&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;; start : request -&amp;gt; response&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;start&lt;/span&gt; &lt;span class="variable"&gt;initial-request&lt;/span&gt;)&lt;br /&gt;   &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;html&lt;/span&gt; (&lt;span class="variable"&gt;head&lt;/span&gt; (&lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="selfeval"&gt;"Hello World"&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="variable"&gt;body&lt;/span&gt; ([&lt;span class="variable"&gt;bgcolor&lt;/span&gt; &lt;span class="selfeval"&gt;"white"&lt;/span&gt;])&lt;br /&gt;                (&lt;span class="variable"&gt;p&lt;/span&gt; &lt;span class="selfeval"&gt;"Coffee is bliss."&lt;/span&gt;)))))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;A module based servlet must provide a &lt;span style="font-family: courier new;"&gt;start&lt;/span&gt; function, that given a request computes a response. In this case the response is XHTML represented as an X-expression. If your fancy is classical HTML as strings, you can return a list, whose first element is the mime type as a byte string, and whose second element is a list of strings (or byte strings) with the lines of the document. For more advanced purposes (such as generating incremental responses) one can return a response structure - see the documentation for details.&lt;br /&gt;&lt;br /&gt;A little tip: If you place a call to &lt;span style="font-family: courier new;"&gt;report-errors-to-browser&lt;/span&gt; at the beginning of start, then the web server will catch any otherwise uncaught exceptions, generate an error page (with source location information) and send it to the client. This is considerably more convenient than constantly rumaging through log files.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Requests&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Back to the &lt;span style="font-family: courier new;"&gt;request &lt;/span&gt;structure. A request structure holds:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; the method (get, post, ...)&lt;/li&gt;&lt;li&gt; the uri of the resource&lt;/li&gt;&lt;li&gt; the headers (including cookies)&lt;/li&gt;&lt;li&gt; bindings (from name value pairs either from a posted form or from the query url itself)&lt;/li&gt;&lt;li&gt; the host-ip (in case the same web server instance handles more than one ip)&lt;/li&gt;&lt;li&gt; the client ip&lt;/li&gt;&lt;li&gt; raw data from a post operations&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;The &lt;span style="font-family: courier new;"&gt;net&lt;/span&gt; collection contains many valuable utilities to deal with uri, headers, cookies etc. I have collected these and other utilities in a little &lt;a href="http://planet.plt-scheme.org/display.ss?package=web.plt&amp;owner=soegaard"&gt;web framework&lt;/a&gt; available from &lt;a href="http://planet.plt-scheme.org"&gt;PLaneT&lt;/a&gt;. It also contains some syntax that hopefully, makes it a bit easier to write servlets. The philosophy is to let the servlet parse the request and store the information in parameters. Similarly parameters hold what will become assembled to a response, when the servlet is finished. For simple servlets, like the one above, nothing much is gained, but more advanced usage patterns like post-redirect-get become much easier to code. The last part of this series will use the framework to implement the control.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Try the PLT Web Server&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The PLT Web Server is included in the &lt;a href="http://download.plt-scheme.org/drscheme/"&gt;DrScheme download&lt;/a&gt;. If you start "PLT Web Server.exe" (Windows) or "web-server-text" (unix and mac), then the static content will be served from "c:/Programs/PLT/collects/web-server/default-web-root/htdocs" and the servlets are in will be in "...default-web-root/servlets/". A few &lt;a href="http://svn.plt-scheme.org/plt/trunk/collects/web-server/default-web-root/servlets/examples/"&gt;examples&lt;/a&gt; are included.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-5277670548420149962?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/5277670548420149962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=5277670548420149962' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/5277670548420149962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/5277670548420149962'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/04/introduction-to-web-development-with.html' title='An Introduction to Web Development with PLT Scheme - An Intermezzo'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-3864408497591325818</id><published>2007-04-24T20:15:00.000+02:00</published><updated>2007-04-24T21:04:39.180+02:00</updated><title type='text'>Fun with macros - extending application to support vector notation</title><content type='html'>[Remember to leave a comment: Was this post silly? Enligthning? Old news?]&lt;br /&gt;&lt;br /&gt;"Scheme vector notation sucks" - a common complaint often heard amongst children and drunks. They might even be right. The sum of a three element vector is calculated like this:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; (&lt;span class="builtin"&gt;vector&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;))&lt;br /&gt;(&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;) (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;) (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;It looks like they are right. Can we repair this with some macro magic?&lt;br /&gt;&lt;br /&gt;Let's first consider what syntax we want to implement. Maybe something like this:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;[&lt;span class="selfeval"&gt;0&lt;/span&gt;] &lt;span class="variable"&gt;a&lt;/span&gt;[&lt;span class="selfeval"&gt;1&lt;/span&gt;] &lt;span class="variable"&gt;a&lt;/span&gt;[&lt;span class="selfeval"&gt;2&lt;/span&gt;])&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Not bad, but in most Scheme implementations the parentheses () and [] mean the same.&lt;br /&gt;How about&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_0&lt;/span&gt;)  (&lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_1&lt;/span&gt;)  (&lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_2&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;then? That we can implement. In PLT Scheme the above is parsed as the&lt;br /&gt;application:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_0&lt;/span&gt;) (&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_1&lt;/span&gt;) (&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;_2&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;All we need to do now, is to implement a new application, that takes special action&lt;br /&gt;when the second argument begins with an underscore. In the following code underscore-symbol? is a function that checks whether a symbol starts with an underscore, and remove-underscore removes an initial underscore from a symbol.&lt;br /&gt;&lt;br /&gt;The code also handles the case where the subscript is an identifier, such as in &lt;span style="font-family: courier new;"&gt;(v _n)&lt;/span&gt;.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;my-app&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; ()&lt;br /&gt;     [(&lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;identifier?&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="variable"&gt;underscore-symbol?&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)))&lt;br /&gt;      (&lt;span class="keyword"&gt;let*&lt;/span&gt; ([&lt;span class="variable"&gt;sub&lt;/span&gt; (&lt;span class="variable"&gt;remove-underscore&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;))]&lt;br /&gt;             [&lt;span class="variable"&gt;num&lt;/span&gt; (&lt;span class="builtin"&gt;string-&amp;gt;number&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;))])&lt;br /&gt;        (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;          [(&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="builtin"&gt;zero?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="builtin"&gt;positive?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))]&lt;br /&gt;          [&lt;span class="variable"&gt;else&lt;/span&gt;&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)))]))]&lt;br /&gt;     [(&lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="variable"&gt;more&lt;/span&gt; ...)&lt;br /&gt;      &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="variable"&gt;more&lt;/span&gt; ...)]&lt;br /&gt;     [&lt;span class="variable"&gt;_&lt;/span&gt;&lt;br /&gt;      (&lt;span class="builtin"&gt;raise-syntax-error&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;my-app&lt;/span&gt; &lt;span class="selfeval"&gt;"bad syntax, in ~a"&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)]))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Notice the use of quasisyntax/loc instead of plain quasisyntax.&lt;br /&gt;If a user writes &lt;span style="font-family: courier new;"&gt;(v _4)&lt;/span&gt; and &lt;span style="font-family: courier new;"&gt;v&lt;/span&gt; is of size 3, then an error must be signaled.&lt;br /&gt;The culprit is the &lt;span style="font-family: courier new;"&gt;vector-ref&lt;/span&gt; expression, so if plain quasisyntax is used,&lt;br /&gt;DrScheme will color the &lt;span style="font-family: courier new;"&gt;vector-ref&lt;/span&gt; expression red - and the user will think&lt;br /&gt;the macro code is faulty. Using &lt;span style="font-family: courier new;"&gt;quasisyntax/loc&lt;/span&gt; allows us to report errors&lt;br /&gt;to the usage of the macro.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;     (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;We also need a notation for the case, where the subscript is a general expression.&lt;br /&gt;That's fortunately easy. Add &lt;span style="font-family: courier new;"&gt;_&lt;/span&gt; to the list of literals of the &lt;span style="font-family: courier new;"&gt;syntax-case&lt;/span&gt; expression, and add this clause:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;      [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;syntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;        (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;))]&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Finally we also need a convenient way to make assignments to vectors. The syntax&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;(v 2 := 42)&lt;/span&gt; is easy to implement. And just in case people forget, we also support &lt;span style="font-family: courier new;"&gt;(v _2 := 42)&lt;/span&gt;.&lt;br /&gt;The entire source follows.&lt;br /&gt;&lt;br /&gt;Remember to leave a comment: Was this post silly? Enligthning? Old news?&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; vector-hack.scm   --  Jens Axel Søgaard&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;vector-hack&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;provide&lt;/span&gt; (&lt;span class="variable"&gt;rename&lt;/span&gt; &lt;span class="variable"&gt;my-app&lt;/span&gt; &lt;span class="keyword"&gt;#%app&lt;/span&gt; ))&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;begin-for-syntax&lt;/span&gt;&lt;br /&gt;   (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;underscore-symbol?&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;symbol?&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)&lt;br /&gt;          (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;str&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)])&lt;br /&gt;            (&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;str&lt;/span&gt;) &lt;span class="selfeval"&gt;0&lt;/span&gt;)&lt;br /&gt;            (&lt;span class="builtin"&gt;equal?&lt;/span&gt; (&lt;span class="builtin"&gt;string-ref&lt;/span&gt; &lt;span class="variable"&gt;str&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;) &lt;span class="selfeval"&gt;#\_&lt;/span&gt;))))&lt;br /&gt;  &lt;br /&gt;   (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;remove-underscore&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="variable"&gt;underscore-symbol?&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)&lt;br /&gt;         (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;str&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;)])&lt;br /&gt;           (&lt;span class="builtin"&gt;string-&amp;gt;symbol&lt;/span&gt; (&lt;span class="builtin"&gt;substring&lt;/span&gt; &lt;span class="variable"&gt;str&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; (&lt;span class="builtin"&gt;string-length&lt;/span&gt; &lt;span class="variable"&gt;str&lt;/span&gt;))))&lt;br /&gt;         (&lt;span class="builtin"&gt;error&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;remove-underscore&lt;/span&gt; &lt;span class="selfeval"&gt;"symbol doesn't start with an underscore: ~a"&lt;/span&gt; &lt;span class="variable"&gt;sym&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;my-app&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; (&lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="selfeval"&gt;:=&lt;/span&gt;)&lt;br /&gt;     [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;identifier?&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="variable"&gt;underscore-symbol?&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)))&lt;br /&gt;      (&lt;span class="keyword"&gt;let*&lt;/span&gt; ([&lt;span class="variable"&gt;sub&lt;/span&gt; (&lt;span class="variable"&gt;remove-underscore&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;))]&lt;br /&gt;             [&lt;span class="variable"&gt;num&lt;/span&gt; (&lt;span class="builtin"&gt;string-&amp;gt;number&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;))])&lt;br /&gt;        (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;          [(&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="builtin"&gt;zero?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="builtin"&gt;positive?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))]&lt;br /&gt;          [&lt;span class="variable"&gt;else&lt;/span&gt;&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)))]))]&lt;br /&gt;     [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;_&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;syntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;        (&lt;span class="builtin"&gt;vector-ref&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;))]&lt;br /&gt;     [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="selfeval"&gt;:=&lt;/span&gt; &lt;span class="variable"&gt;value-expr&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;identifier?&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="variable"&gt;underscore-symbol?&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;)))&lt;br /&gt;      (&lt;span class="keyword"&gt;let*&lt;/span&gt; ([&lt;span class="variable"&gt;sub&lt;/span&gt; (&lt;span class="variable"&gt;remove-underscore&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-e&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt;))]&lt;br /&gt;             [&lt;span class="variable"&gt;num&lt;/span&gt; (&lt;span class="builtin"&gt;string-&amp;gt;number&lt;/span&gt; (&lt;span class="builtin"&gt;symbol-&amp;gt;string&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;))])&lt;br /&gt;        (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;          [(&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;number?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="builtin"&gt;zero?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) (&lt;span class="builtin"&gt;positive?&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;)))&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-set!&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="variable"&gt;num&lt;/span&gt;) &lt;span class="variable"&gt;value-expr&lt;/span&gt;))]&lt;br /&gt;          [&lt;span class="variable"&gt;else&lt;/span&gt;&lt;br /&gt;           (&lt;span class="keyword"&gt;quasisyntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;             (&lt;span class="builtin"&gt;vector-set!&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;datum-&amp;gt;syntax-object&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt;) &lt;span class="variable"&gt;value-expr&lt;/span&gt;))]))]&lt;br /&gt;     [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="selfeval"&gt;:=&lt;/span&gt; &lt;span class="variable"&gt;value-expr&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;syntax/loc&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;&lt;br /&gt;        (&lt;span class="builtin"&gt;vector-set!&lt;/span&gt; &lt;span class="variable"&gt;expr&lt;/span&gt; &lt;span class="variable"&gt;sub&lt;/span&gt; &lt;span class="variable"&gt;value-expr&lt;/span&gt;))]&lt;br /&gt;     [(&lt;span class="variable"&gt;__&lt;/span&gt; &lt;span class="variable"&gt;more&lt;/span&gt; ...)&lt;br /&gt;      &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;#%app&lt;/span&gt; &lt;span class="variable"&gt;more&lt;/span&gt; ...)]&lt;br /&gt;     [&lt;span class="variable"&gt;__&lt;/span&gt;&lt;br /&gt;      (&lt;span class="builtin"&gt;raise-syntax-error&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;my-app&lt;/span&gt; &lt;span class="selfeval"&gt;"bad syntax, in ~a"&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)])))&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;  (&lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;vector-hack&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;v&lt;/span&gt; (&lt;span class="builtin"&gt;vector&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;))&lt;br /&gt;(&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_0&lt;/span&gt;)  &lt;span class="comment"&gt;; =&amp;gt; 0&lt;br /&gt;&lt;/span&gt; (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_1&lt;/span&gt;)  &lt;span class="comment"&gt;; =&amp;gt; 1&lt;br /&gt;&lt;/span&gt; (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_2&lt;/span&gt;)  &lt;span class="comment"&gt;; =&amp;gt; 2&lt;br /&gt;&lt;/span&gt; &lt;span class="comment"&gt;; (my-app v _3)  ; =&amp;gt; error, correct syntax location&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_a&lt;/span&gt;)                    &lt;span class="comment"&gt;; =&amp;gt; 1&lt;br /&gt;&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_0&lt;/span&gt;) (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_1&lt;/span&gt;) (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_2&lt;/span&gt;))  &lt;span class="comment"&gt;; =&amp;gt; 3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="variable"&gt;v&lt;/span&gt;                &lt;span class="comment"&gt;; =&amp;gt; #(0 1 2)&lt;br /&gt;&lt;/span&gt; (&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="variable"&gt;_0&lt;/span&gt; &lt;span class="selfeval"&gt;:=&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;)      &lt;span class="comment"&gt;; #&amp;lt;void&amp;gt;&lt;br /&gt;&lt;/span&gt; &lt;span class="variable"&gt;v&lt;/span&gt;                &lt;span class="comment"&gt;; =&amp;gt; #(3 1 2)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="variable"&gt;v&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt; &lt;span class="selfeval"&gt;:=&lt;/span&gt; &lt;span class="selfeval"&gt;42&lt;/span&gt;)       &lt;span class="comment"&gt;; void&lt;br /&gt;&lt;/span&gt;&lt;span class="variable"&gt;v&lt;/span&gt;                 &lt;span class="comment"&gt;; =&amp;gt; #(42 1 2)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-3864408497591325818?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/3864408497591325818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=3864408497591325818' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/3864408497591325818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/3864408497591325818'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/04/fun-with-macros-extending-application.html' title='Fun with macros - extending application to support vector notation'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-1175976409849651675</id><published>2007-01-29T23:14:00.000+01:00</published><updated>2007-01-30T00:12:16.924+01:00</updated><title type='text'>An Introduction to Web Development with PLT Scheme - The View</title><content type='html'>&lt;span style="font-size:130%;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First of all, thanks for the positive response to &lt;a href="http://www.scheme.dk/blog/2007/01/introduction-to-web-development-with.html"&gt;part 1 of this introduction&lt;/a&gt;. Comments are very welcome.&lt;br /&gt;&lt;br /&gt;The goal of this introduction is to write a "Mini Reddit" called "List It!". The first part focused on the model component i.e. the underlying data and how to implement it using an SQLite database. This second part will concentrate on the view component, which presents the data to the user. The third part will be on the controller.&lt;br /&gt;&lt;br /&gt;Our user interface consists of two pages: the frontpage shows the list of links with the highest scores and the submission page where a user can enter the name and url of a new entry. To give an impression of where we are headed, here is screenshots of the final result:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.scheme.dk/blog/uploaded_images/listit-frontpage-787533.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer;" src="http://www.scheme.dk/blog/uploaded_images/listit-frontpage-783118.png" alt="" border="0" /&gt;&lt;/a&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.scheme.dk/blog/uploaded_images/listit-submit-new-748026.png"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; cursor: pointer;" src="http://www.scheme.dk/blog/uploaded_images/listit-submit-new-744605.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the Model-View-Controller organization, the controller receives a request from the client (user), retrieves data from the model, lets the view construct a web page and the sends a response back to the client. The view thus consists of a series of functions turning data&lt;br /&gt;into web-pages.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Representing XHTML as X-expressions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;PLT Scheme supports multiple ways of representing web-pages. One option is to use strings:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;"&amp;lt;html&gt;&amp;lt;head&gt;&amp;lt;title&gt;A Title&amp;lt;/title&gt;&lt;br /&gt;&amp;lt;body&gt;A body&amp;lt;/body&gt;&amp;lt;/html&gt;".&lt;br /&gt;&lt;/pre&gt;Since the structure of the document is lost with this choice, all but the most simple manipulations of the document, becomes harder to program than they should.&lt;br /&gt;&lt;br /&gt;Instead we will use X-expressions (S-expressions representing XML) to represent our web-pages. The above example becomes:&lt;br /&gt;&lt;pre&gt;  `(html (head (title "A title"))&lt;br /&gt;  (body "A body"))&lt;br /&gt;&lt;/pre&gt;Besides X-expressions another popular choice in the Scheme world is SXML (if you are into serious XML-manipulations  look into &lt;a href="http://www196.pair.com/lisovsky/xml/index.html"&gt;SXML and SSAX&lt;/a&gt;), which are similar to X-expressions in terms of use.&lt;br /&gt;&lt;br /&gt;The beauty of X-expressions is that, since they are normal lists, we can use the builtin functions to manipulate them. Another major convenience is we can use unquote (written as a comma) to insert the result of a Scheme expressions into the X-expression:&lt;br /&gt;&lt;pre&gt;   `(body "The result of 1+2 is: " ,(number-&gt;string (+ 1 2)))&lt;br /&gt;&lt;/pre&gt;which, when evaluated, results in&lt;br /&gt;&lt;pre&gt;    (body "The result of 1+2 is: " "3").&lt;br /&gt;&lt;/pre&gt;Attributes are placed right after the tag:&lt;br /&gt;&lt;pre&gt;    `(body ((color "white") (bgcolor "black"))&lt;br /&gt;     "Hello world")&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-size:130%;"&gt;The WEB library&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To avoid writting boilerplate stuff (charset, stylesheet, content type etc.) each and every time a web page is constructed, we will use the general &lt;a href="http://planet.plt-scheme.org/300/docs/soegaard/web.plt/1/0/doc.txt"&gt;web framework from PLaneT &lt;/a&gt;(the PLT Scheme "CPAN" - note that packages are downloaded automatically if needed).&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="builtin"&gt;&gt;&lt;/span&gt; (&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"html.scm"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"web.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;span class="builtin"&gt;&gt;&lt;/span&gt; (&lt;span class="variable"&gt;html-page&lt;/span&gt; &lt;span class="variable"&gt;#:body&lt;/span&gt; &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;p&lt;/span&gt; &lt;span class="selfeval"&gt;"Hello world"&lt;/span&gt;))&lt;br /&gt;(&lt;span class="variable"&gt;html&lt;/span&gt;&lt;br /&gt;(&lt;span class="variable"&gt;head&lt;/span&gt; (&lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="selfeval"&gt;"A title"&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="variable"&gt;link&lt;/span&gt; ((&lt;span class="variable"&gt;rel&lt;/span&gt; &lt;span class="selfeval"&gt;"stylesheet"&lt;/span&gt;) (&lt;span class="variable"&gt;type&lt;/span&gt; &lt;span class="selfeval"&gt;"text/css"&lt;/span&gt;) (&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="selfeval"&gt;""&lt;/span&gt;)))&lt;br /&gt;    (&lt;span class="variable"&gt;meta&lt;/span&gt; ((&lt;span class="variable"&gt;http-equiv&lt;/span&gt; &lt;span class="selfeval"&gt;"Content-Type"&lt;/span&gt;) (&lt;span class="variable"&gt;content&lt;/span&gt; &lt;span class="selfeval"&gt;"text/html;charset=UTF-8"&lt;/span&gt;))))&lt;br /&gt;(&lt;span class="variable"&gt;body&lt;/span&gt; (&lt;span class="variable"&gt;h1&lt;/span&gt; &lt;span class="selfeval"&gt;"A Header"&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="variable"&gt;p&lt;/span&gt; &lt;span class="selfeval"&gt;"Hello world"&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;In the example above, the &lt;span style="font-family:courier new;"&gt;html-page&lt;/span&gt; only received the body, so it used the site wide default arguments for the title, the stylesheet and the "header". Obviously we need to override the defaults for our List It! site:&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-title&lt;/span&gt;&lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-header&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;h1&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"page_header"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;))&lt;br /&gt;(&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-style-sheet&lt;/span&gt; &lt;span class="selfeval"&gt;"http://localhost/stylesheet.css"&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;After overriding the defaults we get:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;    (&lt;span class="variable"&gt;html&lt;/span&gt;&lt;br /&gt;  (&lt;span class="variable"&gt;head&lt;/span&gt; (&lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt;        (&lt;span class="variable"&gt;link&lt;/span&gt; ((&lt;span class="variable"&gt;rel&lt;/span&gt; &lt;span class="selfeval"&gt;"stylesheet"&lt;/span&gt;) (&lt;span class="variable"&gt;type&lt;/span&gt; &lt;span class="selfeval"&gt;"text/css"&lt;/span&gt;)&lt;br /&gt;               (&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="selfeval"&gt;"http://localhost/stylesheet.css"&lt;/span&gt;)))&lt;br /&gt;        (&lt;span class="variable"&gt;meta&lt;/span&gt; ((&lt;span class="variable"&gt;http-equiv&lt;/span&gt; &lt;span class="selfeval"&gt;"Content-Type"&lt;/span&gt;)&lt;br /&gt;               (&lt;span class="variable"&gt;content&lt;/span&gt; &lt;span class="selfeval"&gt;"text/html;charset=UTF-8"&lt;/span&gt;))))&lt;br /&gt;  (&lt;span class="variable"&gt;body&lt;/span&gt; (&lt;span class="variable"&gt;h1&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"page_header"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt;        (&lt;span class="variable"&gt;p&lt;/span&gt; &lt;span class="selfeval"&gt;"Hello world"&lt;/span&gt;)))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Use the keywords &lt;span style="font-family:courier new;"&gt;#:title, #:header, #:body, #:style-sheet, and #:style-sheet&lt;/span&gt; with &lt;span style="font-family:courier new;"&gt;html-pag&lt;/span&gt;e, in order not to use the site wide defaults.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Submit-new-entry page&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The funtion &lt;span style="font-family:courier new;"&gt;html-submit-new-page&lt;/span&gt; builds an X-expression representing the submission page. It takes no arguments, since it doesn't rely on data from the model:&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-submit-new-page&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;html-page&lt;/span&gt;&lt;br /&gt;&lt;span class="variable"&gt;#:title&lt;/span&gt;  &lt;span class="selfeval"&gt;"List it! - submit"&lt;/span&gt;&lt;br /&gt;&lt;span class="variable"&gt;#:header&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;h1&lt;/span&gt; &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt;&lt;span class="variable"&gt;#:body&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; (&lt;span class="variable"&gt;h2&lt;/span&gt; &lt;span class="selfeval"&gt;"Submit a new entry"&lt;/span&gt;)&lt;br /&gt;   &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-form&lt;/span&gt;&lt;br /&gt;     &lt;span class="selfeval"&gt;"submitnewform"&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm"&lt;/span&gt;&lt;br /&gt;     (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"action"&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt;)&lt;br /&gt;     &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;table&lt;/span&gt; (&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt;)   (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt;   &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;text&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"http://"&lt;/span&gt;)))&lt;br /&gt;             (&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt;) (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;text&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"A title"&lt;/span&gt;))))&lt;br /&gt;     (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt;)))))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The submission page consists of a form with two input fields. One for the url and one for the title. The function &lt;span style="font-family:courier new;"&gt;html-form&lt;/span&gt; rececives a name of the form, the action. The default method for submitting is POST, but one can use the keyword argument &lt;span style="font-family:courier new;"&gt;#:method&lt;/span&gt; to choose something else. The function &lt;span style="font-family:courier new;"&gt;html-input&lt;/span&gt; builds an input field. Other types of input fields are: &lt;span style="font-family:courier new;"&gt;'image&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;'hidden&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;Clicking the submit button will post the parameters action, url and title to &lt;span style="font-family:courier new;"&gt;control.scm&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Frontpage&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The submitted entries are ranked according to their score.  The entry with the highest score has rank 1, the next rank 2 and so on. Only a limited number of entries can be showed at a time, so we imagine the entries divided into pages. The function &lt;span style="font-family:courier new;"&gt;html-front-page&lt;/span&gt; below receives three arguments: a page number, the rank of the first entry of the page in question and the list of entries&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-front-page&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)&lt;br /&gt;(&lt;span class="variable"&gt;html-page&lt;/span&gt;&lt;br /&gt;&lt;span class="variable"&gt;#:body&lt;/span&gt; &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt;&lt;br /&gt;       &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-menu&lt;/span&gt;)&lt;br /&gt;       &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-list-of-entries&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;))))&lt;/pre&gt;&lt;/div&gt;The function &lt;span style="font-family:courier new;"&gt;html-menu&lt;/span&gt; generates an X-expression for the "menu" on top of the screen The function &lt;span style="font-family:courier new;"&gt;html-list-of-entries&lt;/span&gt; generates an X-expression representing the list of entries.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The menu&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The "menu" consists so far of a single menu item "submit-new-link".&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-menu&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;a&lt;/span&gt; ((&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm?action=submitnew"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"submit-new-link"&lt;/span&gt;))&lt;/pre&gt;&lt;/div&gt;&lt;span style="font-size:130%;"&gt;The list of entries&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The list of entries is received by &lt;span style="font-family:courier new;"&gt;html-list-of-entries&lt;/span&gt; as a list of vectors.&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"entry_id"&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt; &lt;span class="selfeval"&gt;"score"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"1"&lt;/span&gt; &lt;span class="selfeval"&gt;"Everything Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.scheme.dk/blog/"&lt;/span&gt; &lt;span class="selfeval"&gt;"42"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"3"&lt;/span&gt; &lt;span class="selfeval"&gt;"PLT Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.plt-scheme.org"&lt;/span&gt; &lt;span class="selfeval"&gt;"9"&lt;/span&gt;)&lt;br /&gt;...)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The first vector holds the column names in the database, and can thus safely be ignored.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-list-of-entries&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"entries"&lt;/span&gt;))&lt;br /&gt;   &lt;span class="keyword"&gt;,@&lt;/span&gt;(&lt;span class="variable"&gt;list-ec&lt;/span&gt;&lt;br /&gt;      (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;not&lt;/span&gt; (&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)))&lt;br /&gt;      (&lt;span class="selfeval"&gt;:list&lt;/span&gt; &lt;span class="variable"&gt;entry&lt;/span&gt; (&lt;span class="variable"&gt;index&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;) (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;))&lt;br /&gt;      (&lt;span class="selfeval"&gt;:match&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;(&lt;span class="variable"&gt;id&lt;/span&gt; &lt;span class="variable"&gt;header&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;) &lt;span class="variable"&gt;entry&lt;/span&gt;)&lt;br /&gt;      &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;table&lt;/span&gt; ...))))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;A DIV of class "entries" is used around the list of entries, so we single them out in the stylesheet. Next we use an eager comprehension list-ec to generate a list of X-expressions, one for each entry. Since we want the result to be of the form &lt;span style="font-family:courier new;"&gt;(div (class "entries") (table ...) (table ...) ...) &lt;/span&gt;and not &lt;span style="font-family:courier new;"&gt;(div (class "entries") ((table ...) (table ...) ...))&lt;/span&gt; we use unquote-splicing &lt;span style="font-family:courier new;"&gt;,@&lt;/span&gt; instead of just unquote.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts.html"&gt;eager comprehension&lt;/a&gt; first checks to see, whether entries is the empty list - and if so, an empty list of X-expressions is generated.&lt;br /&gt;&lt;br /&gt;The clause &lt;span style="font-family:courier new;"&gt;(list entry (index i) (cdr entries))&lt;/span&gt; iterates over the elements of the list entries (minus the first element), binding entry to each element in turn, also the index variable&lt;span style="font-family:courier new;"&gt; i&lt;/span&gt; counts from 0 and up.&lt;br /&gt;&lt;br /&gt;The clause (:match #(id header url score) entry) uses pattern matching to bind the variables &lt;span style="font-family:courier new;"&gt;id&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;header&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;url&lt;/span&gt;, and &lt;span style="font-family:courier new;"&gt;score&lt;/span&gt; to the elements of the entry vector.&lt;br /&gt;&lt;br /&gt;The final expression &lt;span style="font-family:courier new;"&gt;`(table ...)&lt;/span&gt; can now use the variables to generate the X-expression for the entry in question.&lt;br /&gt;&lt;br /&gt;The table is used to position the rank, the up- and down-arrow and the link. I am able to do the same in CSS - but not in all browsers at the same time.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;table&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"entry"&lt;/span&gt;))&lt;br /&gt;(&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"rank"&lt;/span&gt;)) &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;number-&amp;gt;string&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt;)))&lt;br /&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;form&lt;/span&gt; (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowform~a"&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt;)))&lt;br /&gt;        (&lt;span class="variable"&gt;html-form&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm"&lt;/span&gt;&lt;br /&gt;           &lt;span class="variable"&gt;#:atts&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrows"&lt;/span&gt;))&lt;br /&gt;           (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt;  &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"entry_id"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt;)&lt;br /&gt;           (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"action"&lt;/span&gt;   &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"updown"&lt;/span&gt;)&lt;br /&gt;           &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-a-submit&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt; &lt;span class="selfeval"&gt;"up"&lt;/span&gt;&lt;br /&gt;                                      (&lt;span class="variable"&gt;html-icon&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;go-up&lt;/span&gt; &lt;span class="variable"&gt;#:class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrow"&lt;/span&gt;)))&lt;br /&gt;                 &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-a-submit&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt; &lt;span class="selfeval"&gt;"down"&lt;/span&gt;&lt;br /&gt;                                      (&lt;span class="variable"&gt;html-icon&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;go-down&lt;/span&gt; &lt;span class="variable"&gt;#:class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrow"&lt;/span&gt;)))))&lt;br /&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; (&lt;span class="variable"&gt;div&lt;/span&gt; (&lt;span class="variable"&gt;a&lt;/span&gt; ((&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;url&lt;/span&gt;)) &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;header&lt;/span&gt;))&lt;br /&gt;     (&lt;span class="variable"&gt;span&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"score"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"score: "&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;score&lt;/span&gt;)))))))&lt;/pre&gt;&lt;/div&gt;The alert reader will probably wonder, why the form is introduced. Why aren't the arrows two simple links to, say,&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;control.scm?action=updown&amp;arrowitem=down&amp;amp;entry_id=1 ?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Well, a click at the above url would result in the entry getting a vote. The problem lies in what happens next. If the user now reloads the page, the entry will get an extra vote. Bookingmarking the page will also result in extra votes, when the user returns.&lt;br /&gt;&lt;br /&gt;The form-solution sends the parameters "behind the scenes", so that the url becomes &lt;span style="font-family:courier new;"&gt;control.scm&lt;/span&gt;. This obviously solves the bookmarking problem. The reload problem is solved via the Post/Redirect/Get pattern - which I'll discuss in detail in the post on the controller.&lt;br /&gt;&lt;br /&gt;The function &lt;span style="font-family:courier new;"&gt;html-a-submit&lt;/span&gt; builds a link that submits the form (it's in the web-framework), it involves a little JavaScript.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-a-submit&lt;/span&gt; &lt;span class="variable"&gt;formname&lt;/span&gt; &lt;span class="variable"&gt;formitem&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt; &lt;span class="variable"&gt;text&lt;/span&gt;)&lt;br /&gt;&lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;a&lt;/span&gt; ((&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;string-append&lt;/span&gt;&lt;br /&gt;          (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"javascript:document.~a.~a.value='~a';"&lt;/span&gt; &lt;span class="variable"&gt;formname&lt;/span&gt; &lt;span class="variable"&gt;formitem&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt;)&lt;br /&gt;          (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"document.~a.submit();"&lt;/span&gt; &lt;span class="variable"&gt;formname&lt;/span&gt;))))&lt;br /&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;text&lt;/span&gt;))&lt;/pre&gt;&lt;/div&gt;The function &lt;span style="font-family:courier new;"&gt;html-icon&lt;/span&gt; returns an X-expression &lt;span style="font-family:courier new;"&gt;`(img ...)&lt;/span&gt; representing various images. In this tutorial only the up- and down-arrow is supported, but if anyone is interested, I have a version supporting all of &lt;a href="http://tango.freedesktop.org/Tango_Icon_Gallery"&gt;Tango&lt;/a&gt; (an excellent source of icons).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Program&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;;;; view.scm  --  Jens Axel Soegaard&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;view&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;provide&lt;/span&gt; (&lt;span class="variable"&gt;all-defined&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;lib&lt;/span&gt; &lt;span class="selfeval"&gt;"kw.ss"&lt;/span&gt;)&lt;br /&gt;          (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"42.ss"&lt;/span&gt;    (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"srfi.plt"&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"html.scm"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"web.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"web.scm"&lt;/span&gt;  (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"web.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;;;;&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;;;; SITE WIDE DEFAULTS&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;;;;&lt;br /&gt;&lt;/span&gt; &lt;br /&gt; (&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-title&lt;/span&gt;       &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt; (&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-header&lt;/span&gt;      &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;h1&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"page_header"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;))&lt;br /&gt; (&lt;span class="variable"&gt;override-default&lt;/span&gt; &lt;span class="variable"&gt;current-page-style-sheet&lt;/span&gt; &lt;span class="selfeval"&gt;"http://localhost/stylesheet.css"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;;;;&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;;;; FRONT PAGE(S)&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;;;;&lt;br /&gt;&lt;/span&gt; &lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-front-page&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="variable"&gt;html-page&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable"&gt;#:body&lt;/span&gt; &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt;&lt;br /&gt;             &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-menu&lt;/span&gt;)&lt;br /&gt;             &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-list-of-entries&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-menu&lt;/span&gt;)&lt;br /&gt;   &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;a&lt;/span&gt; ((&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm?action=submitnew"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"submit-new-link"&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-submit-new-page&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="variable"&gt;html-page&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable"&gt;#:title&lt;/span&gt;  &lt;span class="selfeval"&gt;"List it! - submit"&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable"&gt;#:header&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;h1&lt;/span&gt; &lt;span class="selfeval"&gt;"List it!"&lt;/span&gt;)&lt;br /&gt;    &lt;span class="variable"&gt;#:body&lt;/span&gt;  &lt;br /&gt;    &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; (&lt;span class="variable"&gt;h2&lt;/span&gt; &lt;span class="selfeval"&gt;"Submit a new entry"&lt;/span&gt;)&lt;br /&gt;          &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-form&lt;/span&gt;&lt;br /&gt;            &lt;span class="selfeval"&gt;"submitnewform"&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm"&lt;/span&gt;&lt;br /&gt;            (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"action"&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt;)&lt;br /&gt;            &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;table&lt;/span&gt; (&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt;)   (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;text&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"http://"&lt;/span&gt;)))&lt;br /&gt;                    (&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt;) (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;text&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"A title"&lt;/span&gt;))))&lt;br /&gt;            (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"submit"&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt; (&lt;span class="variable"&gt;define/kw&lt;/span&gt; (&lt;span class="variable"&gt;html-icon&lt;/span&gt; &lt;span class="variable"&gt;name&lt;/span&gt; &lt;span class="variable"&gt;#:key&lt;/span&gt; (&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;icon-absolute-url&lt;/span&gt; &lt;span class="variable"&gt;name&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"/~a.png"&lt;/span&gt; &lt;span class="variable"&gt;name&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="variable"&gt;class&lt;/span&gt;&lt;br /&gt;       &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;img&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;class&lt;/span&gt;) (&lt;span class="variable"&gt;src&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;icon-absolute-url&lt;/span&gt; &lt;span class="variable"&gt;name&lt;/span&gt;))))&lt;br /&gt;       &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;img&lt;/span&gt; (               (&lt;span class="variable"&gt;src&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;icon-absolute-url&lt;/span&gt; &lt;span class="variable"&gt;name&lt;/span&gt;))))))&lt;br /&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-list-of-entries&lt;/span&gt; &lt;span class="variable"&gt;page-number&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)&lt;br /&gt;   &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"entries"&lt;/span&gt;))&lt;br /&gt;         &lt;span class="keyword"&gt;,@&lt;/span&gt;(&lt;span class="variable"&gt;list-ec&lt;/span&gt;&lt;br /&gt;            (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;not&lt;/span&gt; (&lt;span class="builtin"&gt;null?&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;)))&lt;br /&gt;            (&lt;span class="selfeval"&gt;:list&lt;/span&gt; &lt;span class="variable"&gt;entry&lt;/span&gt; (&lt;span class="variable"&gt;index&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt;) (&lt;span class="builtin"&gt;cdr&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;))&lt;br /&gt;            (&lt;span class="selfeval"&gt;:match&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;(&lt;span class="variable"&gt;id&lt;/span&gt; &lt;span class="variable"&gt;header&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;) &lt;span class="variable"&gt;entry&lt;/span&gt;)&lt;br /&gt;            &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;table&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"entry"&lt;/span&gt;))&lt;br /&gt;                    (&lt;span class="variable"&gt;tr&lt;/span&gt; (&lt;span class="variable"&gt;td&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"rank"&lt;/span&gt;)) &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;number-&amp;gt;string&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;i&lt;/span&gt; &lt;span class="variable"&gt;rank-of-first-entry&lt;/span&gt;)))&lt;br /&gt;                        (&lt;span class="variable"&gt;td&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;form&lt;/span&gt; (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowform~a"&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt;)))&lt;br /&gt;                               (&lt;span class="variable"&gt;html-form&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"control.scm"&lt;/span&gt;&lt;br /&gt;                                          &lt;span class="variable"&gt;#:atts&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrows"&lt;/span&gt;))&lt;br /&gt;                                          (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt;  &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt;)&lt;br /&gt;                                          (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"entry_id"&lt;/span&gt; &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="variable"&gt;id&lt;/span&gt;)&lt;br /&gt;                                          (&lt;span class="variable"&gt;html-input&lt;/span&gt; &lt;span class="selfeval"&gt;"action"&lt;/span&gt;   &lt;span class="variable"&gt;#:type&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;hidden&lt;/span&gt; &lt;span class="variable"&gt;#:value&lt;/span&gt; &lt;span class="selfeval"&gt;"updown"&lt;/span&gt;)&lt;br /&gt;                                          &lt;span class="keyword"&gt;`&lt;/span&gt;(&lt;span class="variable"&gt;div&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;html-a-submit&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt; &lt;span class="selfeval"&gt;"up"&lt;/span&gt; (&lt;span class="variable"&gt;html-icon&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;go-up&lt;/span&gt; &lt;span class="variable"&gt;#:class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrow"&lt;/span&gt;)))&lt;br /&gt;                                          (&lt;span class="variable"&gt;html-a-submit&lt;/span&gt; &lt;span class="variable"&gt;form&lt;/span&gt; &lt;span class="selfeval"&gt;"arrowitem"&lt;/span&gt; &lt;span class="selfeval"&gt;"down"&lt;/span&gt; (&lt;span class="variable"&gt;html-icon&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;go-down&lt;/span&gt; &lt;span class="variable"&gt;#:class&lt;/span&gt; &lt;span class="selfeval"&gt;"arrow"&lt;/span&gt;)))))&lt;br /&gt;                        (&lt;span class="variable"&gt;td&lt;/span&gt; (&lt;span class="variable"&gt;div&lt;/span&gt; (&lt;span class="variable"&gt;a&lt;/span&gt; ((&lt;span class="variable"&gt;href&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;url&lt;/span&gt;)) &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;header&lt;/span&gt;))&lt;br /&gt;                            (&lt;span class="variable"&gt;span&lt;/span&gt; ((&lt;span class="variable"&gt;class&lt;/span&gt; &lt;span class="selfeval"&gt;"score"&lt;/span&gt;)) &lt;span class="selfeval"&gt;"score: "&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;score&lt;/span&gt;)))))))&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;; html-redirect-page&lt;br /&gt;&lt;/span&gt;  &lt;span class="comment"&gt;;   a standard text to show, when redirecting&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;html-redirect-page&lt;/span&gt; &lt;span class="variable"&gt;body&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="variable"&gt;html-page&lt;/span&gt; &lt;span class="variable"&gt;#:title&lt;/span&gt; &lt;span class="selfeval"&gt;"Redirecting"&lt;/span&gt;&lt;br /&gt;              &lt;span class="variable"&gt;#:body&lt;/span&gt;  &lt;span class="variable"&gt;body&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt; )&lt;br /&gt; &lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-1175976409849651675?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/1175976409849651675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=1175976409849651675' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/1175976409849651675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/1175976409849651675'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/01/introduction-to-web-development-with_29.html' title='An Introduction to Web Development with PLT Scheme - The View'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-208531338554508101</id><published>2007-01-20T17:13:00.000+01:00</published><updated>2007-01-28T22:21:46.380+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='mvc'/><category scheme='http://www.blogger.com/atom/ns#' term='servlet'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='web-server'/><category scheme='http://www.blogger.com/atom/ns#' term='PLT'/><title type='text'>An Introduction to Web Development with PLT Scheme</title><content type='html'>&lt;span style="font-size:130%;"&gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;From time to time people ask how  to develop for the web with &lt;a href="http://www.plt-scheme.org/"&gt;PLT Scheme&lt;/a&gt; on the &lt;a href="http://list.cs.brown.edu/pipermail/plt-scheme/"&gt;PLT mailing list&lt;/a&gt;. The quick answer is "Just as in any other language", but that's not how to get people hooked on Scheme. To write a decent web-application require knowledge of a range of subjects such as HTML, databases, servlets, and web-servers. For some reason there is a lack of tutorials on these subjects, so I have decided to make an attempt at writing, if not a complete tutorial, then an elaborate get-started example.&lt;br /&gt;&lt;br /&gt;The example application will be a mini version of &lt;a href="http://www.reddit.com/"&gt;Reddit&lt;/a&gt; called ListIt. The front page consists of a list of links to interesting articles, users can vote the articles up and down, and submit new articles. The hope is that the example is small enough to be easily understood, but on the other hand large enough to illustrate as many aspects as possible. Please leave comments on the blog: Did the example hit home?  Is a paragraph in need of a rewrite? Did I skip something?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Model-View-controller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First things first. How should the program be organized? There is no need to reinvent the wheel, so I have chosen to use the Model-View-Controller architecture, which works just as well for web applications as it does for graphical user interfaces.&lt;br /&gt;&lt;br /&gt;In a nutshell the Model-View-Controller architecture works like this: The model holds the data, the view displays data. User interactions goes through the controller in order to keep a separation between the model and the view. (See &lt;a href="http://www.htdp.org/2003-09-26/Book/curriculum-Z-H-28.html#node_idx_1556"&gt;section 22.3 of HTDP&lt;/a&gt;  or &lt;a href="http://en.wikipedia.org/wiki/Model-view-controller"&gt;Wikipedia&lt;/a&gt; for more on MVC ).&lt;br /&gt;&lt;br /&gt;In our case we will represent the model, the view and the controllers as three separate Scheme modules. The model will use a database to hold the links, the view will consists of functions generating HTML and the controller will the web-servlet that reacts on the user actions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Model&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Today we will concentrate on the model. Each entry in our database consists of an entry-id , a title to display, an url to the article and a score representing the votes. Since we expect many entries in our database, we will think of them as divided into page. The number of entries in each page is given by the parameter PAGE-LIMIT.&lt;br /&gt;&lt;br /&gt;The interface to our model consists of the following functions:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;insert-entry: title url score -&gt; entry-id&lt;/span&gt;&lt;br /&gt; Insert a new entry into the database.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;increase-score : entry-id -&gt;&lt;/span&gt;&lt;br /&gt; Increase the score of an existing entry&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;decrease-score : entry-id -&gt;&lt;/span&gt;&lt;br /&gt; Decrease the score of an existing entry&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;top : natural -&gt; (list (list entry-id title url score))&lt;/span&gt;&lt;br /&gt; Return the given number of entries with the highest scores&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;page : natural -&gt; (list (list entry-id title url score))&lt;/span&gt;&lt;br /&gt; Return the list of entries in the given page.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;url-in-db? : url -&gt; boolean&lt;/span&gt;&lt;br /&gt; Is the url already listed?&lt;br /&gt;&lt;br /&gt;These functions are the only ones to be exposed to the controller.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Implementation of the model&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To implement these functions we will use an &lt;a href="http://www.sqlite.org/"&gt;SQLite&lt;/a&gt; database. It wouldn't be unreasonable to argue that it would be easier to use a hash-table, but I want to illustrate how to use SQLite.&lt;br /&gt;&lt;br /&gt;SQLite is small database engine, which comes in the form of a single self-contained, zero-configuration DLL-file on Windows or a a so-file on other platforms. We will use Jay McCarthy and Noel Welsh's PLT Scheme bindings &lt;a href="http://planet.plt-scheme.org/300/#sqlite.plt"&gt;sqlite.plt&lt;/a&gt; . On top of these binding we'll use a S-expression to SQL-string library written by me (it will appear on PLaneT soon - it has been submitted). On Windows you download SQLite by pasting the following into the DrScheme interaction window (the REPL):&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-family:courier new;"&gt;(require (planet "download-sqlite.scm"&lt;br /&gt;("soegaard" "sqlite.plt" 1 0))&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;To use the two SQLite packages, we start our module with&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;(require &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   (planet "sqlite.ss" ("jaymccarthy" "sqlite.plt"))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   (planet "sqlite.ss" ("soegaard" "sqlite.plt" 1 0)))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Opening the database is simple:&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;&lt;br /&gt;(define db (open (string-&gt;path "c:/listit.sb")))&lt;/span&gt; .&lt;br /&gt;&lt;br /&gt;At least it will be, after it is created. The following function creates an empty database with a single table "entries":&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define (create-table-entries)&lt;br /&gt; (exec/ignore&lt;br /&gt;  db&lt;br /&gt;  #&amp;lt;&amp;lt;SQL&lt;br /&gt;CREATE TABLE entries (&lt;br /&gt;  entry_id  INTEGER PRIMARY KEY,&lt;br /&gt;  title     TEXT,&lt;br /&gt;  url       TEXT,&lt;br /&gt;  score     INTEGER )&lt;br /&gt;SQL&lt;br /&gt;  ))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The #&amp;lt;&amp;lt; starts a so called &lt;a href="http://docs.plt-scheme.org/mzscheme/mzscheme-Z-H-11.html#node_idx_2310"&gt;here-string&lt;/a&gt;. The function &lt;span style="font-family:courier new;"&gt;exec/ignore&lt;/span&gt; executes an SQL-statement and ignores the result (there is no S-expression syntax for CREATE TABLE yet).&lt;br /&gt;&lt;br /&gt;Once we have created the our table, we can begin writing the functions in our interface.&lt;br /&gt;The first is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define (insert-entry title url score)&lt;br /&gt; (insert db (sql (INSERT INTO entries (title url score)&lt;br /&gt;                         VALUES (,title ,url ,score)))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The macro &lt;span style="font-family:courier new;"&gt;sql&lt;/span&gt; converts an S-expression representation of an SQL-statement into a string, which is then handed to SQLite by &lt;span style="font-family:courier new;"&gt;insert&lt;/span&gt;. The string produced by the sql macro from&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;(insert-entry "Everything Scheme" "http://www.scheme.dk/blog/" 42)&lt;/span&gt;&lt;span style="font-size:85%;"&gt; &lt;/span&gt;&lt;br /&gt;becomes&lt;br /&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;"INSERT INTO entries (title, url, score) VALUES ('Everything Scheme', 'http://www.scheme.dk/blog/', '42')"&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The remaining functions from the interface are all simple SQL-statements, which can be studied in the full program below.&lt;br /&gt;&lt;br /&gt;A loose end: In the source below the parameter &lt;span style="font-family:courier new;"&gt;current-database&lt;/span&gt; is used to hold the database. As a convenience I have with the help of syntax-id-rules defined the identifier &lt;span style="font-family:courier new;"&gt;db&lt;/span&gt; to expand to &lt;span style="font-family:courier new;"&gt;(current-database)&lt;/span&gt;. But in order make everything work also as when the database isn't created yet, the actual definition below is a little more involved.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Testing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To test the model, open the "model.scm" in DrScheme. In the "Language" menu use "Choose Language" to choose the "Module" language. Click and "Run" and you are ready to test it:&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="variable"&gt;Welcome&lt;/span&gt; &lt;span class="variable"&gt;to&lt;/span&gt; &lt;span class="variable"&gt;DrScheme&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt; &lt;span class="builtin"&gt;version&lt;/span&gt; &lt;span class="variable"&gt;369.3-svn10jan2007.&lt;/span&gt;&lt;br /&gt;&lt;span class="variable"&gt;Language:&lt;/span&gt; (&lt;span class="keyword"&gt;module&lt;/span&gt; ...).&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="selfeval"&gt;"Everything Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.scheme.dk/blog/"&lt;/span&gt; &lt;span class="selfeval"&gt;42&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="selfeval"&gt;"Reddit"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.reddit.com"&lt;/span&gt; &lt;span class="selfeval"&gt;7&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="selfeval"&gt;"PLT Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.plt-scheme.org"&lt;/span&gt; &lt;span class="selfeval"&gt;5&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;3&lt;/span&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;top&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;)&lt;br /&gt;(&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"entry_id"&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt; &lt;span class="selfeval"&gt;"score"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"1"&lt;/span&gt; &lt;span class="selfeval"&gt;"Everything Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.scheme.dk/blog/"&lt;/span&gt; &lt;span class="selfeval"&gt;"42"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"2"&lt;/span&gt; &lt;span class="selfeval"&gt;"Reddit"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.reddit.com"&lt;/span&gt; &lt;span class="selfeval"&gt;"7"&lt;/span&gt;))&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;)&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;)&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;)&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="selfeval"&gt;3&lt;/span&gt;)&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;top&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt;)&lt;br /&gt;(&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"entry_id"&lt;/span&gt; &lt;span class="selfeval"&gt;"title"&lt;/span&gt; &lt;span class="selfeval"&gt;"url"&lt;/span&gt; &lt;span class="selfeval"&gt;"score"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"1"&lt;/span&gt; &lt;span class="selfeval"&gt;"Everything Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.scheme.dk/blog/"&lt;/span&gt; &lt;span class="selfeval"&gt;"42"&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#4&lt;/span&gt;(&lt;span class="selfeval"&gt;"3"&lt;/span&gt; &lt;span class="selfeval"&gt;"PLT Scheme"&lt;/span&gt; &lt;span class="selfeval"&gt;"http://www.plt-scheme.org"&lt;/span&gt; &lt;span class="selfeval"&gt;"9"&lt;/span&gt;))&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;The Program&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;;;; model.scm  -- Jens Axel Søgaard&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;model&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;provide&lt;/span&gt; (&lt;span class="variable"&gt;all-defined&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;require&lt;/span&gt;&lt;br /&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"sqlite.ss"&lt;/span&gt; (&lt;span class="selfeval"&gt;"jaymccarthy"&lt;/span&gt; &lt;span class="selfeval"&gt;"sqlite.plt"&lt;/span&gt;))&lt;br /&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"sqlite.ss"&lt;/span&gt; (&lt;span class="selfeval"&gt;"soegaard"&lt;/span&gt; &lt;span class="selfeval"&gt;"sqlite.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;;; CONFIGURATION&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;PAGE-LIMIT&lt;/span&gt;        (&lt;span class="builtin"&gt;make-parameter&lt;/span&gt; &lt;span class="selfeval"&gt;50&lt;/span&gt;))   &lt;span class="comment"&gt;; number of entries on each page&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;DATABASE-PATH&lt;/span&gt;     (&lt;span class="builtin"&gt;string-&amp;gt;path&lt;/span&gt; &lt;span class="selfeval"&gt;"listit.db"&lt;/span&gt;))&lt;br /&gt;&lt;span class="comment"&gt;; initialization of the db happens at the first run, see bottom of this file&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;current-database&lt;/span&gt;  (&lt;span class="builtin"&gt;make-parameter&lt;/span&gt; &lt;span class="selfeval"&gt;#f&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;;; CONVENIENCE&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;; define db to be short for (current-database)&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt;&lt;br /&gt;  (&lt;span class="keyword"&gt;syntax-id-rules&lt;/span&gt; () [&lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="keyword"&gt;or&lt;/span&gt; (&lt;span class="variable"&gt;current-database&lt;/span&gt;)&lt;br /&gt;                              (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;d&lt;/span&gt; (&lt;span class="variable"&gt;open&lt;/span&gt; &lt;span class="variable"&gt;DATABASE-PATH&lt;/span&gt;)])&lt;br /&gt;                                (&lt;span class="variable"&gt;current-database&lt;/span&gt; &lt;span class="variable"&gt;d&lt;/span&gt;)&lt;br /&gt;                                &lt;span class="variable"&gt;d&lt;/span&gt;))]))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;;; DATABASE CREATION&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;create-table-entries&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;exec/ignore&lt;/span&gt;&lt;br /&gt;   &lt;span class="variable"&gt;db&lt;/span&gt;&lt;br /&gt;   &lt;span class="selfeval"&gt;#&amp;lt;&amp;lt;SQL&lt;/span&gt;&lt;br /&gt; &lt;span class="variable"&gt;CREATE&lt;/span&gt; &lt;span class="variable"&gt;TABLE&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt; (&lt;br /&gt;   &lt;span class="variable"&gt;entry_id&lt;/span&gt;  &lt;span class="variable"&gt;INTEGER&lt;/span&gt; &lt;span class="variable"&gt;PRIMARY&lt;/span&gt; &lt;span class="variable"&gt;KEY&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class="variable"&gt;title&lt;/span&gt;     &lt;span class="variable"&gt;TEXT&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class="variable"&gt;url&lt;/span&gt;       &lt;span class="variable"&gt;TEXT&lt;/span&gt;&lt;span class="keyword"&gt;,&lt;/span&gt;&lt;br /&gt;   &lt;span class="variable"&gt;score&lt;/span&gt;     &lt;span class="variable"&gt;INTEGER&lt;/span&gt; )&lt;br /&gt;&lt;span class="variable"&gt;SQL&lt;/span&gt;&lt;br /&gt;   ))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;drop-table-entries&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;exec/ignore&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; &lt;span class="selfeval"&gt;"DROP TABLE entries"&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;; DATABASE INSERTION AND UPDATES&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;insert-entry&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;insert&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;INSERT&lt;/span&gt; &lt;span class="variable"&gt;INTO&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt; (&lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="builtin"&gt;VALUES&lt;/span&gt; (&lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;score&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;increase-score&lt;/span&gt; &lt;span class="variable"&gt;entry-id&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;update&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;UPDATE&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;&lt;br /&gt;                          &lt;span class="variable"&gt;SET&lt;/span&gt; (&lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;                          &lt;span class="variable"&gt;WHERE&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;entry-id&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;decrease-score&lt;/span&gt; &lt;span class="variable"&gt;entry-id&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;update&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;UPDATE&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;&lt;br /&gt;                          &lt;span class="variable"&gt;SET&lt;/span&gt; (&lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;                          &lt;span class="variable"&gt;WHERE&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;entry-id&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;;; DATABASE RETRIEVAL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;top&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;select&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;SELECT&lt;/span&gt; (&lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="variable"&gt;FROM&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;&lt;br /&gt;                          &lt;span class="variable"&gt;ORDER-BY&lt;/span&gt; (&lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="variable"&gt;DESC&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="variable"&gt;LIMIT&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;&lt;span class="variable"&gt;n&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;page&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;select&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;SELECT&lt;/span&gt; (&lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="variable"&gt;FROM&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;&lt;br /&gt;                          &lt;span class="variable"&gt;ORDER-BY&lt;/span&gt; (&lt;span class="variable"&gt;score&lt;/span&gt; &lt;span class="variable"&gt;DESC&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="variable"&gt;LIMIT&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="variable"&gt;PAGE-LIMIT&lt;/span&gt;) &lt;span class="variable"&gt;OFFSET&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;*&lt;/span&gt; (&lt;span class="variable"&gt;PAGE-LIMIT&lt;/span&gt;) &lt;span class="variable"&gt;n&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;entries-with-url&lt;/span&gt; &lt;span class="variable"&gt;url-str&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;select&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; (&lt;span class="variable"&gt;sql&lt;/span&gt; (&lt;span class="variable"&gt;SELECT&lt;/span&gt; (&lt;span class="variable"&gt;entry_id&lt;/span&gt; &lt;span class="variable"&gt;title&lt;/span&gt; &lt;span class="variable"&gt;url&lt;/span&gt; &lt;span class="variable"&gt;score&lt;/span&gt;)&lt;br /&gt;                          &lt;span class="variable"&gt;FROM&lt;/span&gt; &lt;span class="variable"&gt;entries&lt;/span&gt;&lt;br /&gt;                          &lt;span class="variable"&gt;WHERE&lt;/span&gt; &lt;span class="keyword"&gt;,&lt;/span&gt;(&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="selfeval"&gt;"url='~a'"&lt;/span&gt; &lt;span class="variable"&gt;url-str&lt;/span&gt;)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;url-in-db?&lt;/span&gt; &lt;span class="variable"&gt;url-str&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;result&lt;/span&gt; (&lt;span class="variable"&gt;entries-with-url&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; &lt;span class="variable"&gt;url-str&lt;/span&gt;)])&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;null?&lt;/span&gt; (&lt;span class="variable"&gt;entries-with-url&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; &lt;span class="variable"&gt;url-str&lt;/span&gt;))&lt;br /&gt;        &lt;span class="selfeval"&gt;#f&lt;/span&gt;&lt;br /&gt;        &lt;span class="variable"&gt;result&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;;;; INITIALIZATION&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;; on first run, create tables&lt;br /&gt;&lt;/span&gt;  (&lt;span class="keyword"&gt;unless&lt;/span&gt; (&lt;span class="keyword"&gt;and&lt;/span&gt; (&lt;span class="builtin"&gt;file-exists?&lt;/span&gt; &lt;span class="variable"&gt;DATABASE-PATH&lt;/span&gt;)&lt;br /&gt;             (&lt;span class="variable"&gt;table-exists?&lt;/span&gt; &lt;span class="variable"&gt;db&lt;/span&gt; &lt;span class="selfeval"&gt;"'entries'"&lt;/span&gt;))&lt;br /&gt;  (&lt;span class="variable"&gt;create-table-entries&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="variable"&gt;current-database&lt;/span&gt; (&lt;span class="builtin"&gt;make-parameter&lt;/span&gt; (&lt;span class="variable"&gt;open&lt;/span&gt; &lt;span class="variable"&gt;DATABASE-PATH&lt;/span&gt;)))))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-208531338554508101?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/208531338554508101/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=208531338554508101' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/208531338554508101'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/208531338554508101'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2007/01/introduction-to-web-development-with.html' title='An Introduction to Web Development with PLT Scheme'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-116679050096434202</id><published>2006-12-22T12:15:00.000+01:00</published><updated>2006-12-22T13:28:20.993+01:00</updated><title type='text'>A self-evaluating evaluator</title><content type='html'>December is always a busy month, so the number of blog posts have been low for a while. To make up for it, I have been digging in the archives and found a  self-evaluating evaluator. &lt;a href="http://rondam.blogspot.com/"&gt;Erann Gat&lt;/a&gt; back in 2002 asked the following question in comp.lang.scheme:&lt;br /&gt;&lt;span class="fixed_width"  style="font-family:Courier,Monospaced;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span class="fixed_width"  style="font-family:Courier,Monospaced;"&gt;The topic of self-generating programs (a program whose output is itself) comes up periodically here, but I've never seen the topic of a self-evaluating program discussed.  Of course, meta-circular interpreters are ubiquitous, but the usual metacircular interpreter you find in textbooks typically evaluates a slightly different dialect than it is actually written in.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;My question is: what is the shortest meta-circular &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; interpreter that is actually capable of evaluating itself?&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;It was quite fun to write a short meta-circular interpreter. The shortness-constraint creates a tension between powerful constructs and easily-implementable constructs, when choosing language features to include in the language. My solution below has the following features: &lt;br /&gt;&lt;ul&gt;&lt;li&gt;conditional construct&lt;/li&gt;&lt;li&gt;functions (of one argument)&lt;/li&gt;&lt;li&gt;application&lt;/li&gt;&lt;li&gt;quotation&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;This set of features is pretty minimal. The requirement that the evaluator must be self-evaluating means, it must be possible to pass the code of the evaluator to the evaluator, so quotation is just the right tool. Note that variable assignment (set!) is missing.&lt;br /&gt;&lt;br /&gt;Since only functions of one argument is supported, it is necessary to curry the normal Scheme functions in the initial environment given to the evaluator. This can be seen in the following version of factorial:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; Support code for fak-example&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;plus&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;) (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;) (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;mult&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;) (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;) (&lt;span class="builtin"&gt;*&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;one?&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;) (&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="builtin"&gt;sub1&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="builtin"&gt;-&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;f&lt;/span&gt;)&lt;br /&gt;               (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt;                 (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;                   [(&lt;span class="variable"&gt;one?&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)  &lt;span class="selfeval"&gt;1&lt;/span&gt;]&lt;br /&gt;                   [&lt;span class="selfeval"&gt;#t&lt;/span&gt;        ((&lt;span class="variable"&gt;mult&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) ((&lt;span class="variable"&gt;f&lt;/span&gt; &lt;span class="variable"&gt;f&lt;/span&gt;) (&lt;span class="builtin"&gt;sub1&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)))]))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt;) &lt;span class="selfeval"&gt;5&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The standard definition of factorial is recursive. The chosen languages supports neither recursive bindings nor assignment, so instead we use the same trick, the Y-combinator uses. To calculate factorial of 5, one must write: ((fact fact) 5).&lt;br /&gt;&lt;br /&gt;Since the evaluator must be self-evaluating, the definition of the evaluator uses the same trick as the factorial example. To call the evaluator on the factorial program, one writes:&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;And if we want to let the evaluator evaluate &lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="variable"&gt;jas-eval&lt;/span&gt; (&lt;span class="variable"&gt;fak&lt;/span&gt; &lt;span class="selfeval"&gt;5&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;) &lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;we write&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;fac-code&lt;/span&gt;)) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;(((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;After posting version 1 of the evaluator, &lt;a href="http://home.comcast.net/~prunesquallor/"&gt;Joe Marshall&lt;/a&gt; asked a very interesting question:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;For the sake of curiosity, how much slower is the extra interpretation layer?&lt;br /&gt;&lt;br /&gt;Can you go another level deeper? &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The timings on my current computer is as follows:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;; jas-eval evaluating "(fact 5)"&lt;br /&gt;cpu time: 0 real time: 0 gc time: 0&lt;br /&gt;120&lt;br /&gt;; jas-eval evaluating "(jas-eval (fact 5))"&lt;br /&gt;cpu time: 15 real time: 16 gc time: 0&lt;br /&gt;120&lt;br /&gt;; jas-eval evaluating "(jas-eval (jas-eval (fact 5)))"&lt;br /&gt;cpu time: 922 real time: 954 gc time: 0&lt;br /&gt;120&lt;br /&gt;; jas-eval evaluating "(jas-eval (jas-eval (jas-eval (fact 5))))"&lt;br /&gt;cpu time: 63891 real time: 66109 gc time: 12122&lt;br /&gt;120&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Exponential regression reveals the slow down to be 65 per level (R squared is 0.9999).&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="comment"&gt;; Self evaluating evaluator, version 2&lt;br /&gt;&lt;/span&gt;&lt;span class="comment"&gt;; Jens Axel Soegaard, oct 2002&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;first&lt;/span&gt; &lt;span class="builtin"&gt;car&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;second&lt;/span&gt; &lt;span class="builtin"&gt;cadr&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;third&lt;/span&gt; &lt;span class="builtin"&gt;caddr&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;rest&lt;/span&gt; &lt;span class="builtin"&gt;cdr&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; Support code for fak-example&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;plus&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;) (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;) (&lt;span class="builtin"&gt;+&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;mult&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;) (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;) (&lt;span class="builtin"&gt;*&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;one?&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt;) (&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="builtin"&gt;sub1&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) (&lt;span class="builtin"&gt;-&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;f&lt;/span&gt;)&lt;br /&gt;                (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt;                  (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;                    [(&lt;span class="variable"&gt;one?&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)  &lt;span class="selfeval"&gt;1&lt;/span&gt;]&lt;br /&gt;                    [&lt;span class="selfeval"&gt;#t&lt;/span&gt;        ((&lt;span class="variable"&gt;mult&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;) ((&lt;span class="variable"&gt;f&lt;/span&gt; &lt;span class="variable"&gt;f&lt;/span&gt;) (&lt;span class="builtin"&gt;sub1&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)))]))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt; &lt;span class="variable"&gt;fact&lt;/span&gt;) &lt;span class="selfeval"&gt;5&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; Conventions:  n name, v value, r environment, e expression&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;ev&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;e&lt;/span&gt;)&lt;br /&gt;       (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;r&lt;/span&gt;)&lt;br /&gt;         (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;           [(&lt;span class="builtin"&gt;symbol?&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)      (&lt;span class="variable"&gt;r&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)]&lt;br /&gt;           [(&lt;span class="builtin"&gt;not&lt;/span&gt; (&lt;span class="builtin"&gt;pair?&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))  &lt;span class="variable"&gt;e&lt;/span&gt;]&lt;br /&gt;           [(&lt;span class="builtin"&gt;pair?&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)        (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;                               [((&lt;span class="variable"&gt;ceq?&lt;/span&gt; (&lt;span class="variable"&gt;first&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt;)  (&lt;span class="variable"&gt;first&lt;/span&gt; (&lt;span class="variable"&gt;rest&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))]&lt;br /&gt;                               [((&lt;span class="variable"&gt;ceq?&lt;/span&gt; (&lt;span class="variable"&gt;first&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;cond&lt;/span&gt;)&lt;br /&gt;                                (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;                                  [(((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) (&lt;span class="variable"&gt;first&lt;/span&gt; (&lt;span class="variable"&gt;second&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))) &lt;span class="variable"&gt;r&lt;/span&gt;)  (((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) (&lt;span class="variable"&gt;second&lt;/span&gt; (&lt;span class="variable"&gt;second&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))) &lt;span class="variable"&gt;r&lt;/span&gt;)]&lt;br /&gt;                                  [&lt;span class="selfeval"&gt;#t&lt;/span&gt;                                (((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) ((&lt;span class="variable"&gt;ccons&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;cond&lt;/span&gt;) (&lt;span class="variable"&gt;rest&lt;/span&gt; (&lt;span class="variable"&gt;rest&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)))) &lt;span class="variable"&gt;r&lt;/span&gt;)])]&lt;br /&gt;                               [((&lt;span class="variable"&gt;ceq?&lt;/span&gt; (&lt;span class="variable"&gt;first&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)) &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;lambda&lt;/span&gt;)              (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;x&lt;/span&gt;)&lt;br /&gt;                                                                       (((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) (&lt;span class="variable"&gt;third&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))&lt;br /&gt;                                                                        (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;n&lt;/span&gt;)&lt;br /&gt;                                                                          (&lt;span class="keyword"&gt;cond&lt;/span&gt;&lt;br /&gt;                                                                            [((&lt;span class="variable"&gt;ceq?&lt;/span&gt; (&lt;span class="variable"&gt;first&lt;/span&gt; (&lt;span class="variable"&gt;second&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;))) &lt;span class="variable"&gt;n&lt;/span&gt;)   &lt;span class="variable"&gt;x&lt;/span&gt;]&lt;br /&gt;                                                                            [&lt;span class="selfeval"&gt;#t&lt;/span&gt;                           (&lt;span class="variable"&gt;r&lt;/span&gt; &lt;span class="variable"&gt;n&lt;/span&gt;)]))))]&lt;br /&gt;                               [&lt;span class="selfeval"&gt;#t&lt;/span&gt;                                   ((((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) (&lt;span class="variable"&gt;first&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)) &lt;span class="variable"&gt;r&lt;/span&gt;)&lt;br /&gt;                                                                      (((&lt;span class="variable"&gt;ev&lt;/span&gt; &lt;span class="variable"&gt;ev&lt;/span&gt;) (&lt;span class="variable"&gt;second&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;)) &lt;span class="variable"&gt;r&lt;/span&gt;))])])))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; setup initial environment;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment"&gt;; currying the primitives used in the evaluator&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;ceq?&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="builtin"&gt;eq?&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; (&lt;span class="variable"&gt;ccons&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;lambda&lt;/span&gt; (&lt;span class="variable"&gt;b&lt;/span&gt;)&lt;br /&gt;    (&lt;span class="builtin"&gt;cons&lt;/span&gt; &lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;initial-env&lt;/span&gt; &lt;span class="builtin"&gt;eval&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; use Scheme-eval to get jas-eval&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt; (&lt;span class="builtin"&gt;eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;initial-env&lt;/span&gt; &lt;span class="builtin"&gt;eval&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; use jas-eval to evaluate (fact 5)&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt;)&lt;br /&gt;(&lt;span class="keyword"&gt;time&lt;/span&gt; (((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; use jas-eval to evaluate (jas-eval (fact 5) initial-env)&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt;)) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;span class="comment"&gt;;expression&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;time&lt;/span&gt; (((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; use jas-eval to evaluate (jas-eval (jas-eval (fact 5) initial-env))&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt;))  &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt;)) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;span class="comment"&gt;;expression&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;time&lt;/span&gt; (((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; use jas-eval to evaluate (jas-eval (jas-eval (jas-eval (fact 5) initial-env)))&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;fact-code&lt;/span&gt;))  &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt;)) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;(&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt; &lt;span class="variable"&gt;code-jas-eval&lt;/span&gt;) (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="keyword"&gt;quote&lt;/span&gt; &lt;span class="variable"&gt;expression&lt;/span&gt;)) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;span class="comment"&gt;;expression&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;time&lt;/span&gt; (((&lt;span class="variable"&gt;jas-eval&lt;/span&gt; &lt;span class="variable"&gt;jas-eval&lt;/span&gt;) &lt;span class="variable"&gt;expression&lt;/span&gt;) &lt;span class="variable"&gt;initial-env&lt;/span&gt;))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-116679050096434202?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/116679050096434202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=116679050096434202' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116679050096434202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116679050096434202'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/12/self-evaluating-evaluator.html' title='A self-evaluating evaluator'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-116587387687920842</id><published>2006-12-11T21:31:00.000+01:00</published><updated>2006-12-11T22:51:16.913+01:00</updated><title type='text'>Random Number Generation</title><content type='html'>The &lt;a href="http://schemecookbook.org/"&gt;Scheme Cookbook&lt;/a&gt; has a few recipes on random number generation. Why not turn them into a library?&lt;br /&gt;&lt;br /&gt;Once upon a time I got bitten by the random number generation bug and did just that. I wrote large parts of the random.plt library available through &lt;a href="http://planet.plt-scheme.org"&gt;PLaneT&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;"Huh - where exactly?", I hear you say. Well, the library were submitted when PLaneT were in its infancy, so it appears under the 2xx-page. After two major updates since the 200-series no one checks the old libraries (not even the &lt;a href="http://ja.soegaard.net/planet/html/"&gt;PLT Source Browser&lt;/a&gt;), so not surprisingly the random number library is forgotten.&lt;br /&gt;&lt;br /&gt;After "porting" (well, I *did* change a single line) it is now available again.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://ja.soegaard.net/planet/html/schematics/random.plt/current/doc.txt"&gt;documentation&lt;/a&gt; contains the gory details, so I'll just give a few examples:&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="keyword"&gt;require&lt;/span&gt; (&lt;span class="variable"&gt;planet&lt;/span&gt; &lt;span class="selfeval"&gt;"random.ss"&lt;/span&gt; (&lt;span class="selfeval"&gt;"schematics"&lt;/span&gt; &lt;span class="selfeval"&gt;"random.plt"&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; Good old Gaussian distribution&lt;br /&gt;&lt;/span&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;random-gaussian&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;0.7386912134436788&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; A "stochastic variable"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="keyword"&gt;define&lt;/span&gt; &lt;span class="variable"&gt;X&lt;/span&gt; (&lt;span class="variable"&gt;random-source-make-gaussians&lt;/span&gt; &lt;span class="variable"&gt;default-random-source&lt;/span&gt;))&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;X&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;0.5826066449247809&lt;/span&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;X&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;0.7865269446783535&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;; Other stuff&lt;br /&gt;&lt;/span&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;random-gamma&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;0.013863292728449427&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;random-permutation&lt;/span&gt; &lt;span class="selfeval"&gt;5&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;#5&lt;/span&gt;(&lt;span class="selfeval"&gt;3&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt; &lt;span class="selfeval"&gt;2&lt;/span&gt; &lt;span class="selfeval"&gt;4&lt;/span&gt; &lt;span class="selfeval"&gt;0&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="variable"&gt;random-chi-square&lt;/span&gt; &lt;span class="selfeval"&gt;1&lt;/span&gt;)&lt;br /&gt;&lt;span class="selfeval"&gt;1.1334523156657883&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The source contains an implementation by Sebastian Egner of a very interesting algorithm. It is the generation of random number following a discrete distribution, which surprisingly can be implemented efficiently.&lt;br /&gt;&lt;verbatim&gt;&lt;br /&gt;&lt;/verbatim&gt;&lt;div style="text-align: center;"&gt;&lt;verbatim&gt;   (random-source-make-discretes s w)&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      given a source s of random bits in the sense of SRFI-27&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      and a vector w of n &gt;= 1 non-negative real numbers,&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      this procedure constructs and returns a procedure rand&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      such that (rand) returns the next integer x in {0..n-1}&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      from a pseudo random sequence with&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;  &lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;        Pr{x = k} = w[k] / Sum(w[i] : i)&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;  &lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;      for all k in {0..n-1}.&lt;/verbatim&gt;&lt;br /&gt;&lt;verbatim&gt;&lt;/verbatim&gt;&lt;/div&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Think about it - how would you implement it?&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-116587387687920842?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://planet.plt-scheme.org/#random.plt' title='Random Number Generation'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/116587387687920842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=116587387687920842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116587387687920842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116587387687920842'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/12/random-number-generation.html' title='Random Number Generation'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-116406106175764120</id><published>2006-11-20T23:03:00.000+01:00</published><updated>2006-11-20T23:17:41.770+01:00</updated><title type='text'>PLT Scheme version 360</title><content type='html'>There is now a new release of PLT Scheme in town. Download it from your&lt;br /&gt;local &lt;a href="http://download.plt-scheme.org/drscheme/"&gt;bit-pusher&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To me the most exciting feature is Ryan Culpepper's  &lt;a href="http://www.ccs.neu.edu/home/ryanc/macro-stepper/"&gt;macro stepper&lt;/a&gt;, which will be prove to be an invaluable tool when it comes to understanding and debugging macros.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The release announcement:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;PLT Scheme version 360 is now available from&lt;br /&gt;&lt;br /&gt;&lt;a href="http://download.plt-scheme.org/"&gt;  http://download.plt-scheme.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;DrScheme now has a macro stepper that traces through macro expansion step by step.  The graphical display uses colors to illustrate bindings and a side-panel to display additional syntax information.&lt;br /&gt;&lt;br /&gt; For additional information and an illustrated introduction, see &lt;a href="http://www.ccs.neu.edu/home/ryanc/macro-stepper"&gt;    http://www.ccs.neu.edu/home/ryanc/macro-stepper&lt;br /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;PLT Scheme now includes a new "Lazy Scheme" language level, similar to MzScheme (with a few added libraries), but with call-by-need semantics.  There is also a "lazy" collection that can be used to mix lazy code with eager code (put the former in a module that uses&lt;span style="font-family: courier new;"&gt;(lib "lazy.ss" "lazy")&lt;/span&gt; as its language module).&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;New support for prompts and composable continuations, closely resembling Dorai Sitaram's tagged `%' and `fcontrol' operators.  The new "control.ss" library provides implementations of many other delimited-continuation operators, including `prompt', `control', `shift', `reset', `spawn', `splitter', and `cupto'.  Moreover, these operators all work in a reasonable and useful way with each other, with dynamic-wind', and with continuation marks (which can be used for dynamic variables).&lt;br /&gt;&lt;br /&gt; For more information, see Sitaram's papers at &lt;a href="http://www.ccs.neu.edu/scheme/pubs/"&gt;    http://www.ccs.neu.edu/scheme/pubs/&lt;br /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Regexp support now includes the usual collection of "Perl-compatible" features: numeric quantifiers, backreferences, character classes, Unicode predicates, case-insensitive mode, multi-line mode, lookahead, lookbehind, non-backtracking, and conditionals --- all with improved performance.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Compiler improvements include a lambda-lifting pass and better handling of `call-with-values'.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The "readline" collection is now included.  MzScheme cannot load this library by default, since linking to GNU readline would require licensing PLT Scheme under GPL instead of LGPL. However, you can link readline yourself by adding&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    (when (regexp-match? #rx"xterm" (getenv "TERM"))&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    (dynamic-require '(lib "rep.ss" "readline") #f))&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; in your "~/.mzschemerc" to use readline for MzScheme's REPL.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-116406106175764120?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://download.plt-scheme.org/drscheme/' title='PLT Scheme version 360'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/116406106175764120/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=116406106175764120' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116406106175764120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116406106175764120'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/11/plt-scheme-version-360.html' title='PLT Scheme version 360'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-116146454759791722</id><published>2006-10-21T22:20:00.000+02:00</published><updated>2006-10-21T23:04:48.680+02:00</updated><title type='text'>DivaScheme - Structural Editing for DrScheme</title><content type='html'>A small team consisting of  Romain Legendre, Guillaume Marceau, Danny Yoo, Kathi Fisler and Shriram Krishnamurthi have created a set of alternative keybindings for DrScheme.&lt;br /&gt;&lt;br /&gt;DrScheme has always had keybindings that enabled you to work with whole s-expressions. Like Emacs the normal keybindings require a lot of finger gymnastics due to the use of ctrl/alt/shift. Inspired by Vi the DivaScheme bindings are unchorded. Instead of modifier keys, the editor now have two modes: a command/navigation mode and an insert mode. In command mode &lt;span style="font-family:courier new;"&gt;x&lt;/span&gt; is simply bound to cut, where as &lt;span style="font-family:courier new;"&gt;x&lt;/span&gt; in insert mode inserts an &lt;span style="font-family:courier new;"&gt;x&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;DivaScheme has several features that die-hard Emacs-fans will appreciate. For example keyword-completion a la etags from Emacs. The move-by-searching idiom is also supported via the &lt;span style="font-family:courier new;"&gt;s&lt;/span&gt; command.&lt;br /&gt;&lt;br /&gt;It is difficult to explain how the keybindings work in practice, bun fortunately Danny Yoo made this little video to introduce DivaScheme:&lt;br /&gt;&lt;center&gt;&lt;object height="350" width="425"&gt;&lt;br /&gt;&lt;param name="movie" value="http://www.youtube.com/v/GnQV4je9wTQ"&gt;&lt;br /&gt;&lt;param name="wmode" value="transparent"&gt;&lt;br /&gt;&lt;embed src="http://www.youtube.com/v/GnQV4je9wTQ" type="application/x-shockwave-flash" wmode="transparent" height="350" width="425"&gt;&lt;br /&gt;&lt;/embed&gt;&lt;/param&gt;&lt;/param&gt;&lt;/object&gt;&lt;/center&gt;&lt;br /&gt;Read more on the &lt;a href="http://www.cs.brown.edu/research/plt/software/divascheme/"&gt;DivaScheme homepage&lt;/a&gt; and in the &lt;a href="http://www.cs.brown.edu/research/plt/software/divascheme/doc.txt"&gt;DivaScheme documentation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre id="line14"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-116146454759791722?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cs.brown.edu/research/plt/software/divascheme/' title='DivaScheme - Structural Editing for DrScheme'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/116146454759791722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=116146454759791722' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116146454759791722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116146454759791722'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/10/divascheme-structural-editing-for.html' title='DivaScheme - Structural Editing for DrScheme'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-116138687780982071</id><published>2006-10-21T01:27:00.000+02:00</published><updated>2006-10-21T01:31:04.423+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='search engine'/><title type='text'>Scheme Search gets pattern matching</title><content type='html'>This week I had time to work on the search engine again.&lt;br /&gt;&lt;br /&gt;From a user view point the most important change is the addition of pattern matching. Until now it was possible to find all documents, where a particular identifier occurs. If on the other hand you were unsure which identifier to search for, you were out of luck. Now you can search for occurrences of identifiers matching a regular expression.&lt;br /&gt;&lt;br /&gt;Say you vaguely remember someone using a define- something - struct. A pattern match search for &lt;span style="font-weight: bold;"&gt;define &lt;/span&gt;alone gives 6993 hits. But a search for &lt;span style="font-weight: bold;"&gt;define-.*-struct&lt;/span&gt; gives only 22 hits (the first of which contains &lt;span style="font-weight: bold;"&gt;define-serializable-struct)&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The implementation of the pattern matching search is kept very simple. There are only 150.000 search terms, so the naïve approach of simply matching all terms against the pattern one at a time is fast enough. At least for the moment... After the matching terms have been found, they are looked up in the index and finally the list of documents are ranked.&lt;br /&gt;&lt;br /&gt;Under the hood the representation of the lexicon changed from an in-memory hash-table to a disk-based representation. This has two advantages: the web-server uses less memory and the lexicon uses less space on disk (although it resides in-memory, it was read in, when the web-server started). The disadvantage is that searches now requires disk-access. To keep disk access to a minimum, the lexicon is read in blocks of 100 terms, and a few recently used blocks are cached. If there is a need to look up several terms, it is now best to look them up in alphabetical order.&lt;br /&gt;&lt;br /&gt;The plan is to use the disk space saved for more indexes. Perhaps an index over the documentation a la the HelpDesk? Unfortunately I haven't got enough disk-space enough to implement "preview" of search results.&lt;br /&gt;&lt;br /&gt;In other news Google has released their &lt;a href="http://www.google.com/codesearch"&gt;Google Code Search&lt;/a&gt;. It indexes source from Sourceforge, Google Code and other public repositories.&lt;br /&gt;&lt;br /&gt;To search for Scheme source add&lt;br /&gt;&lt;div style="text-align: center;"&gt;        &lt;span style="font-weight: bold;"&gt;file:(.scm|.ss|.sch)&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;to the beginning of your query.&lt;br /&gt;&lt;br /&gt;Try the above and search for "srfi" to see the how many Scheme projects they have found.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-116138687780982071?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.scheme.dk/search-plt/' title='Scheme Search gets pattern matching'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/116138687780982071/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=116138687780982071' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116138687780982071'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/116138687780982071'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/10/scheme-search-gets-pattern-matching.html' title='Scheme Search gets pattern matching'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115920776911356003</id><published>2006-09-25T19:33:00.000+02:00</published><updated>2006-09-25T20:09:29.136+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='search engine'/><title type='text'>PLT Scheme Source Search Goes Live</title><content type='html'>An alpha version of &lt;a href="http://www.scheme.dk/search-plt/"&gt;PLT Scheme Source Search&lt;/a&gt; is now live. There is no bells and whistles, but the basic functionality is there. The source of all &lt;a href="http://planet.plt-scheme.org"&gt;PLaneT&lt;/a&gt; packages and all builtin collections of PLT Scheme are indexed. The results link to the &lt;a href="http://ja.soegaard.net/planet/html/"&gt;PLT Source Browser&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The PLT Scheme Source Search is the place to turn to, if you have questions like:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is &lt;span style="font-family:courier new;"&gt;define&lt;/span&gt; or &lt;span style="font-family:courier new;"&gt;lambda&lt;/span&gt; most popular?&lt;/li&gt;&lt;li&gt;Who has the most &lt;span style="font-family:courier new;"&gt;TODO&lt;/span&gt;s in his source?&lt;/li&gt;&lt;li&gt;Are there any profanity?&lt;/li&gt;&lt;li&gt;Where is an example of &lt;span style="font-family:courier new;"&gt;local-expand&lt;/span&gt;?&lt;/li&gt;&lt;li&gt;Where is &lt;span style="font-family:courier new;"&gt;set!&lt;/span&gt; abused?&lt;/li&gt;&lt;li&gt;Is the number 42 more popular than 13?&lt;/li&gt;&lt;/ul&gt;The development of the search engine is described in these blog posts:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/03/everything-scheme.html"&gt;Why Write a Search Engine?&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/03/crux-of-search-engine.html"&gt;The Crux of a Search Engine&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/04/back-of-envelope.html"&gt;Back of The Envelope&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/04/tokenizing-scheme-source.html"&gt;Tokenizing Scheme Source&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/04/index-construction.html"&gt;Index Construction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/04/reading-and-writing-bits-bit-ioplt.html"&gt;Reading and Writing Bits - bit-io.plt&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/04/compression-integer-encodings.html"&gt;Compression: Integer Encodings&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/05/search-engine-materializes.html"&gt;The Search Engine Materializes&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;The next step in the project is to implement a disc based lexicon. Right now only the index is disc based, where as the lexicon is an in-memory hash table.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115920776911356003?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.scheme.dk/search-plt/' title='PLT Scheme Source Search Goes Live'/><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115920776911356003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115920776911356003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115920776911356003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115920776911356003'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/09/plt-scheme-source-search-goes-live.html' title='PLT Scheme Source Search Goes Live'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115576156785567238</id><published>2006-08-16T22:44:00.000+02:00</published><updated>2006-08-16T22:52:47.856+02:00</updated><title type='text'>Orange Espresso</title><content type='html'>The blog has always needed colors. Today I finally did something about it.&lt;br /&gt;&lt;br /&gt;Thanks to the &lt;a href="http://www.flickr.com"&gt;Flickr&lt;/a&gt; user &lt;a href="http://www.flickr.com/photos/doozzle/"&gt;Doozzle&lt;/a&gt; and his great &lt;a href="http://www.flickr.com/photos/doozzle/34314549/"&gt;shot&lt;/a&gt; of espresso (pun intended). &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;Doozzle:&lt;/span&gt; Ok, this is a detail of the foam the espresso shot left on a transparent cup. Taken with a soft light slightly above and behind the cup.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115576156785567238?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115576156785567238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115576156785567238' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115576156785567238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115576156785567238'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/orange-espresso.html' title='Orange Espresso'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115556400224319461</id><published>2006-08-14T15:37:00.000+02:00</published><updated>2006-08-14T18:12:34.190+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eager comprehension'/><title type='text'>Eager Comprehensions for Black Belts - 4. Advanced Generators</title><content type='html'>&lt;span style="font-weight: bold;"&gt;&lt;span style="font-size:180%;"&gt;4. Advanced Generators&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Local variables&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Consider this scenario, where we want to produce a list of the even results of a long computation:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:list x '(1 2 3 4 5))&lt;br /&gt;          (if (even? (long-computation x)))&lt;br /&gt;          (long-computation x))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The above solution will call long-computation twice with the same value. Introducing a local variable with the &lt;span style="font-family:courier new;"&gt;:let&lt;/span&gt;-generator &lt;span style="font-family:courier new;"&gt;(:let &amp;lt;vars&amp;gt; &amp;lt;expression&amp;gt;)&lt;/span&gt; solves this.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:list x '(1 2 3 4 5))&lt;br /&gt;          (:let r (long-computation x))&lt;br /&gt;          (if (even? r))&lt;br /&gt;          r)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Parallel loops&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The generator &lt;span style="font-family:courier new;"&gt;(:parallel &amp;lt;generator&amp;gt;*)&lt;/span&gt; runs several generators in parallel. It advances its subgenerators in one step.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  (list-ec (:parallel&lt;br /&gt;              (: x '(one two three))&lt;br /&gt;              (: y '(1   2   3)))&lt;br /&gt;           (list x y))             &lt;br /&gt;   ; =&amp;gt; ((one 1) (two 2) (three 3))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;span style="font-family:courier new;"&gt;(:parallel ...)&lt;/span&gt; generator stops, when any of its sub-generators stop.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   (list-ec (:parallel&lt;br /&gt;              (: x '(one two three))&lt;br /&gt;              (: y '(1   2)))&lt;br /&gt;            (list x y))              &lt;br /&gt;   ; =&amp;gt; ((one 1) (two 2))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The generator &lt;span style="font-family:courier new;"&gt;(:while &amp;lt;generator&amp;gt; &amp;lt;expression&amp;gt;)&lt;/span&gt; runs the generator &lt;span style="font-family:courier new;"&gt;&amp;lt;generator&amp;gt;&lt;/span&gt; while &lt;span style="font-family:courier new;"&gt;&amp;lt;expression&amp;gt;&lt;/span&gt; return non-&lt;span style="font-family:courier new;"&gt;#f&lt;/span&gt;. This can be used to stop a generator before it is done.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:while (: i 1 100000)&lt;br /&gt;                  (&amp;lt; i 5))&lt;br /&gt;          i)                      ;=&amp;gt; (1 2 3 4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Since &lt;span style="font-family:courier new;"&gt;:while&lt;/span&gt; stops the inner generator, it is better to use &lt;span style="font-family:courier new;"&gt;:while&lt;/span&gt; than to use a qualifier to skip all values after a certain point. Compare these timings:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (time (sum-ec (:while (: i 1 10000000)&lt;br /&gt;                       (&amp;lt; i 100000))&lt;br /&gt;               i))&lt;br /&gt; ; cpu time: 47 real time: 47 gc time: 0&lt;br /&gt;&lt;br /&gt; #;&lt;br /&gt; (time (sum-ec (: i 1 10000000)&lt;br /&gt;               (if (&amp;lt; i 100000))&lt;br /&gt;               i))&lt;br /&gt; ; cpu time: 3672 real time: 3687 gc time: 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family:courier new;"&gt;:while&lt;/span&gt;-generator tests the expression before advancing the generator. The &lt;span style="font-family:courier new;"&gt;:until&lt;/span&gt;-generator tests after.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:until (: i 1 100000)&lt;br /&gt;                  (= i 5))&lt;br /&gt;          i)                     ;=&amp;gt; (1 2 3 4 5)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The simple :do loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The generator &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; is a "do-while"-generator (it runs while the test is true - in contrast the normal Scheme do operator is a "do-until", it runs until the test becomes true).&lt;br /&gt;&lt;br /&gt;The simple form is &lt;span style="font-family:courier new;"&gt;(:do (&amp;lt;lb&amp;gt;*) &amp;lt;ne1?&amp;gt; (&amp;lt;ls&amp;gt;*))&lt;/span&gt;. Here &lt;span style="font-family:courier new;"&gt;&amp;lt;lb&amp;gt;*&lt;/span&gt; is zero or more loop bindings, &lt;span style="font-family:courier new;"&gt;&amp;lt;ne1?&gt;&lt;/span&gt;; is the "while" expression and determines whether the loop stops. Finally &lt;span style="font-family:courier new;"&gt;&amp;lt;ls&amp;gt;*&lt;/span&gt; are "loop-steppers", expressions whose evaluation results are bound to the loop variables.&lt;br /&gt;&lt;br /&gt;A simple example &lt;span style="font-family:courier new;"&gt;(:do () #f ())&lt;/span&gt; has no loop variables, and stops immediately, since the "while"-expression is &lt;span style="font-family:courier new;"&gt;#f&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:do () #f ())&lt;br /&gt;          1)               ; =&amp;gt; ()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In contrast &lt;span style="font-family:courier new;"&gt;(:do () #t ())&lt;/span&gt; will give an infinite loop.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:do () #t ())&lt;br /&gt;          1)             ; =&amp;gt; loops till ram is exhausted&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;A loop that counts upwards forever: &lt;span style="font-family:courier new;"&gt;(:do ((x 0)) #t ((+ x 1)))&lt;/span&gt;. To test it we put it inside a :while.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:while (:do ((x 0)) #t ((+ x 1)))&lt;br /&gt;                  (&amp;lt; x 5))&lt;br /&gt;          x)                                 &lt;br /&gt;  ;=&amp;gt; (0 1 2 3 4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It is however better to use that &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; is a "do-while".&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(list-ec (:do ((x 0)) (&amp;lt; x 5) ((+ x 1)))&lt;br /&gt;      x)                                  ;=&amp;gt; (0 1 2 3 4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Updating two variables by repeatedly subtracting the smaller from the larger leads to Euclid's algorithm for calculating the greatest common divisor. The &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt;-generator makes it easy to store the intermediate steps in the calculation.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (define (update a b) (if (&amp;lt; a b) a (- a b)))&lt;br /&gt; (list-ec (:do ((x 8333)&lt;br /&gt;                (y 10897))&lt;br /&gt;               (not (= x y))&lt;br /&gt;               ((update x y)&lt;br /&gt;                (update y x)))&lt;br /&gt;          (list x y))&lt;br /&gt;&lt;br /&gt; ; =&amp;gt; ((8333 10897) (8333 2564) (5769 2564) (3205 2564)&lt;br /&gt; ;     (641 2564) (641 1923) (641 1282))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;so the greatest common divisor of 8333 and 10897 is 641.&lt;br /&gt;&lt;br /&gt;Just as in a normal do-loop all the step-expressions are evaluated before they are bound to the loop- variables.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:do ((x 0) (y 1))&lt;br /&gt;               (&amp;lt; x 10)&lt;br /&gt;               (y          ; -&amp;gt; x&lt;br /&gt;                (+ x y)))  ; -&amp;gt; y&lt;br /&gt;            (list x y))&lt;br /&gt;&lt;br /&gt; ; =&amp;gt; ((0 1) (1 1) (1 2) (2 3) (3 5) (5 8) (8 13))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If &lt;span style="font-family:courier new;"&gt;x&lt;/span&gt; had been updated before &lt;span style="font-family:courier new;"&gt;(+ x y)&lt;/span&gt; were evaluated the result  would have been&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;((0 1) (1 2) (2 4) (4 8) (8 16))&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The syntax of the simple :do-generator is&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (:do (&amp;lt;lb&amp;gt;*)    ; loop bindings&lt;br /&gt;      &amp;lt;ne1?&amp;gt;     ; "while"-expression&lt;br /&gt;      (&amp;lt;ls&amp;gt;*))   ; loop-step-expression&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Lets take a look under the hood. [We'll need that later]&lt;br /&gt;&lt;br /&gt;The generator expands to this loop:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(let loop (&amp;lt;lb&amp;gt;*)&lt;br /&gt;  (if &amp;lt;ne1?&amp;gt;&lt;br /&gt;     (let ()&lt;br /&gt;          payload&lt;br /&gt;          (loop &amp;lt;ls&amp;gt;*))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where payload depends on the enclosing comprehension.&lt;br /&gt;&lt;br /&gt;E.g. if the outer comprehension is &lt;span style="font-family:courier new;"&gt;(list-ec (:do ...) x)&lt;/span&gt; then the payload is&lt;span style="font-family:courier new;"&gt; (set! result (cons x result))&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The :do-generator is the one to turn to, if none of the builtin generators suit your needs. However the simple form turns out to be too simple for some cases.&lt;br /&gt;&lt;br /&gt;Consider this attempt to write &lt;span style="font-family:courier new;"&gt;:list&lt;/span&gt; in terms of &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; :&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:do ((xs (list 2 3 4))&lt;br /&gt;                (x 1))&lt;br /&gt;               (not (null? xs))&lt;br /&gt;               ((cdr xs)          ; -&amp;gt; xs&lt;br /&gt;                (car xs)))        ; -&amp;gt; x&lt;br /&gt;          x)&lt;br /&gt; ; =&amp;gt; (1 2 3)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem here is that 4 is missing from the result list.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The advanced :do loop&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This section is for black belts. The advanced &lt;span style="font-family:courier new;"&gt;:d&lt;/span&gt;o generator is meant to be used only by people interested in defining their own custom generators - and even then, in most cases a custom generator can be built without the advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; generator.&lt;br /&gt;&lt;br /&gt;The advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; generator is more flexible than the simple, but requires a little time getting used to. It is worth learning though, as we will se a little later.&lt;br /&gt;&lt;br /&gt;In fact all the pre-defined generators are defined in terms of the advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt;-generator. Let us examine how the &lt;span style="font-family:courier new;"&gt;:list&lt;/span&gt;-generator works.&lt;br /&gt;&lt;br /&gt;The (cleaned up version of) the expansion of&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  (list-ec (: x '(1 2 3 4)) x)&lt;br /&gt;&lt;/pre&gt; is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(reverse&lt;br /&gt;  (let ((result '()))&lt;br /&gt;    (let loop ((t '(1 2 3 4)))&lt;br /&gt;      (if (not (null? t))&lt;br /&gt;        (let ((x (car t)))&lt;br /&gt;          (set! result (cons x result))&lt;br /&gt;          (loop (cdr t)))))&lt;br /&gt;    result))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We notice that &lt;span style="font-family:courier new;"&gt;list-e&lt;/span&gt;c sets up a result list, into which elements are consed using &lt;span style="font-family:courier new;"&gt;(set! result (cons x result))&lt;/span&gt;. When the list is returned it is reversed.&lt;br /&gt;&lt;br /&gt;The loop itself has&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a set of loop-bindings                                    ((t '(1 2 3 4))) &lt;/li&gt;&lt;li&gt;a "while"-expression                                       (not (null? t))&lt;/li&gt;&lt;li&gt;a set of inner bindings                                   ((x (car t)))&lt;/li&gt;&lt;li&gt;a payload from the comprehension   (set! result (cons x result))&lt;/li&gt;&lt;li&gt;a set of loop-step-expressions           (cdr t)&lt;/li&gt;&lt;/ul&gt;The advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt;-generator makes it possible to write loops which has a similar structure.&lt;br /&gt;&lt;br /&gt;The syntax of the advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt; is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (:do (let (&amp;lt;ob&amp;gt;*) &amp;lt;oc&amp;gt;*) (&amp;lt;lb&amp;gt;*) &amp;lt;ne1?&amp;gt; (let (&amp;lt;ib&amp;gt;*) &amp;lt;ic&amp;gt;*) &amp;lt;ne2?&amp;gt; (&amp;lt;ls&amp;gt;*))&lt;br /&gt;&lt;br /&gt;                                     &amp;lt;ob&amp;gt;*  outer bindings&lt;br /&gt;                                     &amp;lt;oc&amp;gt;*  outer commands&lt;br /&gt;(let loop ((t '(1 2 3 4)))              &amp;lt;lb&amp;gt;*  loop bindings&lt;br /&gt;(if (not (null? t))                   &amp;lt;ne1?&amp;gt;&lt;br /&gt;   (let ((x (car t)))                &amp;lt;ib&amp;gt;*  inner bindings&lt;br /&gt;                                     &amp;lt;ic&amp;gt;*  innner commands&lt;br /&gt;     (set! result (cons x result))   payload from comprehension&lt;br /&gt;     (if #t                          &amp;lt;ne2?&amp;gt;&lt;br /&gt;         (loop (cdr t))))))          &amp;lt;ls&amp;gt;*  loop steps&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is &lt;span style="font-family:courier new;"&gt;(list-ec (:list x '(1 2 3 4)) x)&lt;/span&gt; is equivalent to&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (list-ec (:do (let ())&lt;br /&gt;               ((t '(1 2 3 4)))&lt;br /&gt;               (not (null? t))&lt;br /&gt;               (let ((x (car t))))&lt;br /&gt;               #t&lt;br /&gt;               ((cdr t)))&lt;br /&gt;          x)&lt;br /&gt; ; =&amp;gt; (1 2 3 4)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Consider now the expansion of the general&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(:do (let (&amp;lt;ob&amp;gt;*) &amp;lt;oc&amp;gt;*) (&amp;lt;lb&amp;gt;*) &amp;lt;ne1?&amp;gt; (let (&amp;lt;ib&amp;gt;*) &amp;lt;ic&amp;gt;*) &amp;lt;ne2?&amp;gt; (&amp;lt;ls&amp;gt;*))&lt;br /&gt;&lt;br /&gt;(let (&amp;lt;ob&amp;gt;*)&lt;br /&gt;&amp;lt;oc&amp;gt;*&lt;br /&gt;(let loop (&amp;lt;lb&amp;gt;*)&lt;br /&gt; (if &amp;lt;ne1?&amp;gt;&lt;br /&gt;     (let (&amp;lt;ib&amp;gt;*)&lt;br /&gt;       &amp;lt;ic&amp;gt;*&lt;br /&gt;       payload&lt;br /&gt;       (if &amp;lt;ne2?&amp;gt;&lt;br /&gt;           (loop &amp;lt;ls&amp;gt;*) )))))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The outer bindings is used to set up helper variables, before the loop.&lt;br /&gt;&lt;br /&gt;The outer commands for once-only side effects before the loop starts.&lt;br /&gt;&lt;br /&gt;The loop bindings &lt;span style="font-family:courier new;"&gt;&amp;lt;lb&amp;gt;*&lt;/span&gt; are used for variables updated in the loop.&lt;br /&gt;&lt;br /&gt;The before "while"-expression &lt;span style="font-family:courier new;"&gt;&amp;lt;ne1?&amp;gt;&lt;/span&gt; is tested before the payload.&lt;br /&gt;&lt;br /&gt;The inner bindings &lt;span style="font-family:courier new;"&gt;&amp;lt;ib*&amp;gt;&lt;/span&gt; is used to set up temporary variables&lt;br /&gt;for use in the loop body.&lt;br /&gt;&lt;br /&gt;The inner commands &lt;span style="font-family:courier new;"&gt;&amp;lt;ic&amp;gt;*&lt;/span&gt; is used for side effects which is to be&lt;br /&gt;executed in the loop.&lt;br /&gt;&lt;br /&gt;The payload is work to do be done for the comprehension.&lt;br /&gt;&lt;br /&gt;The after "while"-expression &lt;span style="font-family:courier new;"&gt;&amp;lt;ne1?&amp;gt;&lt;/span&gt; is tested after the payload.&lt;br /&gt;&lt;br /&gt;The loop step expressions determine the next value of the loop&lt;br /&gt;variables.&lt;br /&gt;&lt;br /&gt;Lost your breath? Sebastian Egner puts it like this: "The design of :DO is a compromise between how complicated structures can be expressed, while retaining the ability to merge the loops in parallel". The following example will hopefully clear things up. It will later be reused to illustrate how to make a custom generator.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Combinations&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem of generating all k combinations of the n numbers&lt;br /&gt;0,1,...,n-1 provides a nice example of the advanced &lt;span style="font-family:courier new;"&gt;:do&lt;/span&gt;-generator.&lt;br /&gt;The list of 3,5-combinations are&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (#3(0 1 2) #3(0 1 3) #3(0 1 4) #3(0 2 3) #3(0 2 4) #3(0 3 4)&lt;br /&gt;  #3(1 2 3) #3(1 2 4) #3(1 3 4)&lt;br /&gt;  #3(2 3 4))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The first combination is #(0 1 2) and the last combination is #3(2 3 4).&lt;br /&gt;Given helper funcions &lt;span style="font-family:courier new;"&gt;first-combination&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;last-combination?&lt;/span&gt;, and&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;next-combination&lt;/span&gt; we can use the advanced&lt;span style="font-family:courier new;"&gt; :do&lt;/span&gt;-generator as follows.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(list-ec (:do (let ((k 3) (n 5)))&lt;br /&gt;           ((c (first-combination k n)))&lt;br /&gt;           c ; first-combination returns #f if k&amp;lt;=0 or k&amp;gt;n&lt;br /&gt;           (let ())&lt;br /&gt;           (not (last-combination? k n c))&lt;br /&gt;           ((next-combination k n c)))&lt;br /&gt;      c)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here are the helper functions.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(define (vr v i)                  (vector-ref v i))&lt;br /&gt;(define (vs! v i x)               (vector-set! v i x))&lt;br /&gt;(define (incrementable? v i k n)  (&amp;lt; (vr v i) (+ n (- k) i)))&lt;br /&gt;&lt;br /&gt;(define (last-combination? k n v) (= (vr v 0) (- n k)))&lt;br /&gt;&lt;br /&gt;(define (first-combination k n)&lt;br /&gt;(if (&amp;lt;= 1 k n)&lt;br /&gt;   (vector-ec (: i 0 k) i)&lt;br /&gt;   #f))&lt;br /&gt;&lt;br /&gt;(require (lib "43.ss" "srfi")) ; for vector-copy&lt;br /&gt;(define (next-combination k n v)&lt;br /&gt;(last-ec #f ; default, when there is no next combination&lt;br /&gt;        (:let v (vector-copy v))&lt;br /&gt;        ; find the last incrementable index&lt;br /&gt;        (:let i (last-ec #f (:until (: i (- k 1) -1 -1)&lt;br /&gt;                                    (incrementable? v i k n))&lt;br /&gt;                         i))&lt;br /&gt;        (if i)&lt;br /&gt;        ; increment index i and fix indices to the right of i&lt;br /&gt;        (:parallel (: j i k)&lt;br /&gt;                   (: vj (+ (vr v i) 1) n))&lt;br /&gt;        (begin (vs! v j vj))&lt;br /&gt;        ; if all indices is fixed we have a new combination&lt;br /&gt;        (if (= j (- k 1)))&lt;br /&gt;        ; return the new combination&lt;br /&gt;        v))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115556400224319461?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115556400224319461/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115556400224319461' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115556400224319461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115556400224319461'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-4.html' title='Eager Comprehensions for Black Belts - 4. Advanced Generators'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115541282524894527</id><published>2006-08-12T21:47:00.000+02:00</published><updated>2006-08-12T22:14:58.526+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eager comprehension'/><title type='text'>Eager Comprehensions for Black Belts - 3. Multiple generators (nested loops) and qualifiers (filtering)</title><content type='html'>&lt;span style="font-size:180%;"&gt;3. Multiple Generators (nested loops) and qualifiers (filtering)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Comprehensions allow multiple generators. Consider:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    (list-ec (: x 2)&lt;br /&gt;             (: y 3)&lt;br /&gt;             (list x y))   ; =&gt;  ((0 0) (0 1) (0 2)&lt;br /&gt;                           ;      (1 0) (1 1) (1 2))&lt;br /&gt;&lt;/pre&gt;The inner (last) generator spins faster than the outer generator. Since the scope of variables bound by a generator begins after the generator expression, it is possible to refer to variables bound by previous generators.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    (list-ec (: x 3)&lt;br /&gt;             (: y (+ x 1))&lt;br /&gt;             (list x y))     ; =&gt; ((0 0)&lt;br /&gt;                             ;     (1 0) (1 1)&lt;br /&gt;                             ;     (2 0) (2 1) (2 2))&lt;br /&gt;&lt;/pre&gt;At this point we are capable of generating loads of values, but sometimes we want to skip some of them.&lt;br /&gt;&lt;br /&gt;Consider the problem of finding small integers such that:&lt;br /&gt;&lt;pre&gt;  x^2 + y^2 = z^2 .&lt;br /&gt;&lt;/pre&gt;A valid strategy is to let &lt;span style=";font-family:courier new;font-size:100%;"  &gt;x&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;y&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;z&lt;/span&gt; run from, say, 1 to 100, and skip the triples which doesn't fulfill the equation. To mimic this strategy we will use qualifiers.&lt;br /&gt;&lt;br /&gt;The following qualifiers are available for filtering:&lt;br /&gt;&lt;pre&gt;  &lt;br /&gt;    (if  &amp;lt;test&amp;gt;)&lt;br /&gt;    (not &amp;lt;test&amp;gt;*)&lt;br /&gt;    (and &amp;lt;test&amp;gt;*&lt;br /&gt;    (or  &amp;lt;test&amp;gt;*)&lt;br /&gt;&lt;/pre&gt; [Besides the filtering qualifiers all generators, as well as &lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(begin &amp;lt;sequence&amp;gt;)&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;(nested &amp;lt;qualifier&amp;gt;*)&lt;/span&gt; are also qualifiers.]&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    (list-ec (: x 1 100)&lt;br /&gt;             (: y x 100)&lt;br /&gt;             (: z y 100)&lt;br /&gt;             (if (= (+ (* x x) (* y y))&lt;br /&gt;                    (* z z)))&lt;br /&gt;             (list x y z))               ; =&gt; ((3 4 5)&lt;br /&gt;                                         ;     (5 12 13)&lt;br /&gt;                                         ;     (6 8 10)&lt;br /&gt;                                         ;     ...&lt;br /&gt;                                         ;     (60 63 87)&lt;br /&gt;                                         ;     (65 72 97))&lt;br /&gt;&lt;/pre&gt; The common cases &lt;span style="font-family:courier new;"&gt;(if (not &amp;lt;test&amp;gt;))&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;(if (and &amp;lt;test&amp;gt;*))&lt;/span&gt;, and &lt;span style="font-family:courier new;"&gt;(if (or &amp;lt;test&amp;gt;*))&lt;/span&gt; are abbreviated by (not &amp;lt;test&amp;gt;), &lt;span style="font-family:courier new;"&gt;(and &amp;lt;test&amp;gt;*)&lt;/span&gt;, and &lt;span style="font-family:courier new;"&gt;(or &amp;lt;test&amp;gt;*)&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;    &lt;br /&gt;    (list-ec (: x 1 4)&lt;br /&gt;             (: y 1 4)&lt;br /&gt;             (not (= x y))&lt;br /&gt;             (list x y))    ; =&amp;gt; ((1 2) (1 3)&lt;br /&gt;                            ;     (2 1) (2 3)&lt;br /&gt;                            ;     (3 1) (3 2))&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115541282524894527?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115541282524894527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115541282524894527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115541282524894527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115541282524894527'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-3.html' title='Eager Comprehensions for Black Belts - 3. Multiple generators (nested loops) and qualifiers (filtering)'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115512025246485641</id><published>2006-08-09T12:23:00.000+02:00</published><updated>2006-08-09T12:44:12.540+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eager comprehension'/><title type='text'>Eager Comprehensions for Black Belts - 2. Basic Comprehensions</title><content type='html'>&lt;span style="font-size:180%;"&gt;2. Basic Comprehensions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Comprehensions accumulate the values generated into a result. So far the only comprehension used have been &lt;span style="font-family:courier new;"&gt;list-ec&lt;/span&gt;. There are multiple comprehensions to choose from, when deciding how to accumulate the computed values.&lt;br /&gt;&lt;br /&gt;The comprehensions &lt;span style="font-family:courier new;"&gt;vector-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;string-ec&lt;/span&gt; are analogous to &lt;span style="font-family:courier new;"&gt;list-ec&lt;/span&gt;. The accumulated values of &lt;span style="font-family:courier new;"&gt;string-ec&lt;/span&gt; must all be characters.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; (vector-ec (: i 5)&lt;br /&gt;            i)                    ; =&amp;gt; #5(0 1 2 3 4)&lt;br /&gt;&lt;br /&gt; (string-ec (: c '(#\c #\a #\r))&lt;br /&gt;            c)                    ;=&amp;gt; "car"&lt;br /&gt;&lt;/pre&gt;If the length of the result vector is known ahead of time, one can use &lt;span style="font-family:courier new;"&gt;vector-of-length-ec&lt;/span&gt;, which is more efficient than vector-ec.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   (vector-of-length-ec 3 (: x 3)&lt;br /&gt;                          x)        ; =&amp;gt; #3(0 1 2)&lt;br /&gt;&lt;/pre&gt;Instead of first generating a list of lists, or a list of strings and then applying append or &lt;span style="font-family:courier new;"&gt;string-append&lt;/span&gt;, it is more convenient to use &lt;span style="font-family:courier new;"&gt;append-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;string-append-ec&lt;/span&gt;.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   (append-ec (: x '((1 2) (3 4 5) (6)))&lt;br /&gt;               x)                          ; =&amp;gt; (1 2 3 4 5 6)&lt;br /&gt;&lt;br /&gt;   (string-append-ec (: x '("foo" "bar" "qux"))&lt;br /&gt;                     x)                   ; =&amp;gt; "foobarqux"&lt;br /&gt;&lt;/pre&gt;The comprehensions &lt;span style="font-family:courier new;"&gt;sum-ec&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;product-ec&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;min-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;max-ec&lt;/span&gt; work on numbers.&lt;br /&gt;&lt;pre&gt;    &lt;br /&gt;    (sum-ec (: x '(1 2 3 4))&lt;br /&gt;            x)                     ;=&amp;gt; 10&lt;br /&gt;&lt;br /&gt;    (product-ec (: x '(1 2 3 4))&lt;br /&gt;                x)                 ; =&amp;gt; 24&lt;br /&gt;&lt;br /&gt;    (min-ec (: x '(1 2 3 4))&lt;br /&gt;             x)                    ; =&amp;gt; 1&lt;br /&gt;&lt;br /&gt;    (max-ec (: x '(1 2 3 4))&lt;br /&gt;             x)                    ; =&amp;gt; 4&lt;br /&gt;&lt;/pre&gt;For &lt;span style="font-family:courier new;"&gt;min-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;max-ec&lt;/span&gt; the the generated sequence of values must be non-empty.&lt;br /&gt;&lt;br /&gt;There are two boolean comprehensions &lt;span style="font-family:courier new;"&gt;any?-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;every?-ec&lt;/span&gt;. They test whether at-least-one or all of the computed values were true.&lt;br /&gt;&lt;pre&gt;   &lt;br /&gt;    (every?-ec (: x 1 10)&lt;br /&gt;               (even? x))   ; =&amp;gt; #f&lt;br /&gt;&lt;br /&gt;    (any?-ec (: x 1 10)&lt;br /&gt;             (even? x))     ; =&amp;gt; #t&lt;br /&gt;&lt;/pre&gt;Note:  &lt;span style="font-family:courier new;"&gt;any?-ec&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;every?-ec &lt;/span&gt;(just as their cousins &lt;span style="font-family:courier new;"&gt;or&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;and)&lt;/span&gt; are "early stopping". As soon as &lt;span style="font-family:courier new;"&gt;any?-ec &lt;/span&gt;encounters a &lt;span style="font-family:courier new;"&gt;#t&lt;/span&gt; it stops. &lt;span style="font-family:courier new;"&gt;every?-ec &lt;/span&gt; stops when a &lt;span style="font-family:courier new;"&gt;#f&lt;/span&gt; is seen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115512025246485641?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115512025246485641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115512025246485641' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115512025246485641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115512025246485641'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-2.html' title='Eager Comprehensions for Black Belts - 2. Basic Comprehensions'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115503300167970489</id><published>2006-08-08T12:24:00.000+02:00</published><updated>2006-08-09T12:21:59.153+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eager comprehension'/><title type='text'>Eager Comprehensions for Black Belts - 1. Basic Generators</title><content type='html'>&lt;span style="font-size:180%;"&gt;1. Basic Generators&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Range generators&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A generator binds a variable (or more) to a sequence of values.&lt;br /&gt;&lt;br /&gt;The generator &lt;span style="font-family:courier new;"&gt;:range&lt;/span&gt; is used to generate the values of a numerical range. The simplest form is &lt;span style="font-family:courier new;"&gt;(:range &amp;lt;vars&amp;gt; &amp;lt;stop&amp;gt;)&lt;/span&gt; which generates the values 0, 1, ..., &lt;span style="font-family:courier new;"&gt;&amp;lt;stop&amp;gt;&lt;/span&gt;-1.&lt;br /&gt;&lt;pre&gt;    (list-ec (:range i 5)&lt;br /&gt;          i)              ; =&amp;gt; (0 1 2 3 4)&lt;br /&gt;&lt;/pre&gt;The form &lt;span style="font-family:courier new;"&gt;(:range &amp;lt;vars&amp;gt; &amp;lt;start&amp;gt; &amp;lt;stop&amp;gt;)&lt;/span&gt; is used when the&lt;br /&gt;start value is different from 0.&lt;br /&gt;&lt;pre&gt;   (list-ec (:range i 3 7)&lt;br /&gt;           i)              ; =&amp;gt; (3 4 5 6)&lt;br /&gt;&lt;/pre&gt;The form &lt;span style="font-family:courier new;"&gt;(:range &amp;lt;vars&amp;gt; &amp;lt;start&amp;gt; &amp;lt;stop&amp;gt; &amp;lt;step&amp;gt;)&lt;/span&gt; allows other step sizes than +1.&lt;br /&gt;&lt;pre&gt;   (list-ec (:range i 0 8 2)&lt;br /&gt;          i)              ; =&amp;gt; (0 2 4 6)&lt;br /&gt;&lt;br /&gt; (list-ec (:range i 0 9 2)&lt;br /&gt;          i)              ; =&amp;gt; (0 2 4 6 8)&lt;br /&gt;&lt;/pre&gt;The generator stops when &lt;span style="font-family:courier new;"&gt;&amp;lt;stop&amp;gt;&lt;/span&gt; is reached or crossed. This rule also applies when the step size is negative:&lt;br /&gt;&lt;pre&gt;   (list-ec (:range i 5 0 -1)&lt;br /&gt;          i)                  ; =&amp;gt; (5 4 3 2 1)&lt;br /&gt;&lt;/pre&gt;Note that &lt;span style="font-family:courier new;"&gt;:range&lt;/span&gt; works for integers only, simple stepping leads to accumulation of rounding errors when using reals. To  generate a sequence of reals, use &lt;span style="font-family:courier new;"&gt;:real-range&lt;/span&gt; instead. It calculates the value from the index.&lt;br /&gt;&lt;pre&gt;   (list-ec (:real-range i 0 2 0.5)&lt;br /&gt;          i)                       ; =&amp;gt; (0.0 0.5 1.0 1.5)&lt;br /&gt;&lt;/pre&gt;The special generator &lt;span style="font-family:courier new;"&gt;:&lt;/span&gt; which uses the types of its arguments to dispatch to various generators, uses &lt;span style="font-family:courier new;"&gt;:range&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;:real-range&lt;/span&gt; when given numerical arguments.&lt;br /&gt;&lt;pre&gt;   (list-ec (: i 5 0 -1)&lt;br /&gt;          i)             ; =&amp;gt; (5 4 3 2 1)&lt;br /&gt;&lt;br /&gt; (list-ec (: i 0 2 0.5)&lt;br /&gt;          i)             ; =&amp;gt; (0.0 0.5 1.0 1.5)&lt;br /&gt;&lt;/pre&gt;The dispatch happens at run time, so &lt;span style="font-family:courier new;"&gt;:&lt;/span&gt; is slightly slower than using &lt;span style="font-family:courier new;"&gt;:range&lt;/span&gt; directly.&lt;br /&gt;&lt;br /&gt;[See also :integers and :char-range]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Element generators&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A very common use of generators is to run through the elements of a data structure such as a list, a string or a vector.&lt;br /&gt;&lt;br /&gt;The simplest form of &lt;span style="font-family:courier new;"&gt;:list&lt;/span&gt; runs through the elements of a list.&lt;br /&gt;&lt;pre&gt;   (list-ec (:list x '(1 2 3))&lt;br /&gt;          (* x 2))                        ; (2 4 6)&lt;br /&gt;&lt;/pre&gt;It is possible to run through more than one list at a time:&lt;br /&gt;&lt;pre&gt;   (list-ec (:list x '(1 2) '(3 4) '(5 6))&lt;br /&gt;          (* x 2))                        ; =&amp;gt; (2 4 6 8 10 12)&lt;br /&gt;&lt;/pre&gt;The generators &lt;span style="font-family:courier new;"&gt;:vector&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;:string&lt;/span&gt; works in the same way, but on vectors and strings.&lt;br /&gt;&lt;pre&gt;   (list-ec (:vector x '#(1 2 3))&lt;br /&gt;           x)                            ; =&amp;gt; (1 2 3)&lt;br /&gt;&lt;br /&gt; (list-ec (:string x "abc" "def")&lt;br /&gt;          x)                       ; =&amp;gt; (#\a #\b #\c #\d #\e #\f)&lt;br /&gt;&lt;/pre&gt;The dispatching generators uses &lt;span style="font-family:courier new;"&gt;:list&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;:vector&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;:strings&lt;/span&gt;, when the type of its arguments are lists, vectors and strings respectively.&lt;br /&gt;&lt;pre&gt;   (list-ec (: x '(1 2 3))&lt;br /&gt;          (* x 2))           ; =&amp;gt; (2 4 6)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;Scope of variables bound by a generator&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A variable bound by a generator can be used after the closing parenthesis of the generator expression and extends to the end of the comprehension.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115503300167970489?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115503300167970489/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115503300167970489' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115503300167970489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115503300167970489'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-1.html' title='Eager Comprehensions for Black Belts - 1. Basic Generators'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-115503263371580954</id><published>2006-08-08T12:14:00.000+02:00</published><updated>2006-08-14T18:14:59.813+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eager comprehension'/><title type='text'>Eager Comprehensions for Black Belts - An SRFI 42 Tutorial</title><content type='html'>Eager comprehensions from &lt;a href="http://srfi.schemers.org/srfi-42/srfi-42.html"&gt;SRFI-42&lt;/a&gt; provide a convenient notation for writing loops generating a sequence of values, and optionally accumulating the values into a result. Inspired by Peter Seibel's chapter "LOOP for Black Belts" in "Practical Common Lisp" the following is an attempt to show the utility of eager comprehensions.&lt;br /&gt;&lt;br /&gt;Eager comprehensions (think: loops) can sequentially bind variables to numbers in a numerical range&lt;ul&gt;&lt;li&gt;sequentially bind variables to elements in a data structure&lt;/li&gt;&lt;li&gt;execute arbitrary Scheme expressions&lt;/li&gt;&lt;li&gt;conditionally perform parts of the loop&lt;/li&gt;&lt;/ul&gt;An eager comprehension consists normally of 3 components:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;a comprehension, that accumulates the result&lt;/li&gt;&lt;li&gt;some generators, that produces sequences of values&lt;/li&gt;&lt;li&gt;an expression that uses the generated values, to&lt;br /&gt;compute a value, the comprehension can accumulate&lt;/li&gt;&lt;/ul&gt;This sounds worse than it is, so consider the example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(require (lib "42.ss" "srfi"))&lt;br /&gt;(list-ec (: i 5)&lt;br /&gt;        (* i 2))&lt;br /&gt;; =&amp;gt; (0 2 4 6 8)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The generator &lt;span style="font-family:courier new;"&gt;(: i 5)&lt;/span&gt; binds in turn &lt;span style="font-family:courier new;"&gt;i&lt;/span&gt; to 0, 1, 2, 3, and 4.&lt;br /&gt;The expression &lt;span style="font-family:courier new;"&gt;(* i 2)&lt;/span&gt; is evaluated for each binding of &lt;span style="font-family:courier new;"&gt;i&lt;/span&gt;.&lt;br /&gt;The computed values 0, 2, 4, 6 and 8 are accumulated by the comprehension &lt;span style="font-family:courier new;"&gt;list-ec&lt;/span&gt;. The list comprehension &lt;span style="font-family:courier new;"&gt;list-ec &lt;/span&gt;accumulates the computed values into a list.&lt;br /&gt;&lt;br /&gt;The master plan is now as follows:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-1.html"&gt;Basic generators&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-2.html"&gt;Basic comprehensions&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-3.html"&gt;Multiple generators (nested loops) and qualifiers (filtering)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts-4.html"&gt;Advanced Generators&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Multiple accumulators&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Defining custom comprehensions&lt;/li&gt;&lt;/ol&gt;Expect one post a day.&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://srfi.schemers.org/srfi-42/srfi-42.html"&gt;SRFI 42&lt;/a&gt; by &lt;a href="http://www.sebastian-egner.net/"&gt;Sebastian Egner&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://repository.readscheme.org/ftp/papers/sw2005/egner.pdf" name="Search..."&gt;"Eager Comprehensions in Scheme: The design of SRFI-42"&lt;/a&gt;&lt;span style="text-decoration: underline;"&gt;&lt;/span&gt; by &lt;a href="http://www.sebastian-egner.net/"&gt;Sebastian Egner&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-115503263371580954?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/115503263371580954/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=115503263371580954' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115503263371580954'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/115503263371580954'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/08/eager-comprehensions-for-black-belts.html' title='Eager Comprehensions for Black Belts - An SRFI 42 Tutorial'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-24975746.post-114911716949989868</id><published>2006-05-31T23:47:00.000+02:00</published><updated>2006-06-01T01:22:31.323+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='macro'/><title type='text'>How to Write an Unhygienic Macro - Introducing an Identifier Into the Lexical Context of a Macro Call</title><content type='html'>The standard syntax-rules macro system of R5RS Scheme is &lt;span style="FONT-STYLE: italic"&gt;hygienic&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;If a macro transformer inserts a binding for an identifier (variable or keyword), the identifier will in effect be renamed throughout its scope to avoid conflicts with other identifiers. &lt;/blockquote&gt;and &lt;span style="FONT-STYLE: italic"&gt;referentially transparent&lt;/span&gt;&lt;br /&gt;&lt;blockquote&gt;If a macro transformer inserts a free reference to an identifier, the reference refers to the binding that was visible where the transformer was specified, regardless of any local bindings that may surround the use of the macro.&lt;br /&gt;&lt;/blockquote&gt;These properties of the macro system make the majority of macros easy to write and understand. In some situations it is nevertheless convenient to break the rules. A classic example is the &lt;span style="font-family:courier new;"&gt;if-it&lt;/span&gt; macro.&lt;br /&gt;&lt;blockquote&gt;Syntax: &lt;span style="font-family:courier new;"&gt;(if-it test consequent alternative)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Semantics: An &lt;span style="font-family:courier new;"&gt;if-it&lt;/span&gt; expression is evaluated as follows: first, &lt;span style="font-family:courier new;"&gt;test&lt;/span&gt; is evaluated and its result is bound to it. If the result is a true value, then &lt;span style="font-family:courier new;"&gt;consequent&lt;/span&gt; is evaluated and its value(s) is(are) returned. Otherwise &lt;alternate&gt;is evaluated and its value(s) is(are) returned. In &lt;span style="font-family:courier new;"&gt;consequent&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;alternative&lt;/span&gt; references to it will be bound to the it inserted by if-it.&lt;br /&gt;&lt;br /&gt;Examples:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(if-it 1 it 'bomb) ; =&gt; 1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;(let ((it 'bomb)) (if-it 1 it it)) ; =&gt; 1&lt;/span&gt;&lt;br /&gt;&lt;/alternate&gt;&lt;/blockquote&gt;It isn't too difficult to write such a macro with the syntax-case macro system. It is however a little tricky to ensure the resulting if-it macro can be used by other macros without knowledge of how if-it is implemented - at least until one discovers the following easy-to-use technique.&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;  (&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;  (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; ()&lt;br /&gt;    [(&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; &lt;span class="variable"&gt;e3&lt;/span&gt;)&lt;br /&gt;     (&lt;span class="keyword"&gt;with-syntax&lt;/span&gt; ([&lt;span class="variable"&gt;it&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-local-introduce&lt;/span&gt;&lt;br /&gt;                        (&lt;span class="builtin"&gt;syntax-local-get-shadower&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;it&lt;/span&gt;))])&lt;br /&gt;       &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;])&lt;br /&gt;           (&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; &lt;span class="variable"&gt;e3&lt;/span&gt;)))]))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;The solution uses two seldomly used functions namely &lt;span style="font-family:courier new;"&gt;syntax-local-introduce&lt;/span&gt; and &lt;span style="font-family:courier new;"&gt;syntax-local-get-shadower&lt;/span&gt;. The last of these are relatively unknown - a search reveals it is only used four times in total in the PLT code base - therefore a quote from the documentation is in order.&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-family:courier new;"&gt;(syntax-local-get-shadower identifier)&lt;/span&gt; returns &lt;span style="font-family:courier new;"&gt;identifier&lt;/span&gt; if no binding in the current expansion context shadows identifier, if &lt;span style="font-family:courier new;"&gt;identifier&lt;/span&gt; has no module context, and if the current expansion context is not a module. If a binding of &lt;span style="font-family:courier new;"&gt;inner-identifier&lt;/span&gt; shadows &lt;span style="font-family:courier new;"&gt;identifier&lt;/span&gt;, the result is the same as &lt;span style="font-family:courier new;"&gt;(syntax-local-get-shadower inner-identifier)&lt;/span&gt;, except that it has the location and properties of &lt;span style="font-family:courier new;"&gt;identifier&lt;/span&gt;. Otherwise, the result is the same as &lt;span style="font-family:courier new;"&gt;identifier&lt;/span&gt; with its module context (if any) removed and the current module context (if any) added. Thus, the result is an identifier corresponding to the innermost shadowing of identifier in the current context if its shadowed, and a module-contextless version of identifier otherwise.&lt;br /&gt;&lt;/blockquote&gt;In short &lt;span class="builtin"  style="font-family:courier new;"&gt;syntax-local-get-shadower&lt;/span&gt; allows the macro writer to break referential transparency. The call &lt;span style="font-family:courier new;"&gt;(&lt;/span&gt;&lt;span class="builtin"  style="font-family:courier new;"&gt;syntax-local-get-shadower&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;&lt;span class="selfeval"  style="font-family:courier new;"&gt;#&lt;/span&gt;&lt;span class="keyword"  style="font-family:courier new;"&gt;'&lt;/span&gt;&lt;span class="variable"  style="font-family:courier new;"&gt;it&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;)&lt;/span&gt; will return the identifier to which &lt;span style="font-family:courier new;"&gt;it&lt;/span&gt; is bound at the site of the macro call (and not at the site of definition).&lt;br /&gt;&lt;br /&gt;Inserting the result of &lt;span style="font-family:courier new;"&gt;(&lt;/span&gt;&lt;span class="builtin"  style="font-family:courier new;"&gt;syntax-local-get-shadower&lt;/span&gt;&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;&lt;span class="selfeval"  style="font-family:courier new;"&gt;#&lt;/span&gt;&lt;span class="keyword"  style="font-family:courier new;"&gt;'&lt;/span&gt;&lt;span class="variable"  style="font-family:courier new;"&gt;it&lt;/span&gt;&lt;span style="font-family:courier new;"&gt;)&lt;/span&gt;directly into the template of if-it won't work as expected though. The macro system is hygienic by default, so the identifier will subjected to renaming and will therefore not bind uses at the call site. Preventing renaming is easy though, just call &lt;span style="font-family:courier new;"&gt;syntax-local-introduce&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;To test that if-it behaves properly when used in the definition of other macros and also works with the module system I used the following tests. The four tests all return &lt;span style="font-family:courier new;"&gt;#t&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="scheme"&gt;&lt;pre&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;mod-if-it&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;provide&lt;/span&gt; &lt;span class="variable"&gt;if-it&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; ()&lt;br /&gt;     [(&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; &lt;span class="variable"&gt;e3&lt;/span&gt;)&lt;br /&gt;      (&lt;span class="keyword"&gt;with-syntax&lt;/span&gt; ([&lt;span class="variable"&gt;it&lt;/span&gt; (&lt;span class="builtin"&gt;syntax-local-introduce&lt;/span&gt;&lt;br /&gt;                         (&lt;span class="builtin"&gt;syntax-local-get-shadower&lt;/span&gt; &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;it&lt;/span&gt;))])&lt;br /&gt;        &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ([&lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="variable"&gt;e1&lt;/span&gt;])&lt;br /&gt;            (&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="variable"&gt;e2&lt;/span&gt; &lt;span class="variable"&gt;e3&lt;/span&gt;)))])))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;module&lt;/span&gt; &lt;span class="variable"&gt;mod-cond-it&lt;/span&gt; &lt;span class="variable"&gt;mzscheme&lt;/span&gt;&lt;br /&gt; (&lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;mod-if-it&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;provide&lt;/span&gt; &lt;span class="variable"&gt;cond-it&lt;/span&gt;)&lt;br /&gt; (&lt;span class="keyword"&gt;define-syntax&lt;/span&gt; (&lt;span class="variable"&gt;cond-it&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt;)&lt;br /&gt;   (&lt;span class="keyword"&gt;syntax-case&lt;/span&gt; &lt;span class="variable"&gt;stx&lt;/span&gt; (&lt;span class="variable"&gt;else&lt;/span&gt;)&lt;br /&gt;     [(&lt;span class="variable"&gt;cond-it&lt;/span&gt;)&lt;br /&gt;      &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="builtin"&gt;void&lt;/span&gt;)]&lt;br /&gt;     [(&lt;span class="variable"&gt;cond-it&lt;/span&gt; [&lt;span class="variable"&gt;else&lt;/span&gt; &lt;span class="variable"&gt;e&lt;/span&gt;])&lt;br /&gt;      &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;e&lt;/span&gt;]&lt;br /&gt;     [(&lt;span class="variable"&gt;cond-it&lt;/span&gt; [&lt;span class="variable"&gt;q1&lt;/span&gt; &lt;span class="variable"&gt;a1&lt;/span&gt;] &lt;span class="variable"&gt;more&lt;/span&gt; ...)&lt;br /&gt;      &lt;span class="selfeval"&gt;#&lt;/span&gt;&lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="variable"&gt;q1&lt;/span&gt; &lt;span class="variable"&gt;a1&lt;/span&gt; (&lt;span class="variable"&gt;cond-it&lt;/span&gt; &lt;span class="variable"&gt;more&lt;/span&gt; ...))])))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;mod-cond-it&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;(&lt;span class="variable"&gt;cond-it&lt;/span&gt;&lt;br /&gt;[&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt;]&lt;br /&gt;[&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;nope&lt;/span&gt;])&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="selfeval"&gt;42&lt;/span&gt;))&lt;br /&gt; (&lt;span class="variable"&gt;cond-it&lt;/span&gt;&lt;br /&gt;  [&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt;]&lt;br /&gt;  [&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;nope&lt;/span&gt;]))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;if-it&lt;/span&gt; &lt;span class="selfeval"&gt;43&lt;/span&gt;))&lt;br /&gt; (&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;it&lt;/span&gt; &lt;span class="selfeval"&gt;42&lt;/span&gt;))&lt;br /&gt;   (&lt;span class="variable"&gt;cond-it&lt;/span&gt;&lt;br /&gt;    [&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt;]&lt;br /&gt;    [&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;nope&lt;/span&gt;])))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;require&lt;/span&gt; &lt;span class="variable"&gt;mod-if-it&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;equal?&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;((&lt;span class="variable"&gt;b&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt;) (&lt;span class="variable"&gt;y&lt;/span&gt; &lt;span class="variable"&gt;z&lt;/span&gt;))&lt;br /&gt;        (&lt;span class="variable"&gt;cond-it&lt;/span&gt;&lt;br /&gt;         [(&lt;span class="builtin"&gt;memq&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;b&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;a&lt;/span&gt; &lt;span class="variable"&gt;b&lt;/span&gt; &lt;span class="variable"&gt;c&lt;/span&gt;))&lt;br /&gt;          (&lt;span class="keyword"&gt;let&lt;/span&gt; ((&lt;span class="variable"&gt;it0&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt;))&lt;br /&gt;            (&lt;span class="variable"&gt;if-it&lt;/span&gt; (&lt;span class="builtin"&gt;memq&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;y&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;(&lt;span class="variable"&gt;x&lt;/span&gt; &lt;span class="variable"&gt;y&lt;/span&gt; &lt;span class="variable"&gt;z&lt;/span&gt;))&lt;br /&gt;                   (&lt;span class="builtin"&gt;list&lt;/span&gt; &lt;span class="variable"&gt;it0&lt;/span&gt; &lt;span class="variable"&gt;it&lt;/span&gt;)&lt;br /&gt;                   &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;nope0&lt;/span&gt;))]&lt;br /&gt;         [&lt;span class="selfeval"&gt;#t&lt;/span&gt; &lt;span class="keyword"&gt;'&lt;/span&gt;&lt;span class="variable"&gt;nope1&lt;/span&gt;]))&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/24975746-114911716949989868?l=www.scheme.dk%2Fblog%2Findex.html' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/114911716949989868/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=24975746&amp;postID=114911716949989868' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/114911716949989868'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/24975746/posts/default/114911716949989868'/><link rel='alternate' type='text/html' href='http://www.scheme.dk/blog/2006/05/how-to-write-unhygienic-macro.html' title='How to Write an Unhygienic Macro - Introducing an Identifier Into the Lexical Context of a Macro Call'/><author><name>Jens Axel Søgaard</name><uri>http://www.blogger.com/profile/15211030864341077735</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='00040562269191626540'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry></feed>