<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8288194986820249216</id><updated>2012-01-26T16:15:27.177-08:00</updated><category term='C#'/><category term='DotNet'/><category term='Windows'/><category term='ActiveScripting'/><category term='Lisp'/><category term='CLOS'/><title type='text'>Abstract Heresies</title><subtitle type='html'>Unorthodox opinions on computer science and programming.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default?start-index=101&amp;max-results=100'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>354</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8550473143881422377</id><published>2012-01-19T09:11:00.000-08:00</published><updated>2012-01-19T09:11:27.265-08:00</updated><title type='text'>A bit more challenging</title><content type='html'>In my &lt;a href="http://funcall.blogspot.com/2012/01/slightly-trickier.html"&gt;previous post&lt;/a&gt;, I gave the puzzle of taking a pattern and generating code that matches it.  The tricky part was making sure that the pattern is completely traversed at compile time.  If the object to be tested matches the pattern, the pattern variables and their values were to be returned in an alist.&lt;br /&gt;
&lt;br /&gt;
It would be better, however, to generate code where the pattern variables become &lt;em&gt;bindings&lt;/em&gt; of Scheme variables.  Instead of generating code that stuffs the values into an alist, like this code does at the highlighted points:
&lt;br /&gt;
&lt;pre&gt;(make-matcher '(&lt;span style="background-color: lime;"&gt;(? one)&lt;/span&gt; and &lt;span style="background-color: lime;"&gt;(? two)&lt;/span&gt;)) =&amp;gt;

(lambda (object)
  (and (pair? object)
       (let ((left-submatch
              ((lambda (object) &lt;span style="background-color: lime;"&gt;(list (cons 'one object))&lt;/span&gt;) (car object)))
             (right-submatch
              ((lambda (object)
                 (and (pair? object)
                      (let ((left-submatch
                             ((lambda (object)
                                (and (eqv? object 'and)
                                     '()))
                              (car object)))
                            (right-submatch
                             ((lambda (object)
                                (and (pair? object)
                                     (let ((left-submatch
                                            ((lambda (object)
                                               &lt;span style="background-color: lime;"&gt;(list (cons 'two object))&lt;/span&gt;)
                                             (car object)))
                                           (right-submatch
                                            ((lambda (object)
                                               (and (eqv? object '())
                                                    '()))
                                             (cdr object))))
                                       (and left-submatch
                                            right-submatch
                                            (append left-submatch
                                                    right-submatch)))))
                              (cdr object))))
                        (and left-submatch
                             right-submatch
                             (append left-submatch right-submatch)))))
               (cdr object))))
         (and left-submatch
              right-submatch
              (append left-submatch right-submatch)))))&lt;/pre&gt;
We'd generate something more like this:
&lt;br /&gt;
&lt;pre&gt;(make-matcher '(&lt;span style="background-color: lime;"&gt;(? one)&lt;/span&gt; and &lt;span style="background-color: lime;"&gt;(? two)&lt;/span&gt;) &lt;i&gt;&lt;span style="background-color: yellow;"&gt;&amp;lt;user code goes here&amp;gt;&lt;/span&gt;&lt;/i&gt;) =&amp;gt;

(lambda (object)
  (and (pair? object)
       (let (&lt;span style="background-color: lime;"&gt;(one (car object)&lt;/span&gt;)
             (tail1 (cdr object)))
         (and (pair? tail1)
              (eq? (car tail1) 'and)
              (let ((tail2 (cdr tail1)))
                (and (pair? tail2)
                     (let (&lt;span style="background-color: lime;"&gt;(two (car tail2)&lt;/span&gt;))
                       (and (null? (cdr tail2))
                            &lt;span style="background-color: yellow;"&gt;&lt;i&gt;&amp;lt;user code goes here&amp;gt;&lt;/i&gt;&lt;/span&gt;))))))))
&lt;/pre&gt;
This is more challenging for two reasons.  First, we need to ensure that the pattern variable names become bound in a scope that encloses the user's code so that free references to pattern variables are correctly captured.  In addition, we need to ensure that other &amp;ldquo;helper&amp;rdquo; bindings, like &lt;code&gt;tail1&lt;/code&gt; and &lt;code&gt;tail2&lt;/code&gt; do &lt;em&gt;not&lt;/em&gt; capture free references by accident. (That is to say, watch your macro hygiene.)  Second, you have to be sure that subpattern bindings are visible to the entire body of the user code.  This will throw a monkey wrench into the simple recursive solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8550473143881422377?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8550473143881422377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8550473143881422377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8550473143881422377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8550473143881422377'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2012/01/bit-more-challenging.html' title='A bit more challenging'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2495765392912469456</id><published>2012-01-15T11:38:00.000-08:00</published><updated>2012-01-15T11:38:35.382-08:00</updated><title type='text'>Slightly trickier</title><content type='html'>In my &lt;a href="http://funcall.blogspot.com/2012/01/small-puzzle.html"&gt;previous post&lt;/a&gt;, I gave a small pattern matching problem.  It is easily solved by recursively descending the pattern and the object to match.  This is analogous to interpreting the pattern because you walk the pattern each time you want to try to match an object.&lt;br /&gt;&lt;br /&gt;
If the pattern is constant, though, you can walk the pattern once and generate code that can match against an object much more quickly:
&lt;pre&gt;(define my-matcher
  (eval (make-matcher '(a (? var1) (nested (c (? var2)))))
        user-initial-environment))

(my-matcher '(a b (nested (c d)))) =&gt; ((var1 . b) (var2 . d))&lt;/pre&gt;
I'd rate this as an intermediate puzzle.  It isn't very different from the previous one, but you have to pay more attention to the &lt;i&gt;phase&lt;/i&gt; of evaluation.  As a hint, here are a pair of possible matchers:
&lt;pre&gt;(make-matcher '((? car) . (? cdr))) =&gt;

(lambda (object)
  (and (pair? object)
       (let ((p1 ((lambda (object) (list (cons 'car object))) (car object)))
             (p2 ((lambda (object) (list (cons 'cdr object))) (cdr object))))
         (and p1
              p2
              (append p1 p2)))))

(make-matcher '((? one) and (? two))) =&gt;

(lambda (object)
  (and (pair? object)
       (let ((left-submatch
              ((lambda (object) (list (cons 'one object))) (car object)))
             (right-submatch
              ((lambda (object)
                 (and (pair? object)
                      (let ((left-submatch
                             ((lambda (object)
                                (and (eqv? object 'and)
                                     '()))
                              (car object)))
                            (right-submatch
                             ((lambda (object)
                                (and (pair? object)
                                     (let ((left-submatch
                                            ((lambda (object)
                                               (list (cons 'two object)))
                                             (car object)))
                                           (right-submatch
                                            ((lambda (object)
                                               (and (eqv? object '())
                                                    '()))
                                             (cdr object))))
                                       (and left-submatch
                                            right-submatch
                                            (append left-submatch
                                                    right-submatch)))))
                              (cdr object))))
                        (and left-submatch
                             right-submatch
                             (append left-submatch right-submatch)))))
               (cdr object))))
         (and left-submatch
              right-submatch
              (append left-submatch right-submatch)))))

&lt;/pre&gt;
Astute readers will notice that this latter matcher is doing more work than necessary.  If the match against part of the pattern fails, it still attempts to match the rest of the pattern.  It only notices just before assembling the final result.  Also, using &lt;code&gt;append&lt;/code&gt; to assemble the sub-matches is a terrible waste.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2495765392912469456?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2495765392912469456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2495765392912469456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2495765392912469456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2495765392912469456'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2012/01/slightly-trickier.html' title='Slightly trickier'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1763307296244377465</id><published>2012-01-13T08:53:00.000-08:00</published><updated>2012-01-13T08:53:25.947-08:00</updated><title type='text'>A small puzzle</title><content type='html'>Here's a quick little puzzle that isn't too hard.&lt;br /&gt;&lt;br /&gt;

A &lt;i&gt;pattern&lt;/i&gt; is:
&lt;ol&gt;&lt;li&gt;A symbol, number, boolean, or null (an atom).&lt;/li&gt;
&lt;li&gt;A &lt;i&gt;pattern variable&lt;/i&gt;, which is a two element list where the
   first element is the symbol &lt;code&gt;?&lt;/code&gt; and the second is a symbolic (a
   symbol) name.
&lt;pre&gt;;;   Examples:
;;     (pattern-variable? '(? foo))                      =&gt; #t
;;     (pattern-variable? '(? another-pattern-variable)) =&gt; #t
;;
;;     (pattern-variable? '(not a (pattern variable)))   =&gt; #f
;;     (pattern-variable? '(?))                          =&gt; #f
;;     (pattern-variable? '(foo ?))                      =&gt; #f
;;     (pattern-variable? '(? foo . bar))                =&gt; #f
;;     (pattern-variable? '(? foo quux))                 =&gt; #f

(define (pattern-variable? thing)
  (and (pair? thing)
       (eq? (car thing) '?)
       (pair? (cdr thing))
       (symbol? (cadr thing))
       (null? (cddr thing))))&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;A pair (a &lt;code&gt;cons&lt;/code&gt;) of two patterns.&lt;/li&gt;&lt;/ol&gt;

Write a program that given a pattern and some list structure (an object composed of
pairs, numbers, symbols, nulls, etc.) returns an association
list (an &lt;code&gt;alist&lt;/code&gt;) of the pattern variable names and
the associated matching elements, or &lt;code&gt;#F&lt;/code&gt; if the
pattern does not match.
&lt;pre&gt;;;  Examples:
;;   (pmatch '(foo (? pvar1) (? pvar2) bar) '(foo 33 #f bar))
;;      =&gt; ((pvar2 . #f) (pvar1 . 33))
;;
;;   (pmatch '(foo (? pvar) bar) '(quux 33 bar))
;;      =&gt; #f
;;
;;   (pmatch '(a (? var1) (nested (c (? var2)))) '(a b (nested (c d))))
;;      =&gt; ((var2 . d) (var1 . b))
;;
;;  Edge cases:
;;
;;   (pmatch '(a b c) '(a b c))
;;      =&gt; '()
;;
;;   (pmatch '(foo (? pvar1) (? pvar2) bar) '(foo 33 (xyzzy #f) bar))
;;      =&gt; ((pvar2 xyzzy #f) (pvar1 . 33))
;;
;;   (pmatch '(foo . (? pvar)) '(foo bar baz))
;;      =&gt; ((pvar bar baz))
;;
;;   (pmatch '((? ?) quux) '(foo quux))
;;      =&gt; ((? . foo))
;;
;;   (pmatch '(? ?) '(foo quux))
;;      =&gt; ((? foo quux))
;;
;;   (pmatch '(? ? ?) '(foo quux))
;;      =&gt; #f&lt;/pre&gt;

&lt;i&gt;Please be careful and obfuscate your solution if you want to post it.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1763307296244377465?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1763307296244377465/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1763307296244377465' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1763307296244377465'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1763307296244377465'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2012/01/small-puzzle.html' title='A small puzzle'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6800872612857911948</id><published>2011-11-23T12:21:00.000-08:00</published><updated>2011-11-23T12:21:44.176-08:00</updated><title type='text'></title><content type='html'>Imagine that we have a boatload of memory and we're nowhere near the
limit.  Suppose, too, that we allocate memory simply by bumping the
free pointer.  If you think about it, you can see that the age of the
most recently allocated objects is simply the distance between the
object's location and the current value of the free pointer.  Little's
Law tells us that mean age of a heap allocated object is equal to the
mean size of the reachable heap, so it must be the case that the mean
distance from the reachable objects to the free pointer is also equal
to the mean size of the heap (blah, blah, satisfy boundary conditions,
blah, in the limit, etc.)&lt;br /&gt;&lt;br /&gt;
A few weeks ago, someone asked about the improvement in locality that one may get from the garbage collector.  The vast majority of objects don't survive even a single garbage collection, so the vast majority of objects are layed out in memory exactly where they were consed and cannot benefit from any improvement in locality.  This is not to say that there is no effect at all, but that the effect doesn't apply to the vast majority of objects.&lt;br /&gt;&lt;br /&gt;
Someone also asked what the GC pauses were.  With a large heap (131072 blocks), the total time for MIT/GNU Scheme compiling itself was 167.7 seconds runtime, 1.06 second GC time.  This comes out to about 22 milliseconds per GC.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6800872612857911948?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6800872612857911948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6800872612857911948' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6800872612857911948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6800872612857911948'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/11/imagine-that-we-have-boatload-of-memory.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5030129076410081145</id><published>2011-11-18T18:05:00.000-08:00</published><updated>2011-11-18T18:05:52.468-08:00</updated><title type='text'>Little's Law and the weak generational hypothesis</title><content type='html'>&lt;b&gt;Theorem:&lt;/b&gt;   &lt;i&gt;The mean lifetime of a heap allocated object is equal to the mean amount of reachable storage.&lt;/i&gt;&lt;br /&gt;
Proof:  This is Little's Law with λ=1.&lt;br /&gt;
&lt;br /&gt;
This turns out to be a pretty handy theorem.  Here's an example.&lt;br /&gt;
&lt;br /&gt;
In a &lt;a href="http://funcall.blogspot.com/2011/10/garbage-collection-gives-us-illusion-of.html"&gt;prior post&lt;/a&gt;, I mentioned that a prerequisite for effective garbage collection is that the amount of reachable storage must at all times be less than the amount of memory available for the heap.  We apply Little's Law and get this:  The mean lifetime of a heap allocated object must be less than the time it takes to exhaust the heap.&lt;br /&gt;
&lt;br /&gt;
That naturally follows:  in order for garbage collection to “work”, we need &lt;em&gt;something&lt;/em&gt; to become garbage before we completely run out of memory.  But Little's Law allows us to make a much stronger statement.  The mean lifetime of &lt;em&gt;all&lt;/em&gt; objects (where lifetime is measured in subsequent allocations), is, by Little's Law, equal to the mean size of reachable storage.  The mean size of the reachable storage has to be less than the amount of memory available for the heap.  Since the mean lifetime of an object must be small, and we have the occasional very long-lived object, it must be the case that the vast majority of objects have very short lifetimes.  Or in other words,
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
Most allocated objects die young.&lt;/div&gt;&lt;br /&gt;
This statement is often called the &lt;em&gt;weak generational hypothesis&lt;/em&gt;.  It is usually presented as an empirical observation.  By Little's Law, it is equivalent to saying that the size of the reachable objects is small, which is not a hypothesis, but a strong pre-condition of garbage collection.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5030129076410081145?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5030129076410081145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5030129076410081145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5030129076410081145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5030129076410081145'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/11/littles-law-and-weak-generational.html' title='Little&apos;s Law and the weak generational hypothesis'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8776795663892788377</id><published>2011-11-16T18:28:00.000-08:00</published><updated>2011-11-17T17:23:24.346-08:00</updated><title type='text'>Little's Law and Lisp</title><content type='html'>We model the Lisp heap as a queuing system.
&lt;br /&gt;
&lt;blockquote&gt;
A “queuing system” consists of discrete objects we shall call “items” that “arrive” at
some rate to the “system.”  Within the system the items may form one or more queues
and eventually receive “service” and exit. &lt;br /&gt;&lt;span style="text-align: center;"&gt;-- &lt;i&gt;Graves and Little in&amp;nbsp;&lt;u&gt;Building Intuition: Insights from Basic Operations Management Models and Principles&lt;/u&gt;, edited by D. Chhajed and T. J. Lowe, Springer Science+Business Media, LLC, New York, 2008&lt;/i&gt;&lt;/span&gt;&lt;/blockquote&gt;
Our discrete objects are the objects returned by &lt;code&gt;cons&lt;/code&gt;, &lt;code&gt;make-vector&lt;/code&gt;, &lt;code&gt;make-string&lt;/code&gt;, and the other primitive constructors.  The heap is where these objects wait, and the objects &amp;ldquo;exit&amp;rdquo; the system when they become unreachable.&lt;br /&gt;
We can now apply Little's Law:
&lt;div style="text-align: center;"&gt;
L=λW
&lt;/div&gt;
We will assign λ, the average number of items arriving per unit time, to 1.  In other words, we normalize time to be equal to the allocation rate.  Little's Law simplifies to:
&lt;div style="text-align: center;"&gt;
L/λ=W &lt;i&gt;(when λ is 1)&lt;/i&gt;&lt;br /&gt;
L=W 
&lt;/div&gt;
We let L, average number of items in the queuing system, be the size of the heap in allocation units.  W, the average waiting time in the system for an item, is therefore the mean lifetime of an object.  Provided that we meet the necessary boundary conditions:
&lt;b&gt;The mean lifetime of a heap allocated object is equal to the mean size of the reachable heap.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;
We are measuring object lifetime in `allocations'.  If desired, we could measure the allocation rate in units of time, and then we would get the object lifetime also in units of time.  Instead, we are determining the average number of word allocations that occur before an object becomes unreachable.&lt;br /&gt;&lt;br /&gt;
The boundary conditions for Little's Law are quite lax.  If the heap begins  and ends empty we can satisfy them.  The heap naturally starts empty, and when a program ends, we discard the heap, so we can pretend it is empty again. (This puts an upper limit on the lifetime of all objects.)  As I noted in a previous post, the mean heap size for MIT/GNU Scheme compiling itself is about 300,000 words.  Therefore, the mean object lifetime is 300,000 word allocations.&lt;br /&gt;&lt;br /&gt;
I will expand on this in the next post...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8776795663892788377?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8776795663892788377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8776795663892788377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8776795663892788377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8776795663892788377'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/11/littles-law-and-lisp.html' title='Little&apos;s Law and Lisp'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-855128973461239165</id><published>2011-11-15T16:22:00.000-08:00</published><updated>2011-11-15T16:22:50.686-08:00</updated><title type='text'>Little's Law</title><content type='html'>In Chapter 5 of &lt;u&gt;Building Intuition: Insights from Basic Operations Management Models and Principles&lt;/u&gt;, edited by D. Chhajed and T. J. Lowe, Springer Science+Business Media, LLC, New York, 2008, &lt;a href="http://web.mit.edu/sgraves/www/"&gt;Steven Graves&lt;/a&gt; and &lt;a href="http://www.blogger.com/sloancf.mit.edu/vpf/popup-if.cfm?in_spseqno=69&amp;amp;co_list=F"&gt;John Little&lt;/a&gt; discuss &lt;a href="http://web.mit.edu/sgraves/www/papers/Little's%20Law-Published.pdf"&gt;Little's Law&lt;/a&gt;:
&lt;br /&gt;
&lt;blockquote&gt;
A “queuing system” consists of discrete objects we shall call “items” that “arrive” at
some rate to the “system.”  Within the system the items may form one or more queues
and eventually receive “service” and exit.&lt;/blockquote&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-vtE9BbrI8uE/TsGde-h2DxI/AAAAAAAABmQ/Gn-V1U_8HzQ/s1600/QueuingSystem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="76" src="http://1.bp.blogspot.com/-vtE9BbrI8uE/TsGde-h2DxI/AAAAAAAABmQ/Gn-V1U_8HzQ/s400/QueuingSystem.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote&gt;
Little's Law says that, under steady state conditions, the average number of
items in a queuing system equals the average rate at which items arrive multiplied
by the average time that an item spends in the system. Letting&lt;br /&gt;&lt;br /&gt;
L = average number of items in the queuing system,&lt;br /&gt;
W = average waiting time in the system for an item, and&lt;br /&gt;
λ = average number of items arriving per unit time, the law is&lt;/blockquote&gt;
&lt;div style="text-align: center;"&gt;
L=λW
&lt;/div&gt;
Graves and Little give several examples, and I'll paraphrase one here.
&lt;blockquote&gt;
Caroline is a wine buff.  Her wine rack in the cellar holds 240 bottles.  She seldom fills the rack to the top but sometimes after a good party the
rack is empty. On average it seems to be about 2/3rds full.  She buys, on average, about eight bottles per month.  How long, on average, does a bottle languish in the cellar before being consumed?&lt;/blockquote&gt;
Using Little's Law, we let L be the average number of bottles in the wine rack, 2/3&amp;times;240=160.  λ is the average number of items arriving per unit time, 12&amp;times8=96 bottles/year.  Divide L by λ and we get W&amp;cong;1.67 years per bottle.&lt;br /&gt;
&lt;br /&gt;&lt;i&gt;(It seems to me that Little's Law is related to Stoke's Theorem.  The size of the queue is the integral of the &amp;ldquo;flux&amp;rdquo; across the queue boundaries.)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;
more to come...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-855128973461239165?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/855128973461239165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=855128973461239165' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/855128973461239165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/855128973461239165'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/11/littles-law.html' title='Little&apos;s Law'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-vtE9BbrI8uE/TsGde-h2DxI/AAAAAAAABmQ/Gn-V1U_8HzQ/s72-c/QueuingSystem.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1437352751964810145</id><published>2011-10-27T16:24:00.000-07:00</published><updated>2011-10-27T16:24:31.210-07:00</updated><title type='text'>Another chart</title><content type='html'>Here is a chart of the number of words in use after each garbage collection (for MIT/GNU Scheme compiling itself with a heap of 1935360 words):
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-D-peoIHgW7Y/Tql3yaNY4SI/AAAAAAAABl0/9NwwSvgS-bw/s1600/inuse1890.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-D-peoIHgW7Y/Tql3yaNY4SI/AAAAAAAABl0/9NwwSvgS-bw/s400/inuse1890.png" /&gt;&lt;/a&gt;&lt;/div&gt;
This is the smallest heap that is big enough for the compilation to complete.  The limiting factor seems to be the big spike on the left at about 0.9&amp;times;10&lt;sup&gt;9&lt;/sup&gt;.  We obviously wouldn't want to run with the minimum size heap; 3935 garbage collections are needed and almost a third of the total time is spent in GC.  But the more frequently you collect, the better resolution you get.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1437352751964810145?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1437352751964810145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1437352751964810145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1437352751964810145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1437352751964810145'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/another-chart.html' title='Another chart'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-D-peoIHgW7Y/Tql3yaNY4SI/AAAAAAAABl0/9NwwSvgS-bw/s72-c/inuse1890.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8306413849861239292</id><published>2011-10-26T08:20:00.000-07:00</published><updated>2011-10-26T08:20:54.288-07:00</updated><title type='text'></title><content type='html'>Garbage collection gives us the illusion of nearly unlimited memory for temporary storage.  To pull off this illusion, we must be able to satisfy every allocation request (at least up to the point where we throw up our hands and raise an &amp;ldquo;out of memory&amp;rdquo; condition).  In other words, there must be free or unused memory &lt;em&gt;available&lt;/em&gt; whenever we need some.  Since the point of automatic memory management is to free the programmer from having to think about it, we expect to be able to allocate temporary storage at any time we wish during program execution.&lt;br /&gt;&lt;br /&gt;
A data structure can be considered &amp;ldquo;in use&amp;rdquo; if modifications to it can change the future behavior or result of a program.  Since we cannot in general statically determine the future behavior, we compute the transitive closure of the data structures under the data access primitives.  This is a superset of the data &amp;ldquo;in use&amp;rdquo;.  That is, if you can't access the data, it cannot be &amp;ldquo;in use&amp;rdquo;.&lt;br /&gt;&lt;br /&gt;
In order for garbage collection to succeed as a storage management strategy, there must be at all times (anytime we want to allocate) some storage that is either unallocated or unreachable.  The size of the heap must always exceed the size of the reachable data.  Or we could say that the amount of reachable data must at all times be less than the size of the heap. (By &amp;lsquo;size of the heap&amp;rsquo; I mean the total amount of storage both in use &lt;em&gt;and&lt;/em&gt; free.  For example, I could have a five megabyte heap, but only have 3 words in use.)&lt;br /&gt;&lt;br /&gt;
Any allocated data structure has but one of two ultimate fates: it remains reachable for the remainder of the run of the program &lt;em&gt;or&lt;/em&gt; it becomes unreachable at some point (and we may re-use the storage).  Assuming the heap starts empty, the size of reachable storage at any point in time is the difference between the total amount of all allocation and the total amount of all storage that has become unreachable up to that point.  For example, if my program allocates sixty megabytes over its lifetime and it abandons fifty-nine megabytes, then the heap must contain the remaining megabyte.&lt;br /&gt;&lt;hr /&gt;
We now consider the differential case, which is to say, the &lt;em&gt;rates&lt;/em&gt; of allocation, collection, and heap growth or shrinkage.  If the rate of allocation exceeds the rate of collection, the amount of storage in use in the heap must grow to meet the demand.  Conversely, if the amount of reachable storage in the heap is decreasing, then we are abandoning storage at a faster rate than we are allocating it.  But there are hard boundaries on the size of the heap.  We can never have a negative amount of storage in use, and we have the requirement (see above) that the heap must be larger than the reachable storage at all times.  The heap size is limited, so the rate of increase in reachable storage must be quite small over the long term if we are not to run out of heap.&lt;br /&gt;&lt;br /&gt;
&lt;em&gt;The rate of storage allocation must be nearly equal to the rate of deallocation (or abandonment) almost all the time.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;
(This is only slightly different from the &amp;ldquo;steady-state&amp;rdquo; assumption that the rates &lt;em&gt;are&lt;/em&gt; essentially equal.  We're simply admitting the possibility that the reachable storage grows indefinitely and that the program would eventually crash if it doesn't finish first.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8306413849861239292?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8306413849861239292/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8306413849861239292' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8306413849861239292'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8306413849861239292'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/garbage-collection-gives-us-illusion-of.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4005385386757336845</id><published>2011-10-24T14:06:00.000-07:00</published><updated>2011-10-24T14:06:10.123-07:00</updated><title type='text'></title><content type='html'>&lt;p style="text-align: center; font-size: 28pt; border-style: solid; border-width: 10px; border-color: black; padding: 16px"&gt;John McCarthy&lt;br /&gt;&lt;br /&gt;1927 - 2011&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4005385386757336845?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4005385386757336845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4005385386757336845' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4005385386757336845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4005385386757336845'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/john-mccarthy-1927-2011.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8566857843781203202</id><published>2011-10-24T09:13:00.000-07:00</published><updated>2011-10-24T09:13:39.616-07:00</updated><title type='text'>Boring charts</title><content type='html'>Here is a chart that shows the amount of free space remaining after each garbage collection (MIT/GNU Scheme compiling itself, heap size 1935360 words):
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-g6QLLJiIIZQ/TqV8WSZLkWI/AAAAAAAABlM/Vl08SRmLtr8/s1600/free1890.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://4.bp.blogspot.com/-g6QLLJiIIZQ/TqV8WSZLkWI/AAAAAAAABlM/Vl08SRmLtr8/s400/free1890.png" /&gt;&lt;/a&gt;&lt;/div&gt;
Compare that chart with this one which shows the amount of free space remaining after each GC with heaps of sizes 
8388608, 16777216, 33554432, and 100663296 words.  Note that the y axis is now displayed in log scale in order to get the wide variation in heap size on one chart.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-oT0-hSwaKro/TqWFiBwRt8I/AAAAAAAABlk/_aNReIxo_9M/s1600/freevarious.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-oT0-hSwaKro/TqWFiBwRt8I/AAAAAAAABlk/_aNReIxo_9M/s400/freevarious.png" /&gt;&lt;/a&gt;&lt;/div&gt;
As we move to larger and larger heap sizes, the proportion of memory that is freed after each GC increases.  This makes sense because the program allocates memory in the same way regardless of how much heap is present
(a program that adjusts its allocation profile in response to the heap size would look much, much different).  When the heap is small, large allocations of temporary storage (like the one at about 8.5&amp;times;10&lt;sup&gt;8&lt;/sup&gt;) make a significant difference in the amount of free space, but when the heap is big, these differences virtually disappear.&lt;br /&gt;&lt;br /&gt;
It is almost disappointing that the detail is lost when we use larger heap sizes.  The charts for the large heap sizes are essentially flat.  At large heap sizes, the variations in temporary storage usage become insignificant.
In other words, the number of garbage collections becomes less dependent upon the moment by moment allocation of the program being run and approaches the simple limit of the heap size divided by the total allocation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8566857843781203202?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8566857843781203202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8566857843781203202' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8566857843781203202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8566857843781203202'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/boring-charts.html' title='Boring charts'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-g6QLLJiIIZQ/TqV8WSZLkWI/AAAAAAAABlM/Vl08SRmLtr8/s72-c/free1890.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-483538409925539531</id><published>2011-10-21T11:43:00.000-07:00</published><updated>2011-10-21T17:11:35.561-07:00</updated><title type='text'>Scheming and plotting</title><content type='html'>Another interesting thing to plot is the amount of space that remains in use after the garbage collector runs.  This is simply the total size of the heap minus the amount the collector frees (on average).  For example, if we start MIT/GNU Scheme with &lt;code&gt;--heap 4096&lt;/code&gt;, we'll get a heap of &lt;code&gt;(* 4096 1024) = 4194304 words&lt;/code&gt;.  With this size heap, the garbage collector will run 1589 times and recycle 6204751035 words, or 3904815 words per collection.  This gives us &lt;code&gt;(- 4194304 3904815) = 289489 words&lt;/code&gt; that are still in use (averaging over all 1589 collections, of course).  If we do this calculation for various heap sizes and plot the results, we get this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-WCGKkzGVyiI/TqIKHp0zqvI/AAAAAAAABko/3aYkqifs9h0/s1600/inuse0a.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://2.bp.blogspot.com/-WCGKkzGVyiI/TqIKHp0zqvI/AAAAAAAABko/3aYkqifs9h0/s400/inuse0a.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-483538409925539531?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/483538409925539531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=483538409925539531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/483538409925539531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/483538409925539531'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/scheming-and-plotting.html' title='Scheming and plotting'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-WCGKkzGVyiI/TqIKHp0zqvI/AAAAAAAABko/3aYkqifs9h0/s72-c/inuse0a.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7477599340138821810</id><published>2011-10-16T10:13:00.000-07:00</published><updated>2011-10-16T10:13:39.778-07:00</updated><title type='text'>Adjusting for extra collections</title><content type='html'>Here is a log-log plot of garbage collection counts as function of heap size.  The green line is the predicted number of collections assuming that the product of the heap size and GC count is constant.  The red points are actual GC counts for MIT/GNU Scheme compiling itself.
 &lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-NYRhMuHvgtY/TpnUNlvFC1I/AAAAAAAABjc/9-CTHQzbugo/s1600/gc7a.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-NYRhMuHvgtY/TpnUNlvFC1I/AAAAAAAABjc/9-CTHQzbugo/s400/gc7a.png" /&gt;&lt;/a&gt;&lt;/div&gt;
As you can see, the line matches pretty good in the middle, but not so much at the ends.  It took me a while, but I figured out that the discrepancy at the lower right of the curve (where the heap size is very large and the number of collections quite small) can be attributed to a few extra garbage collections that are triggered for the purposes of compaction.  If we take these into account, our graph looks more like this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-P1yG6QN_so8/TpnVT4SuzfI/AAAAAAAABjo/6snvLizc74s/s1600/gc7b.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-P1yG6QN_so8/TpnVT4SuzfI/AAAAAAAABjo/6snvLizc74s/s400/gc7b.png" /&gt;&lt;/a&gt;&lt;/div&gt;
That takes care of the lower end, but it is the discrepancy at the upper end of the curve (smaller memory and more frequent GC) that is more interesting.&lt;br /&gt;&lt;br /&gt;
Dividing the total amount of memory used by the size of the heap gives us a pretty good estimate of the number of garbage collections provided that each garbage collection frees the entire heap.  This is generally not the case in a real program.  We should be dividing the total amount of memory used by the average of the amount of storage freed by the garbage collector.  In this next chart, we adjust for both the extra collections and the space in use that cannot be collected.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-9OoGt31FBTM/TpsILOVufjI/AAAAAAAABj0/Z_-WYmdkDk8/s1600/gc7c.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://4.bp.blogspot.com/-9OoGt31FBTM/TpsILOVufjI/AAAAAAAABj0/Z_-WYmdkDk8/s400/gc7c.png" /&gt;&lt;/a&gt;&lt;/div&gt;
In this chart, we can see the effect of not reclaiming 100% of the storage on each collection.  When the heap size is small, the memory that survives garbage collection becomes a larger fraction of that heap.  This causes the GC count to increase faster than it would if it could free all the storage.
There is a vertical asymptote to the line.  This is where the heap size is equal to the averaged amount of storage retained at each GC.  Basically, when the heap is only a little larger than the amount of storage retained, you have to do a lot of extra collection.  This next chart is simply a close-up of the previous chart showing the divergence better.
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-hPqgWbbBC54/TpsMNz9iZoI/AAAAAAAABkA/5tgjXVydY5g/s1600/gc7d.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-hPqgWbbBC54/TpsMNz9iZoI/AAAAAAAABkA/5tgjXVydY5g/s400/gc7d.png" /&gt;&lt;/a&gt;&lt;/div&gt;
It is interesting to see that retaining a modest amount of storage (empirically, it is about 400K words) can have a noticeable effect even
when the heap is tens of times larger.  (Remember, the vertical scale is logarithmic, so differences that appear small are actually quite a bit larger.)&lt;br /&gt;&lt;br /&gt;
If it is possible to use a heap ten, twenty, fifty, or even a hundred times larger than the averaged amount of storage retained, then we'll be beyond the worst part of the curve and down in the linear region.  Another way to state this is that you want the amount of storage retained at each GC to be only a few percent of the entire heap.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7477599340138821810?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7477599340138821810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7477599340138821810' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7477599340138821810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7477599340138821810'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/adjusting-for-extra-collections.html' title='Adjusting for extra collections'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-NYRhMuHvgtY/TpnUNlvFC1I/AAAAAAAABjc/9-CTHQzbugo/s72-c/gc7a.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7808434601198001393</id><published>2011-10-13T10:59:00.000-07:00</published><updated>2011-10-13T10:59:12.000-07:00</updated><title type='text'>Demystified</title><content type='html'>I discovered why the total amount of memory used does not seem approximately constant across the different heap sizes.  I had forgotten to take into account that a garbage collection cycle can be run for reasons other than reclaiming storage.  In particular, it can be run as part of a compaction phase that precedes dumping a binary object or moving an object out of the collected heap into &amp;ldquo;pure&amp;rdquo; storage.  These are not particularly interesting operations; they contribute little to the total resource usage or total time.  They just cause an overestimate of the amount of storage used in very large heaps.  I could correct for this, but I'm far more interested in what happens on the &lt;em&gt;other&lt;/em&gt; end of the curve when you have a relatively small heap.  More to come.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7808434601198001393?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7808434601198001393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7808434601198001393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7808434601198001393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7808434601198001393'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/demystified.html' title='Demystified'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2968438224264603050</id><published>2011-10-06T08:23:00.000-07:00</published><updated>2011-10-06T08:23:18.246-07:00</updated><title type='text'>Confusing</title><content type='html'>I found some of the data in my GC timings to be a little confusing.  I can understand how different runs of the compiler might have different space usages even when compiling the same thing (things like timestamps are going to change), but the variation is too large to explain away like this.  I think the problem is that by instrumenting the code to measure the timings I have inadvertently changed the behavior of the code beyond simply collecting the data.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2968438224264603050?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2968438224264603050/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2968438224264603050' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2968438224264603050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2968438224264603050'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/confusing.html' title='Confusing'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-672059592910273224</id><published>2011-10-04T09:54:00.000-07:00</published><updated>2011-10-04T09:54:42.335-07:00</updated><title type='text'>Some GC stats</title><content type='html'>I invested some time making MIT/GNU Scheme compile itself with various sizes of heap.  I did one set of runs with the variable &lt;code&gt;compiler:preserve-data-structures?&lt;/code&gt; set to &lt;code&gt;#f&lt;/code&gt; and another with it set to &lt;code&gt;#t&lt;/code&gt;.  The MIT/GNU Scheme compiler was written in a way that allows the garbage collector to reap the intermediate storage for the compiler after each phase of compilation.  When &lt;code&gt;compiler:preserve-data-structures?&lt;/code&gt; is set to &lt;code&gt;#t&lt;/code&gt;, however, the intermediate data structures are retained until the next compilation.  This should not change the total amount of storage used by the compiler, but it should have the effect of reducing the amount of storage recovered by a GC cycle.  The number of GC cycles can be seen to be larger for the smaller heap sizes.  When the heap is huge, the extra amount of storage in use has little effect on the GC count.&lt;br /&gt;&lt;br /&gt;
The &lt;i&gt;Total Free&lt;/i&gt; column contains the sum of the memory freed after each GC totaled for the entire compilation.&lt;br /&gt; 

&lt;table style="border-spacing:2em 1ex"&gt;
&lt;tr&gt;&lt;th colspan="2"&gt;Memory Size&lt;/th&gt;&lt;th colspan="2"&gt;Discard Data Structures&lt;/th&gt;&lt;th colspan="2"&gt;Preserve Data Structures&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;th&gt;(blocks)&lt;/th&gt;&lt;th&gt;(words)&lt;/th&gt;&lt;th&gt;GC Count&lt;/th&gt;&lt;th&gt;Total Free&lt;/th&gt;&lt;th&gt;GC Count&lt;/th&gt;&lt;th&gt;Total Free&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  1890&lt;/td&gt;&lt;td style="text-align:right"&gt;  1935360&lt;/td&gt;&lt;td style="text-align:right"&gt;3935&lt;/td&gt;&lt;td style="text-align:right"&gt;6213003931&lt;/td&gt;&lt;td style="text-align:center"&gt;  - &lt;/td&gt;&lt;td style="text-align:center"&gt;    -     &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  1900&lt;/td&gt;&lt;td style="text-align:right"&gt;  1945600&lt;/td&gt;&lt;td style="text-align:right"&gt;3882&lt;/td&gt;&lt;td style="text-align:right"&gt;6211940217&lt;/td&gt;&lt;td style="text-align:center"&gt;  - &lt;/td&gt;&lt;td style="text-align:center"&gt;    -     &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  1920&lt;/td&gt;&lt;td style="text-align:right"&gt;  1966080&lt;/td&gt;&lt;td style="text-align:right"&gt;3818&lt;/td&gt;&lt;td style="text-align:right"&gt;6213153480&lt;/td&gt;&lt;td style="text-align:center"&gt;  - &lt;/td&gt;&lt;td style="text-align:center"&gt;    -     &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  2048&lt;/td&gt;&lt;td style="text-align:right"&gt;  2097152&lt;/td&gt;&lt;td style="text-align:right"&gt;3502&lt;/td&gt;&lt;td style="text-align:right"&gt;6210260535&lt;/td&gt;&lt;td style="text-align:center"&gt;  - &lt;/td&gt;&lt;td style="text-align:center"&gt;    -     &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  3072&lt;/td&gt;&lt;td style="text-align:right"&gt;  3145728&lt;/td&gt;&lt;td style="text-align:right"&gt;2178&lt;/td&gt;&lt;td style="text-align:right"&gt;6205257571&lt;/td&gt;&lt;td style="text-align:center"&gt;  - &lt;/td&gt;&lt;td style="text-align:center"&gt;    -     &lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  4096&lt;/td&gt;&lt;td style="text-align:right"&gt;  4194304&lt;/td&gt;&lt;td style="text-align:right"&gt;1589&lt;/td&gt;&lt;td style="text-align:right"&gt;6207697668&lt;/td&gt;&lt;td style="text-align:right"&gt;1626&lt;/td&gt;&lt;td style="text-align:right"&gt;6200942665&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  5000&lt;/td&gt;&lt;td style="text-align:right"&gt;  5120000&lt;/td&gt;&lt;td style="text-align:right"&gt;1283&lt;/td&gt;&lt;td style="text-align:right"&gt;6206081325&lt;/td&gt;&lt;td style="text-align:right"&gt;1303&lt;/td&gt;&lt;td style="text-align:right"&gt;6198903924&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  6144&lt;/td&gt;&lt;td style="text-align:right"&gt;  6291456&lt;/td&gt;&lt;td style="text-align:right"&gt;1033&lt;/td&gt;&lt;td style="text-align:right"&gt;6210675904&lt;/td&gt;&lt;td style="text-align:right"&gt;1043&lt;/td&gt;&lt;td style="text-align:right"&gt;6205324016&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;  8192&lt;/td&gt;&lt;td style="text-align:right"&gt;  8388608&lt;/td&gt;&lt;td style="text-align:right"&gt; 766&lt;/td&gt;&lt;td style="text-align:right"&gt;6212253195&lt;/td&gt;&lt;td style="text-align:right"&gt; 771&lt;/td&gt;&lt;td style="text-align:right"&gt;6207156928&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 16384&lt;/td&gt;&lt;td style="text-align:right"&gt; 16777216&lt;/td&gt;&lt;td style="text-align:right"&gt; 377&lt;/td&gt;&lt;td style="text-align:right"&gt;6222514645&lt;/td&gt;&lt;td style="text-align:right"&gt; 379&lt;/td&gt;&lt;td style="text-align:right"&gt;6233468540&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 32768&lt;/td&gt;&lt;td style="text-align:right"&gt; 33554432&lt;/td&gt;&lt;td style="text-align:right"&gt; 188&lt;/td&gt;&lt;td style="text-align:right"&gt;6257358354&lt;/td&gt;&lt;td style="text-align:right"&gt; 188&lt;/td&gt;&lt;td style="text-align:right"&gt;6244416384&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 40000&lt;/td&gt;&lt;td style="text-align:right"&gt; 40960000&lt;/td&gt;&lt;td style="text-align:right"&gt; 154&lt;/td&gt;&lt;td style="text-align:right"&gt;6266232939&lt;/td&gt;&lt;td style="text-align:right"&gt; 154&lt;/td&gt;&lt;td style="text-align:right"&gt;6257300338&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 50000&lt;/td&gt;&lt;td style="text-align:right"&gt; 51200000&lt;/td&gt;&lt;td style="text-align:right"&gt; 124&lt;/td&gt;&lt;td style="text-align:right"&gt;6316240152&lt;/td&gt;&lt;td style="text-align:right"&gt; 124&lt;/td&gt;&lt;td style="text-align:right"&gt;6311996423&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 65536&lt;/td&gt;&lt;td style="text-align:right"&gt; 67108864&lt;/td&gt;&lt;td style="text-align:right"&gt;  94&lt;/td&gt;&lt;td style="text-align:right"&gt;6283277196&lt;/td&gt;&lt;td style="text-align:right"&gt;  94&lt;/td&gt;&lt;td style="text-align:right"&gt;6276744843&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt; 98304&lt;/td&gt;&lt;td style="text-align:right"&gt;100663296&lt;/td&gt;&lt;td style="text-align:right"&gt;  63&lt;/td&gt;&lt;td style="text-align:right"&gt;6324424897&lt;/td&gt;&lt;td style="text-align:right"&gt;  63&lt;/td&gt;&lt;td style="text-align:right"&gt;6320187112&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;131072&lt;/td&gt;&lt;td style="text-align:right"&gt;134217728&lt;/td&gt;&lt;td style="text-align:right"&gt;  48&lt;/td&gt;&lt;td style="text-align:right"&gt;6430202774&lt;/td&gt;&lt;td style="text-align:right"&gt;  48&lt;/td&gt;&lt;td style="text-align:right"&gt;6426705701&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="text-align:right"&gt;262144&lt;/td&gt;&lt;td style="text-align:right"&gt;268435456&lt;/td&gt;&lt;td style="text-align:right"&gt;  25&lt;/td&gt;&lt;td style="text-align:right"&gt;6704242312&lt;/td&gt;&lt;td style="text-align:right"&gt;  25&lt;/td&gt;&lt;td style="text-align:right"&gt;6702940561&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
Some of my thoughts about this (with graphs) in a bit.  (It becomes very interesting when the data seriously disagrees with the math,
but it is tedious to collect enough data to either support or refute the mathematical model.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-672059592910273224?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/672059592910273224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=672059592910273224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/672059592910273224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/672059592910273224'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/10/some-gc-stats.html' title='Some GC stats'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3887793854089358677</id><published>2011-09-23T17:53:00.000-07:00</published><updated>2011-09-23T17:53:53.864-07:00</updated><title type='text'>Knee surgery</title><content type='html'>As an anonymous person pointed out, the knee in the curve is an illusion.  Here is the same chart displayed with varying scales for the x and y axes:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-8KgJCZf0qE8/Tn0hjvm-nKI/AAAAAAAABi0/KhxnF4Fhc40/s1600/gc4a.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://4.bp.blogspot.com/-8KgJCZf0qE8/Tn0hjvm-nKI/AAAAAAAABi0/KhxnF4Fhc40/s400/gc4a.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-3x4l3bXtd4s/Tn0h7p5zA-I/AAAAAAAABjE/DDqjKq_IAj8/s1600/gc4b.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-3x4l3bXtd4s/Tn0h7p5zA-I/AAAAAAAABjE/DDqjKq_IAj8/s400/gc4b.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-ABw0sSx1Dh4/Tn0iRxJsEUI/AAAAAAAABjM/ZSU1hQ8wTGU/s1600/gc4c.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-ABw0sSx1Dh4/Tn0iRxJsEUI/AAAAAAAABjM/ZSU1hQ8wTGU/s400/gc4c.png" /&gt;&lt;/a&gt;&lt;/div&gt;

You can see that the position of the &amp;ldquo;knee&amp;rdquo; depends upon the scale of the X and Y axes.&lt;br /&gt;&lt;br /&gt;
The whole chart is a problem.  Not only does it show a knee, but the rest of the chart has the data all squished up along either the X or Y axis.  It is going to be hard to compare different charts if they all look like this.  I want the whole chart to be scale invariant.&lt;br /&gt;&lt;br /&gt;
(Can you guess where this is going?)&lt;br /&gt;&lt;br /&gt;
The curved line in the chart represents the solution to &lt;code&gt;x &amp;times; y = 6100000&lt;/code&gt;.  This line appears to come pretty close to the actual garbage collection count when you use MIT/GNU Scheme to compile itself.  Since the product is a constant, we have a hyperbolic curve.  To transform this into something more reasonable, we want to take the logarithm of the curve in both the X and Y direction.  This will change our line from &lt;code&gt;x &amp;times; y = constant&lt;/code&gt; to &lt;code&gt;x &amp;plus; y = constant&lt;/code&gt; (because logarithms transform multiplication into addition).
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-7PdrorJSOWM/Tn0n8bSsFqI/AAAAAAAABjU/at2bo885UUQ/s1600/gc5.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://1.bp.blogspot.com/-7PdrorJSOWM/Tn0n8bSsFqI/AAAAAAAABjU/at2bo885UUQ/s400/gc5.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;em&gt;This&lt;/em&gt; chart is certainly more interesting!  First, notice how the measured garbage collection counts fall in almost a straight line.  The curve that approximates the count &lt;em&gt;is&lt;/em&gt; a straight line, and you can see that the actual garbage collection count deviates from this line slightly at the ends.  Second, notice that the lines &lt;code&gt;10 &amp;times; x&lt;/code&gt;, &lt;code&gt;x&lt;/code&gt;, and &lt;code&gt;x/10&lt;/code&gt; become parallel.  This is convenient, too.  Finally, notice that the knee is gone.  This sort of chart won't fool us with a fake knee.&lt;br /&gt;&lt;br /&gt;
Now that we have something of an interesting baseline, it would be instructive to plot other processes that generate garbage and see how they look.  (upcoming post)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3887793854089358677?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3887793854089358677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3887793854089358677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3887793854089358677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3887793854089358677'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/09/knee-surgery.html' title='Knee surgery'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-8KgJCZf0qE8/Tn0hjvm-nKI/AAAAAAAABi0/KhxnF4Fhc40/s72-c/gc4a.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6658843717157323892</id><published>2011-09-23T13:59:00.000-07:00</published><updated>2011-09-23T13:59:10.706-07:00</updated><title type='text'>A bit of a problem</title><content type='html'>Once again, here is a plot of the actual garbage collection counts as a function of heap size:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-JKpiXfcBOQ4/TnuNYCeVZFI/AAAAAAAABis/GuuRGPBBQT4/s400/gc4.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-JKpiXfcBOQ4/TnuNYCeVZFI/AAAAAAAABis/GuuRGPBBQT4/s400/gc4.png" /&gt;&lt;/a&gt;&lt;/div&gt;
and we mention that we want to be &amp;ldquo;beyond the knee&amp;rdquo; in the curve.  So where is that &amp;ldquo;knee&amp;rdquo;?&lt;br /&gt;&lt;br /&gt;
The green line is the plot of &lt;code&gt;f(x) = 6100000/x&lt;/code&gt;, or, to put it another way, the plot of &lt;code&gt;x &amp;times; y = 6100000&lt;/code&gt;.  The knee in the curve ought to be where &lt;code&gt;x = y = &amp;radic;6100000 &amp;asymp; 2470&lt;/code&gt;.  But look at the chart!  Just by eyeballing it, we can see that 2470 is nowhere near what anyone would call the knee.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6658843717157323892?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6658843717157323892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6658843717157323892' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6658843717157323892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6658843717157323892'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/09/bit-of-problem.html' title='A bit of a problem'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-JKpiXfcBOQ4/TnuNYCeVZFI/AAAAAAAABis/GuuRGPBBQT4/s72-c/gc4.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1960488595799900613</id><published>2011-09-22T13:14:00.000-07:00</published><updated>2011-09-22T13:14:16.725-07:00</updated><title type='text'>More on GC</title><content type='html'>I had been thinking of improving the garbage collector in MIT/GNU Scheme.  I carefully measured the current GC performance so I could quantify any improvements.  This uncovered a bug (see earlier post), but it also uncovered something more interesting.  Here is a plot of the number of garbage collections as a function of heap size for the problem of compiling all the Scheme code in MIT/GNU Scheme:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-zvGrw-cjvoo/TnuLsHvhPPI/AAAAAAAABik/MVTAlLbAVNQ/s1600/gc3.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-zvGrw-cjvoo/TnuLsHvhPPI/AAAAAAAABik/MVTAlLbAVNQ/s400/gc3.png" /&gt;&lt;/a&gt;&lt;/div&gt;
This graph looks an awful lot like the graph of minimal collections.
In fact, if we plot the minimum number of garbage collections necessary for about 6100000 blocks, we get this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-JKpiXfcBOQ4/TnuNYCeVZFI/AAAAAAAABis/GuuRGPBBQT4/s1600/gc4.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="300" width="400" src="http://3.bp.blogspot.com/-JKpiXfcBOQ4/TnuNYCeVZFI/AAAAAAAABis/GuuRGPBBQT4/s400/gc4.png" /&gt;&lt;/a&gt;&lt;/div&gt;
That &lt;em&gt;appears&lt;/em&gt; to be a really good fit.  This isn't too surprising, because a GC that collects &lt;em&gt;only&lt;/em&gt; when it is almost out of memory ought not to be doing much more work than the minimum necessary.&lt;br /&gt;&lt;br /&gt;
What makes this interesting is this:  We can clearly see the &amp;ldquo;knee&amp;rdquo; of the curve, and we have enough memory to be &amp;ldquo;well beyond the knee&amp;rdquo; when we compile all of Scheme.  This means that the total number of garbage collections will be quite low.  If the garbage collector is fast enough, the total GC time will also be quite low.  For example, when given 40000 blocks of memory, MIT/GNU Scheme will compile itself in about 3 minutes of which only 2.6 seconds total are spent in garbage collection.  And as I noted previously, with sufficient memory, there need not be any garbage collection at all.&lt;br /&gt;&lt;br /&gt;
Notice that the &lt;em&gt;details&lt;/em&gt; of the collector are unimportant.  MIT/GNU Scheme uses a variation of the Minsky-Fenichel-Yochelson-Cheney-Arnborg algorithm, but it could just as easily use a mark-sweep collector.  The point is that when you are only doing a few dozen collections, it doesn't matter much what algorithm you use because changing the algorithm will make little impact on the total run time.  (Suppose I had the world's greatest garbage collector that just blows away the current one.  Then I could reduce the total time from 182.6 seconds to exactly 180 seconds.  This is less than a 5% improvement and not worth pursuing.)  (A reference count GC, however, would be a problem because it traces garbage rather than live storage.)&lt;br /&gt;&lt;br /&gt;
So my original plan is pointless.  There is no advantage to improving the garbage collector if it doesn't take more than a small amount of time, and it looks like you can achieve this by simply throwing memory at the process.  So long as you have sufficient memory, you can make the cost of a collection be close to (or even equal to) zero.&lt;br /&gt;&lt;br /&gt;
At least it &lt;em&gt;looks&lt;/em&gt; that way...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1960488595799900613?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1960488595799900613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1960488595799900613' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1960488595799900613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1960488595799900613'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/09/more-on-gc.html' title='More on GC'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-zvGrw-cjvoo/TnuLsHvhPPI/AAAAAAAABik/MVTAlLbAVNQ/s72-c/gc3.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8681726236710599141</id><published>2011-09-19T17:33:00.000-07:00</published><updated>2011-09-19T17:33:44.344-07:00</updated><title type='text'>Thoughts about GC</title><content type='html'>Suppose I have a program that, when run, allocates a total of 10 GiB
  (10×2&lt;sup&gt;30&lt;/sup&gt; bytes).  If it happens that I &lt;em&gt;have&lt;/em&gt;
  more than 10 GiB of heap, then I don't need to worry about running
  out.  If my heap is smaller than 10 GiB, I'm going to have a
  problem.&lt;br /&gt;
&lt;br /&gt;
It is often possible to re-use storage by overwriting the previously
  written information.  If the result computed by a program (including
  the side effects as part of the ‘result’) is completely
  invariant with respect to the value of a location in memory, then
  that memory location could be re-used.  Depending upon the program
  and the runtime system, re-use can be the responsibility of the
  programmer, or there can be an automatic means of storage
  management (&lt;i&gt;e.g.&lt;/i&gt; a garbage collector).  Regardless of how
  re-usable storage is identified and made available to the program,
  we can use
  the &lt;a href="http://en.wikipedia.org/wiki/Pigeonhole_principle"&gt;pigeonhole
  principle&lt;/a&gt; to determine the &lt;em&gt;minimum&lt;/em&gt; number of times that
  we must re-use some part of memory.  For example, if my program uses 10×2&lt;sup&gt;30&lt;/sup&gt; and I have
  10×2&lt;sup&gt;30&lt;/sup&gt;−1 bytes of heap, then at least one
  byte somewhere will have to be re-used.&lt;br /&gt;
&lt;br /&gt;
So let us suppose that our program which allocates 10 GiB is to be
  run with a 2 GiB heap and our runtime system provides a garbage
  collector so we don't have to manage our storage manually.  Suppose
  further that our garbage collector is not continuous, but has some
  sort of identifiable ‘cycle’ during which it locates
  re-usable memory.  On each cycle the garbage collector can reclaim
  at most 2 GiB, so we know the runtime system must perform
  a &lt;em&gt;minimum&lt;/em&gt; of at least five garbage collection cycles.  It
  may perform many, many more than five, but it cannot perform fewer
  because it would have to recycle more than 100% of the heap at some
  point.&lt;br /&gt;
&lt;br /&gt;
Another way to state this is that the number of garbage
 collections times the size of the heap must be equal to or greater than
 the total amount of storage allocated by a program.  Here is a graph
 that shows the minimum number of collections needed for a program
 that allocates 50 bytes of storage.
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-1djTfRtcBrU/TnfZ93DywdI/AAAAAAAABiY/HxX_cuRJuV0/s1600/gc0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-1djTfRtcBrU/TnfZ93DywdI/AAAAAAAABiY/HxX_cuRJuV0/s320/gc0.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
The discrete jumps in the graph are because we aren't considering
 partial allocations (less than 1 byte).  When working with realistic
 heap sizes, we can approximate this graph by dividing the total
 allocation by the heap size.  The green line in this chart plots
 50/x.

&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-KI_BPA1WrAI/TnfafwsuaRI/AAAAAAAABic/B7PNJw3jURo/s1600/gc1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-KI_BPA1WrAI/TnfafwsuaRI/AAAAAAAABic/B7PNJw3jURo/s320/gc1.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;More to come...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8681726236710599141?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8681726236710599141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8681726236710599141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8681726236710599141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8681726236710599141'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/09/thoughts-about-gc.html' title='Thoughts about GC'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-1djTfRtcBrU/TnfZ93DywdI/AAAAAAAABiY/HxX_cuRJuV0/s72-c/gc0.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8164620579289869106</id><published>2011-08-30T13:13:00.000-07:00</published><updated>2011-08-30T13:13:15.472-07:00</updated><title type='text'>Measuring GC times</title><content type='html'>MIT/GNU Scheme has a command line parameter, &lt;code&gt;--heap&lt;/code&gt;, that allows one to specify the size of heap in 1024 word blocks.  On a 32-bit machine, the heap size is limited because MIT/GNU Scheme stores the type tag in the upper bits of the word.  On a 64-bit machine the word size is wider, so it is possible to specify extremely large heaps without worrying that the address will overflow into the type tag.&lt;br /&gt;
&lt;br /&gt;
For kicks, I decided to vary the value of the heap size and see what effect that had on the task of MIT/GNU Scheme compiling itself.
&lt;br /&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;th&gt;Heap&lt;/th&gt;&lt;th&gt;GC Count&lt;/th&gt;&lt;th&gt;Cumulative GC Time&lt;br /&gt;in ms&lt;/th&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;6000&lt;/td&gt;&lt;td&gt;1056&lt;/td&gt;&lt;td&gt;25800&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;8192  &lt;i&gt;(64 MiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;764 &lt;/td&gt;&lt;td&gt;19120&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;10000&lt;/td&gt;&lt;td&gt;623 &lt;/td&gt;&lt;td&gt;17910&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;16384 &lt;i&gt;(128 MiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;377 &lt;/td&gt;&lt;td&gt;10980&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;32768 &lt;i&gt;(256 MiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;188 &lt;/td&gt;&lt;td&gt;7350&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;50000&lt;/td&gt;&lt;td&gt;124 &lt;/td&gt;&lt;td&gt;5560&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;65536 &lt;i&gt;(512 MiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;94  &lt;/td&gt;&lt;td&gt;5000&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;100000&lt;/td&gt;&lt;td&gt;63  &lt;/td&gt;&lt;td&gt;4410&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;131072 &lt;i&gt;(1 GiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;48  &lt;/td&gt;&lt;td&gt;3910&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;150000&lt;/td&gt;&lt;td&gt;42  &lt;/td&gt;&lt;td&gt;4160&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;200000&lt;/td&gt;&lt;td&gt;32  &lt;/td&gt;&lt;td&gt;3800&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;250000&lt;/td&gt;&lt;td&gt;26  &lt;/td&gt;&lt;td&gt;3560&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;262144 &lt;i&gt;(2 GiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;25  &lt;/td&gt;&lt;td&gt;3050&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;300000&lt;/td&gt;&lt;td&gt;22  &lt;/td&gt;&lt;td&gt;3360&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;350000&lt;/td&gt;&lt;td&gt;19  &lt;/td&gt;&lt;td&gt;3260&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;393216 &lt;i&gt;(3 GiB)&lt;/i&gt;&lt;/td&gt;&lt;td&gt;18  &lt;/td&gt;&lt;td&gt;2740&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;
Collecting this data was tedious, so I spent a fair amount of time thinking about a model that could explain the results.  At first glance, everything looks about right:  the more memory, the fewer GCs and the less total time is spent garbage collecting.  The problem is that the curve predicted by my model doesn't fit the empirical data at all.  Of course this means that my model is either wrong or incomplete.&lt;br /&gt;&lt;br /&gt;
I have since figured out the problem, but I thought I'd let people puzzle over it themselves for a bit, first.
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8164620579289869106?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8164620579289869106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8164620579289869106' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8164620579289869106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8164620579289869106'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/08/measuring-gc-times.html' title='Measuring GC times'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8271154687530641049</id><published>2011-04-28T09:42:00.000-07:00</published><updated>2011-04-28T09:42:10.837-07:00</updated><title type='text'>50 years ago — April 28, 1961</title><content type='html'>&lt;blockquote&gt;
This is an excerpt from the forth coming&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt; LISP 1.5 Programmer's Manual&lt;/span&gt;.&lt;/blockquote&gt;
&lt;blockquote&gt;
Provision is made in &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt; for allocating blocks of storage for data.  The data may consist of list structure or data words.  Arrays may have up to three indicies.&lt;/blockquote&gt;
&lt;blockquote&gt;
To declare an array, us the function &lt;u&gt;array&lt;/u&gt;.  Its argument is a list of arrays to be declared.  Each one must be for list structure or non-list structure.&lt;/blockquote&gt;
&lt;blockquote&gt;
Suppose &lt;code&gt;ALPHA&lt;/code&gt; is to be a 10 x 10 array of list structure and &lt;code&gt;BETA&lt;/code&gt; a 5 x 5 x 5 array of non-list structure.  The &lt;u&gt;array&lt;/u&gt; function is
&lt;br /&gt;
&lt;pre&gt;ARRAY ((
     (ALPHA (10,10) LIST)
     (BETA (5,5,5) NONLIST)    ))&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
To find the value of B&lt;sub&gt;3,4,2&lt;/sub&gt;: &lt;code&gt;(BETA 3,4,2)&lt;/code&gt; or &lt;code&gt;(BETA I J K)&lt;/code&gt; with a pair list.&lt;/blockquote&gt;
&lt;blockquote&gt;
To set &lt;code&gt;ALPHA&lt;/code&gt;&lt;sub&gt;3,4&lt;/sub&gt; to "YES":  &lt;code&gt;(ALPHA (QUOTE SET) (QUOTE YES) 3 4)&lt;/code&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;u&gt;Array&lt;/u&gt; uses marginal indexing for maximum speed.  The total number of words used by an array whose size is D&lt;sub&gt;1&lt;/sub&gt; x D&lt;sub&gt;2&lt;/sub&gt; x D&lt;sub&gt;3&lt;/sub&gt; is 4 + D&lt;sub&gt;1&lt;/sub&gt; + D&lt;sub&gt;1&lt;/sub&gt;D&lt;sub&gt;2&lt;/sub&gt; + D&lt;sub&gt;1&lt;/sub&gt;D&lt;sub&gt;2&lt;/sub&gt;D&lt;sub&gt;3&lt;/sub&gt;.  If the array is 2 dimensional, D&lt;sub&gt;1&lt;/sub&gt; = 1.  If the array is 1 dimensional, D&lt;sub&gt;1&lt;/sub&gt; and D&lt;sub&gt;2&lt;/sub&gt; = 1.&lt;/blockquote&gt;
&lt;blockquote&gt;
To save space, specify the dimensions in increasing order.&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;code&gt;ALPHA (3,4,5)&lt;/code&gt; takes less words than &lt;code&gt;ALPHA (5,3,4)&lt;/code&gt;.&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;h3&gt;



Compatability of &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1&lt;/span&gt; and &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt;.&lt;/h3&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;EVALQUOTE&lt;/code&gt; has two arguments while &lt;code&gt;APPLY&lt;/code&gt; has three.  To change a &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1&lt;/span&gt; program for &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt; simply eliminate the p-list if it is null.  If the p-list is needed, then the function &lt;u&gt;apply&lt;/u&gt; is available in &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt;,&lt;/li&gt;
&lt;li&gt;Arithmetic in &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt; is new, improved, and generally incompatible with &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1.5&lt;/span&gt; has many extra features.  There [&lt;i&gt;sic&lt;/i&gt;, these] are being written up for the new &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;LISP 1 Programmer's Manual&lt;/span&gt;.  Until it comes, check in &lt;a href="http://whereis.mit.edu/?q=26-265&amp;amp;zoom=16&amp;amp;lat=42.36355421290528&amp;amp;lng=-71.09019041061401&amp;amp;open=object-26&amp;amp;maptype=mit"&gt;Room 26-265&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;div&gt;
&lt;div style="text-align: right;"&gt;
&lt;i&gt;—&amp;nbsp;Michael Levin&lt;/i&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;i&gt;Artificial Intelligence Project&lt;/i&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;i&gt;RLE and MIT Computation Center Memo 24&lt;/i&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;i&gt;Arithmetic in Lisp 1.5&lt;/i&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/8288194986820249216-8271154687530641049?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8271154687530641049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8271154687530641049' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8271154687530641049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8271154687530641049'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/04/50-years-ago-april-28-1961.html' title='50 years ago — April 28, 1961'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4041700831458862002</id><published>2011-04-22T15:25:00.000-07:00</published><updated>2011-04-22T15:25:17.224-07:00</updated><title type='text'>Fun with scammers</title><content type='html'>No Scheme or Lisp content today.  I was amusing myself for a while with this email exchange.  The strings of digits are courtesy &lt;a href="http://www.random.org/"&gt;www.random.org&lt;/a&gt;.  I even found a site that creates &lt;a href="http://www.spyrkes.info/wugen2/index.php"&gt;fake Western Union receipts&lt;/a&gt;.&lt;br /&gt;
&lt;hr /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Hello,&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;I'm writing this with tears in my eyes,my family and I came down here to Edinburgh Scotland for a short vacation unfortunately we were mugged at the park of the hotel where we stayed,all cash,credit card and cell were all stolen from us but luckily for us we still have our passports with us.&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;We've been to the embassy and the Police here but they're not helping issues at all and our flight leaves in few hrs from now but we're having problems settling the hotel bills and the hotel manager won't let us leave until we settle the bills the amount needed now is just $2,700..I am so confused right now and thank God i wasn't injured because I complied immediately.

Waiting to hear from you.

Robert&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;I sent this message to Bob's &lt;em&gt;other&lt;/em&gt; account:
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
I just got this message that supposedly came from you. It is plausible enough that your friends might fall for it! You should email your friends and assure them that you are OK and to NOT SEND MONEY&lt;br /&gt;
~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Thanks for checking on me, well the message is from me and not a hoax. I'm presently stuck in UK and really in a bad situation.....I have been talking to the lazy embassy but it's taking them time process me help, and it's hard to get hold of a phone, that was why I had to send out email for help....I need a financial help with getting back home...all i need is $2,700.,but anything you could assist with now be helpful ..let me if can you have the money wire to me through western union&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Thanks.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Robert&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;br /&gt;&lt;/div&gt;
I'm glad to hear your email is ok, it would be terrible to be mugged &lt;i&gt;and&lt;/i&gt;&amp;nbsp;hacked. Where do you need it sent?&lt;br /&gt;
~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Glad you replied back.

I am full of panic now and the police only asked me to write a statement about the incident and directed me to the embassy,i have spoken to the Consulate here but they are not responding to the matter effectively,I really need your help to get myself out of this place.

Well all i need now is just $2,700 but any amount you can afford will be appreciated, you can have it wired to my name via Western Union i'll have to show my passport as ID to pick it up here and i promise to pay you back as soon as i get back home.&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Here's the info you need at western union location below&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Name: Robert G&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Address: 48 Princes Street, Edinburgh, Scotland&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Kindly email me the transfer details as soon as you have it done.Please let me know if you are heading out to western union now.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Thanks&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Robert&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;What's going on?&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;I was only able to wire $300 (I hit the limit on my ATM).  I can send a lot more tomorrow, but will you have time to get it?&lt;br /&gt;
&amp;nbsp;~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Please Let me have the western union confirmation number # M.T.C.N, so i can be able to pick up the Money.

I'm freaked out at the moment please keep me posted.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;Robert, did you receive the money?  Are you still in trouble?  Is there anything more I can do?&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Thanks for your effort,Let me have the western union confirmation number # M.T.C.N.

Awaiting for your reply.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;i&gt;I left him dangling on this one&lt;/i&gt;.&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;What's going on?&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert .&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;My apologies, Robert, (I know you are in trouble, but I do have to sleep at times!)

The MTCN is 2665592734&lt;br /&gt;
&lt;br /&gt;
HOWEVER!!!  IMPORTANT!!!!&lt;br /&gt;
&lt;br /&gt;
I didn't want to broadcast that over email because it could be read by someone unscrupulous.  So I added in your wife's birth date.  Just subtract that out to get the real tracking number.

I hope you can figure that out.  Please let me know.  If you want, I have an additional $500 I can send right away.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;What's going on,I just got back from Western Union and i was told there was no record for the transaction,kindly check the receipt and get back to me with the correct confirmation #&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Awaiting to reply.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert .&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;&lt;i&gt;Trip number 1. &amp;nbsp;I'm shocked it didn't work&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
What?!  Did you remember to subtract your wife's birth date from the number I gave you?&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Omg!!  I am full of panic now,Let me have the scanned receipt For Payment giving to you by the Western Union Agent.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;i&gt;Uh oh. &amp;nbsp;I'm busted... maybe I can vamp a bit....&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
How can I do that?  You know I don't have a scanner.

I've got an idea!  What's the phone number of the hotel that is giving you problems?  I'll call the manager myself and put it on my credit card.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;No reply. &amp;nbsp;I was going to give up but it occurred to me to check for an on-line receipt generator (they have everything on line, don't they?) They do. &amp;nbsp;I sent him a nice receipt.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Good news!  I found a scanner.

Please let me know if everything is ok.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Thanks for your help.. i just got the money but there seems to be a problem with the conversion rate, i noticed the money came out here in $300but all i need is $2,700 as i requested, don't  know that the conversion is that low, please i will need your further assistance so i will be needing $2,400.

Please let me know when you will be heading out to western union.

Waiting to read from you.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;i&gt;Hmm, he read the receipt, but didn't make a Western Union run. &amp;nbsp;I'll string him along a bit.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I'll have to go by the bank (again) to get an additional check.  I should be able to do that after work, in a few hours.

Hang in there!  I'm very worried.&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Ok,I will be waiting ,Do e-mail the full Western Union Transfer Details once you have it done.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Keep me posted.&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;i&gt;I'm trying to get the guy to go `off script'.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;URGENT&lt;br /&gt;
&amp;nbsp;Robert, I need to know if you want the money in US Dollars,
GB Pounds, or Euros, and what the exchange rate is.  Can you get
back to me as soon as you can?

I'm really sorry about this, hope you are surviving.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;No reply. &amp;nbsp;Better dangle some cash.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I sent some more money.  Did you get it?  Is everything all right?&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;OK...Can i have the full transfer details (MTCN) so i will be able to pick up the money.

Waiting to read from you.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Thanks

Robert.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;The MTCN is 4677254413
Please let me know when you get it!&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Are you there?&lt;/span&gt;&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;Robert, did you receive the money?  Are you still in trouble?  Is there anything more I can do?&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Let me have the confirmation details # M.T.C.N.

Awaiting for your urgent reply.

Robert&lt;/span&gt;&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Please do get back to me with the Western Union Control Number M.T.C.N#

Please Keep me posted.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;&lt;i&gt;This guy just has a one-track mind. &amp;nbsp;It seems impossible to get him `off script'.&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Robert,&lt;br /&gt;
What is going on?  Are you all right?&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I just checked with Western Union and they say you haven't picked up either of the two wires that I sent!  Are you having difficulty getting them?&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;The Western Union Control Number M.T.C.N # are these:&lt;br /&gt;
&amp;nbsp;2665591653  --- amount $300&lt;br /&gt;
&amp;nbsp;3207519347  --- amount $500&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Please let me know if you have any problems retrieving the money.&lt;br /&gt;
&amp;nbsp;~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Are you kidding me or what,cause i was told at western union office the money you sent to me was not there.

Please Let me know what's going on am freaked out here.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp;Robert.&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&amp;nbsp;&lt;i&gt;Yes! &amp;nbsp;Trip number 2. &amp;nbsp;He's probably figured out I'm playing him, though. &amp;nbsp;Let's goad him into one more trip. &amp;nbsp;A bit of an insane rant to allay his suspicions and we'll sweeten the pot just a bit more...&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
I don't know what to say, Robert.  Perhaps they have a different system in Edinburgh and the numbers don't match?  Are you sure that you are telling them the right numbers and didn't get them mixed up?&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I checked with Western Union, and the agent told me that the money was there and that you didn't pick it up.  Why don't you go to the Royal Bank of Scotland?  They are at 4 Princess Street, right around the corner from where you are staying.  They should be able to straighten this out right away.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I'm surprised you suggest that I am kidding.  Why would I be so cruel? I have $800 on the line, and I'm doing this for your benefit.  I'm not the victim here, you are.  Do you think I would wire you this kind of money and then make a joke about it?  Do you think I get a kick out of imagining you walk back and forth to Western Union for no reason? This is a bad situation and you seem to think I'm making it worse! I'm not sure you are taking this as seriously as I am.  Are you sure you didn't get injured?&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;I'm going to try this one more time, and I expect action on your part. I have wired an additional $200 dollars for a total of One Thousand ($1000) dollars.  I really cannot afford any more, so I hope this is enough.  The details are these:&amp;nbsp;
 &lt;br /&gt;
&lt;br /&gt;
Sender:  Joseph Marshall&lt;br /&gt;
&amp;nbsp;Receiver:  Robert G, 48 Princess Street, Edinburgh Scotland&lt;br /&gt;
&amp;nbsp;Amount:  $1000.00  (One Thousand)&amp;nbsp; &lt;br /&gt;
Money Transfer Control Number:  1822631749&lt;br /&gt;
&amp;nbsp;Transfer Fee:  50.00&lt;br /&gt;
&amp;nbsp;Number:  10341731365&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;And I am enclosing a receipt.  Please be sure to get these details correct.

I am awaiting to hear that you have collected the cash.&lt;br /&gt;
&amp;nbsp;~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;The receipt was fake and I included a “security question”:  Who's your daddy?  I was sure this would tip my hand, but....&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;Robert, it has been 7 hours since I sent this.  Did you get it?&lt;br /&gt;
&amp;nbsp;~jrm&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: right;"&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;No i didn't,I will like to go back to western union and make this complain to them that all the confirmation number they give you was invalid ok..&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;i&gt;YES! &amp;nbsp;Three trips! &amp;nbsp;Well, that's good enough for me.&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4041700831458862002?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4041700831458862002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4041700831458862002' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4041700831458862002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4041700831458862002'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/04/fun-with-scammers.html' title='Fun with scammers'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3863504965940268273</id><published>2011-04-12T16:14:00.000-07:00</published><updated>2011-04-12T16:14:02.746-07:00</updated><title type='text'>Oops</title><content type='html'>I made a mistake that has lead to a lot of confusion.  It is a common mistake, so I have a lot of company.  To assuage the trauma to my ego, I'll point out that no one who argued with me (or, for that matter, agreed with me) identified it.  Allow me to explain it and correct myself.&lt;br /&gt;&lt;br /&gt;
The Church-Turing thesis is often stated as follows:
&lt;blockquote&gt;&lt;i&gt;Anything that can be computed by some means can also be computed by a Turing machine.&lt;/i&gt;&lt;/blockquote&gt;
And this is usually coupled with Rosser's observation that &amp;lambda;-calculus and recursion theory are equivalent formulations.&lt;br /&gt;&lt;br /&gt;
The problem is that phrasing, while not exactly incorrect, is not exactly right, either.  It is vagueness disguised as definition.  Because it is a definition, it is &amp;ldquo;correct, by definition&amp;rdquo;, but it is vague enough to admit interpretations that are absurd.  Thus, if one isn't careful, one can deduce several absurdities that are &amp;ldquo;correct, by defintion&amp;rdquo;.&lt;br /&gt;&lt;br /&gt;
So what is the correct statement?  The Church-Turing thesis is a statement about &amp;ldquo;effective calculability&amp;rdquo;.  This is an &lt;em&gt;intuitive&lt;/em&gt; concept which tries to generalize on the idea of an &lt;em&gt;algorithm&lt;/em&gt;, or &amp;ldquo;plug and chug&amp;rdquo; math formulas, or &amp;ldquo;mechanistic&amp;rdquo; procedures like Newton's method.  Many mathematicians have attempted to formalize the notion of &amp;ldquo;effective calculability&amp;rdquo;, among them Church and Turing, but also Gödel, Kleene, Rosser, and Post (and many others after them, but these are the big names).  A correct statement of the Church-Turing thesis is more like this:
&lt;blockquote&gt;The formal terms &amp;ldquo;computable by a Turing machine&amp;rdquo; and &amp;ldquo;&amp;lambda;-definable&amp;rdquo; fully capture the intuitive notion of &amp;ldquo;effectively calculable&amp;rdquo;.&lt;/blockquote&gt;
Naturally, the bulk of what a modern digital computer does is in fact an &amp;ldquo;effective calculation&amp;rdquo; and thus a Turing machine or &amp;lambda;-calculus is a very good model for what a computer can calculate.  However, there are things a modern digital computer can do &lt;em&gt;other than&lt;/em&gt; calculate.  These activities fall outside the scope of the Church-Turing thesis and there is no reason to believe that they would be subject to the limitations of computability.&lt;br /&gt;
&lt;blockquote&gt;&lt;em&gt;Does anybody really know what time it is?&lt;/em&gt;&lt;/blockquote&gt;
&lt;div style="text-align:right"&gt;&amp;mdash;&amp;nbsp;Robert Lamm of Chicago&lt;/div&gt;
A good example of a non-computable, yet common task that a digital computer performs is to determine the current time.  There is no algorithm or calculation that you can perform that will yield the current time.  You simply must check a clock.  Even if you somehow know the elapsed time since some event, you nonetheless have to check a clock in order to determine the beginning of the &amp;lsquo;epoch&amp;rsquo; (baseline time).&lt;br /&gt;&lt;br /&gt;
A whole set of non-computable quantities can be made available via reflection.  Recall the definition of a Turing machine.  The next state of a Turing machine is a function of the current state and the symbol on the tape under the head.  It is &lt;em&gt;not&lt;/em&gt; a function of, for example, the  the size of the state transition table.  This is not to say that these quantities are &lt;em&gt;unknowable&lt;/em&gt;, but that they cannot be &lt;em&gt;calculated&lt;/em&gt; without introspection (certainly bounds can calculated, and certainly any machine can be instrumented or even simulated, but consider this:  any Turing machine can be augmented by any number of inaccessible states.  There is no way to &lt;em&gt;calculate&lt;/em&gt; the size of the state table without knowing the number of these states.)  Also note, that there is nothing magic about these quantities, you can calculate to your heart's content with them &lt;em&gt;after you obtain them&lt;/em&gt;.  It is obtaining them in the first place that involves something other than computation.&lt;br /&gt;&lt;br /&gt;
My mistake is this:  I didn't &lt;em&gt;specifically&lt;/em&gt; and &lt;em&gt;explicitly&lt;/em&gt; state when I was referring to the informal &amp;ldquo;effective calculation&amp;rdquo; and the superset that is the informal &amp;ldquo;computing&amp;rdquo; that one can do on a modern digital computer.  In other words, I applied the Church-Turing thesis to too broad a class.&lt;br /&gt;&lt;br /&gt;
Given that, I'll rephrase my Exercise 1 and see how people react:
&lt;blockquote&gt;&lt;b&gt;Exercise 1:&lt;/b&gt; Write a program for a class of universal Turing machines that, when run, &lt;em&gt;calculates&lt;/em&gt; whether the machine it is on is imposing additional space complexity.&lt;/blockquote&gt;
When I phrase it that way, it sort of sounds obvious that there are going to be problems.&lt;br /&gt;&lt;br /&gt;
On the other hand, this is a far more satisfying rewording than
&lt;blockquote&gt;Write a portable program that is non-portable.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3863504965940268273?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3863504965940268273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3863504965940268273' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3863504965940268273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3863504965940268273'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/04/oops.html' title='Oops'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8281834452108869852</id><published>2011-04-08T09:53:00.000-07:00</published><updated>2011-04-08T09:53:11.064-07:00</updated><title type='text'>Too much exercise</title><content type='html'>I've spent the past few days thinking about how to answer the exercises in my previous post.  I think I finally came up with a good analogy.  (Bear with me.)&lt;br /&gt;
&lt;br /&gt;
These days, it is not uncommon to run programs on &lt;em&gt;virtual&lt;/em&gt; hardware.  Programs like VMWare or Virtual Box provide nearly undetectable emulation of an x86 PC.  In fact, modern x86 CPUs actually emulate the x86 instruction set through hardware accelerated interpretation or jit compiling.  Although it can be tricky to emulate the entire body of computer hardware and peripherals that might go into a PC, it is straightforward to emulate the bare bones PC hardware with close to perfect fidelity, even down to the CPUID.&lt;br /&gt;
&lt;br /&gt;
So could one write a &lt;em&gt;portable&lt;/em&gt; x86 program — one that can run without modification on a real PC with real hardware or on a real PC with virtual hardware (like a Transmeta CPU) or on completely virtual hardware — that can &lt;em&gt;reliably&lt;/em&gt; and &lt;em&gt;predictably&lt;/em&gt; detect whether it is being “run directly” or “just being emulated”?
The entire &lt;i&gt;raison d'être&lt;/i&gt; of virtualization rests on the fact that, given enough effort, you &lt;em&gt;can&lt;/em&gt; fool &lt;em&gt;all&lt;/em&gt; of the programs &lt;em&gt;all&lt;/em&gt; of the time.  (Bugs notwithstanding.)&lt;br /&gt;
&lt;br /&gt;
So let's reconsider &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;Exercise 1:&lt;/b&gt; &amp;nbsp;Write a program that returns 1 if run on any tail-recursive implementation of a language, but returns 0 if run on any non tail-recursive implementation of that same language.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Restate this as:  Write a &lt;em&gt;portable&lt;/em&gt; x86 program  — one that can run without modification on a real PC with real hardware or on a real PC with virtual hardware (like a Transmeta CPU) or on completely virtual hardware — that can &lt;b&gt;NOT ONLY&lt;/b&gt; &lt;em&gt;reliably&lt;/em&gt; and &lt;em&gt;predictably&lt;/em&gt; detect whether it is being “run directly” or “just being emulated”, &lt;b&gt;BUT FURTHERMORE&lt;/b&gt; can &lt;em&gt;reliably&lt;/em&gt; and &lt;em&gt;predictably&lt;/em&gt; detect whether the underlying execution mechanism is “recursive” or “iterative”?&lt;br /&gt;
&lt;br /&gt;
I assert that this question is barely worth thinking about (unless you work at VMWare) and that the answer could hardly be anything but “No.”&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;Exercise 1a&lt;/b&gt; &lt;i&gt;(extra credit)&lt;/i&gt;&lt;b&gt;:&lt;/b&gt;&amp;nbsp; Write a program that crashes or doesn't return if run on a any tail-recursive implementation of a language, but returns 0 if run on a any non tail-recursive implementation of that same language.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
If a program cannot detect whether or not it is being emulated, perhaps it can “half” detect.  If it could &lt;em&gt;reliably&lt;/em&gt; crash the emulator, then you could at least &lt;em&gt;demonstrate&lt;/em&gt; that some sort of emulation is being done even if you couldn't perform a conditional branch in this situation.  Suppose the program were being emulated.  Suppose further that the emulator is recursive (for whatever reason).  One could, in theory, crash the emulator via a stack overflow or out-of-memory error (maybe that emulator is recursive, but it uses heap-allocated stack frames).  Alas, this isn't what we asked for.  We are looking for a program that can &lt;em&gt;reliably&lt;/em&gt; crash an &lt;em&gt;iterative&lt;/em&gt; emulator.  We're out of luck.&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;Exercise 1b, essay&lt;/b&gt;&amp;nbsp;&lt;i&gt;(extra extra credit)&lt;/i&gt;&lt;b&gt;:&lt;/b&gt; Discuss the implications of your answers to exercises 1 and 1a to the semantics of the programs&lt;/span&gt; (woah, my apologies, &lt;em&gt;programs&lt;/em&gt; don't have semantics, &lt;em&gt;languages&lt;/em&gt; do.  Pretend I wrote “languages”).  &lt;span class="Apple-style-span" style="color: #38761d;"&gt;In particular, briefly outline what changes to the various semantic models — denotational, operational, and/or axiomatic — take place upon introducing tail recursion.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
The implication is this:  the semantics of a programming language are logically independent of the implementation of the language.  (If they were not, virtual machines would be impossible.)&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;Exercise 2:&lt;/b&gt; What trivial change can Louis make to his code for &lt;code&gt;smaller&lt;/code&gt; that will disable tail recursion?&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;(define (smallest list predicate)
  ;; Returns the smallest element of list.
  (if (null? list)
      #f
      &lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;(let ((answer&lt;/span&gt;&lt;/b&gt;
        (if (predicate (car list) (cadr list))
            (smallest (cons (car list) (cddr list)) predicate)
            (smallest (cdr list) predicate))))
        &lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;answer&lt;/span&gt;&lt;/b&gt;)))
&lt;/pre&gt;
There is no need for a flag to enable or disable tail recursion.  Tail recursion only “works” when the caller does nothing to the return value but immediately return it itself.  A &lt;code&gt;LET&lt;/code&gt; expression is syntactic sugar:
&lt;br /&gt;
&lt;pre&gt;(define (smallest list predicate)
  ;; Returns the smallest element of list.
  (if (null? list)
      #f
      (&lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;(lambda (answer) answer)&lt;/span&gt;&lt;/b&gt;
        (if (predicate (car list) (cadr list))
            (smallest (cons (car list) (cddr list)) predicate)
            (smallest (cdr list) predicate)))))
&lt;/pre&gt;
You can now see that the value of the conditional expression is not immediately returned, but rather passed as an argument to a (rather trivial) &lt;code&gt;lambda&lt;/code&gt; expression.  (Yes, a smart compiler could notice that the &lt;code&gt;lambda&lt;/code&gt; expression is simply the identity function &lt;em&gt;in this case&lt;/em&gt;.  If that is a problem, simply make sure that the function you use to disable the tail recursion is late-bound so that the compiler cannot prove that it can be elided.)&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;Exercise 3:&lt;/b&gt; What trivial change can Louis make to his code for &lt;code&gt;smaller&lt;/code&gt; that will enable tail recursion on all but the &lt;em&gt;initial&lt;/em&gt; call to &lt;code&gt;smaller&lt;/code&gt;?
&lt;/span&gt;&lt;br /&gt;
&lt;pre&gt;(define (smallest list predicate)
  ;; Returns the smallest element of list.

  &lt;b&gt;&lt;span class="Apple-style-span" style="color: #0b5394;"&gt;(define (smallest list predicate)&lt;/span&gt;&lt;/b&gt;
    (if (null? list)
        #f
        (if (predicate (car list) (cadr list))
            (smallest (cons (car list) (cddr list)) predicate)
            (smallest (cdr list) predicate))))
  &lt;span class="Apple-style-span" style="color: #0b5394;"&gt;&lt;b&gt;(let ((answer (smallest list predicate)))
    answer)&lt;/b&gt;&lt;/span&gt;)
&lt;/pre&gt;
Again, we don't need special flags to have fine control over tail recursion.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exercise 4:&lt;/b&gt; Implement &lt;code&gt;disable-tail-recursion&lt;/code&gt; as a macro.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;;;; For example:
(define-syntax disable-tail-recursion
  (syntax-rules ()
    ((disable-tail-recursion form)
     (let ((answer form)) answer))))&lt;/pre&gt;
You could be more sophisticated and invoke a late-bound function, but this is, frankly, overkill.  You hardly need macros, special forms, flags, decorations, etc. to control tail recursion.  This is especially true if all you want is a pretty stack trace for debugging.  Tail recursion is as easy to turn on and off as a &lt;code&gt;printf&lt;/code&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8281834452108869852?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8281834452108869852/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8281834452108869852' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8281834452108869852'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8281834452108869852'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/04/too-much-exercise.html' title='Too much exercise'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1738705082254774214</id><published>2011-04-01T11:11:00.000-07:00</published><updated>2011-04-01T17:24:53.126-07:00</updated><title type='text'>Exercises</title><content type='html'>&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;Apparently I was not as clear with my questions as I thought I was.  I've edited the questions to make them more precise.  The additional text is in this alternative color.
&lt;/span&gt;&lt;br /&gt;
&lt;hr /&gt;
&lt;b&gt;Exercise 1:&lt;/b&gt;  Write a program that returns 1 if run on &lt;strike&gt;a&lt;/strike&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;any&lt;/span&gt; tail-recursive implementation &lt;span class="Apple-style-span" style="color: #990000;"&gt;of a language&lt;/span&gt;, but returns 0 if run on &lt;strike&gt;a&lt;/strike&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;any&lt;/span&gt; non tail-recursive implementation &lt;span class="Apple-style-span" style="color: #990000;"&gt;of that same language&lt;/span&gt;. &amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;The goal is not to find a program and language implementation pair that exhibit the behavior, but to design a program that can correctly infer whether on not any supplied language implementation supports tail recursion by examining its own behavior.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exercise 1a&lt;/b&gt;&amp;nbsp;&lt;i&gt;(extra credit)&lt;/i&gt;&lt;b&gt;:&lt;/b&gt;&amp;nbsp;Write a program that &lt;i&gt;crashes&lt;/i&gt; or &lt;i&gt;doesn't return&lt;/i&gt; if run on&amp;nbsp;&lt;strike&gt;a&lt;/strike&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;any&lt;/span&gt;&amp;nbsp;tail-recursive implementation&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;of a language&lt;/span&gt;, but returns 0 if run on&amp;nbsp;&lt;strike&gt;a&lt;/strike&gt;&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;any&lt;/span&gt;&amp;nbsp;non tail-recursive implementation&amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;of that same language&lt;/span&gt;. &amp;nbsp;&lt;span class="Apple-style-span" style="color: #990000;"&gt;The goal is not to find a program and language implementation pair that exhibit the behavior, but to design a program that can correctly infer that any supplied implementation does not support tail recursion (this is a weaker condition because we do not require that the program correctly infer support of tail recursion, but only lack of support).&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exercise 1b, essay&lt;/b&gt;&amp;nbsp;&lt;i&gt;(extra extra credit)&lt;/i&gt;&lt;b&gt;:&lt;/b&gt; Discuss the implications of your answers to exercises 1 and 1a to the semantics of the programs.  In particular, briefly outline what changes to the various semantic models — denotational, operational, and/or axiomatic — take place upon introducing tail recursion.&lt;br /&gt;
&lt;br /&gt;
Louis Reasoner wrote this program to sort numbers:
&lt;br /&gt;
&lt;pre&gt;(define (smallest list predicate)
  ;; Returns the smallest element of list.
  (if (null? list)
      #f
      (if (predicate (car list) (cadr list))
          (smallest (cons (car list) (cddr list)) predicate)
          (smallest (cdr list) predicate))))

(define (louis-sort list predicate)
  (do ((remainder list (cdr remainder))
       (answer '() (append answer (cons (smallest remainder predicate) '()))))
      ((null? remainder) answer)))

(define test-list
  (do ((i 0 (+ i 1))
       (answer '() (cons i answer)))
      ((&amp;gt;= i 100) answer)))
&lt;/pre&gt;
He complains “I am unable to debug this because &lt;code&gt;smallest&lt;/code&gt; tail calls itself and leaves no trace on the stack.  Look!&lt;br /&gt;
&lt;pre&gt;1 ]=&amp;gt; (louis-sort test-list &amp;lt;)

;The object (), passed as an argument to safe-car, is not a pair.
;To continue, call RESTART with an option number:
; (RESTART 1) =&amp;gt; Return to read-eval-print level 1.

2 error&amp;gt; (debug)

There are 9 subproblems on the stack.

Subproblem level: 0 (this is the lowest subproblem level)
Expression (from stack):
    (predicate (car list) ###)
 subproblem being executed (marked by ###):
    (cadr list)
Environment created by the procedure: SMALLEST

 applied to: ((0) #[arity-dispatched-procedure 39])
The execution history for this subproblem contains 1 reduction.
You are now in the debugger.  Type q to quit, ? for commands.

3 debug&amp;gt; H
H
SL#  Procedure-name          Expression

0    smallest                (predicate (car list) (cadr list))
1    smallest                (if (predicate (car list) (cadr list)) (smalle ...
2    do-loop                 (cons (smallest remainder predicate) (quote ()))
3    do-loop                 (append answer (cons (smallest remainder predi ...
4    do-loop                 (do-loop (cdr remainder) (append answer (cons  ...
5    %repl-eval              (let ((value (hook/repl-eval s-expression envi ...
6    %repl-eval/write        (hook/repl-write (%repl-eval s-expression envi ...
7    do-loop                 (begin (if (queue-empty? queue) (let ((environ ...
8    loop                    (loop (bind-abort-restart cmdl (lambda () (der ...
&lt;/pre&gt;
“I was expecting to see pending stack frames as the program recursively called &lt;code&gt;smaller&lt;/code&gt;, but since they are all tail-recursive calls, I don't have a way of knowing how deep it went.  I wish I could selectively enable or disable tail recursion for this one call...”&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exercise 2:&lt;/b&gt; What trivial change can Louis make to his code for &lt;code&gt;smaller&lt;/code&gt; that will disable tail recursion?&lt;br /&gt;
&lt;br /&gt;
Louis again has a problem.  “I have a stack trace, but, but, well, just LOOK at it!&lt;br /&gt;
&lt;pre&gt;1 ]=&amp;gt; (louis-sort test-list &amp;lt;)

;The object (), passed as an argument to safe-car, is not a pair.
;To continue, call RESTART with an option number:
; (RESTART 1) =&amp;gt; Return to read-eval-print level 1.

2 error&amp;gt; (debug)

There are more than 50 subproblems on the stack.

Subproblem level: 0 (this is the lowest subproblem level)
Expression (from stack):
    (predicate (car list) ###)
 subproblem being executed (marked by ###):
    (cadr list)
Environment created by the procedure: SMALLEST

 applied to: ((0) #[arity-dispatched-procedure 39])
The execution history for this subproblem contains 1 reduction.
You are now in the debugger.  Type q to quit, ? for commands.

3 debug&amp;gt; H
H
SL#  Procedure-name          Expression

0    smallest                (predicate (car list) (cadr list))
1    smallest                (if (predicate (car list) (cadr list)) (smalle ...
2    smallest                (let ((answer (if (predicate (car list) (cadr  ...
3    smallest                (let ((answer (if (predicate (car list) (cadr  ...
4    smallest                (let ((answer (if (predicate (car list) (cadr  ...
5    smallest                (let ((answer (if (predicate (car list) (cadr  ...
6    smallest                (let ((answer (if (predicate (car list) (cadr  ...
7    smallest                (let ((answer (if (predicate (car list) (cadr  ...
8    smallest                (let ((answer (if (predicate (car list) (cadr  ...
9    smallest                (let ((answer (if (predicate (car list) (cadr  ...
10   smallest                (let ((answer (if (predicate (car list) (cadr  ...
11   smallest                (let ((answer (if (predicate (car list) (cadr  ...
12   smallest                (let ((answer (if (predicate (car list) (cadr  ...
13   smallest                (let ((answer (if (predicate (car list) (cadr  ...
14   smallest                (let ((answer (if (predicate (car list) (cadr  ...
15   smallest                (let ((answer (if (predicate (car list) (cadr  ...
16   smallest                (let ((answer (if (predicate (car list) (cadr  ...
17   smallest                (let ((answer (if (predicate (car list) (cadr  ...
18   smallest                (let ((answer (if (predicate (car list) (cadr  ...
19   smallest                (let ((answer (if (predicate (car list) (cadr  ...
20   smallest                (let ((answer (if (predicate (car list) (cadr  ...
21   smallest                (let ((answer (if (predicate (car list) (cadr  ...
22   smallest                (let ((answer (if (predicate (car list) (cadr  ...
23   smallest                (let ((answer (if (predicate (car list) (cadr  ...
24   smallest                (let ((answer (if (predicate (car list) (cadr  ...
25   smallest                (let ((answer (if (predicate (car list) (cadr  ...
26   smallest                (let ((answer (if (predicate (car list) (cadr  ...
27   smallest                (let ((answer (if (predicate (car list) (cadr  ...
28   smallest                (let ((answer (if (predicate (car list) (cadr  ...
29   smallest                (let ((answer (if (predicate (car list) (cadr  ...
30   smallest                (let ((answer (if (predicate (car list) (cadr  ...
31   smallest                (let ((answer (if (predicate (car list) (cadr  ...
32   smallest                (let ((answer (if (predicate (car list) (cadr  ...
33   smallest                (let ((answer (if (predicate (car list) (cadr  ...
34   smallest                (let ((answer (if (predicate (car list) (cadr  ...
35   smallest                (let ((answer (if (predicate (car list) (cadr  ...
36   smallest                (let ((answer (if (predicate (car list) (cadr  ...
37   smallest                (let ((answer (if (predicate (car list) (cadr  ...
38   smallest                (let ((answer (if (predicate (car list) (cadr  ...
39   smallest                (let ((answer (if (predicate (car list) (cadr  ...
40   smallest                (let ((answer (if (predicate (car list) (cadr  ...
41   smallest                (let ((answer (if (predicate (car list) (cadr  ...
42   smallest                (let ((answer (if (predicate (car list) (cadr  ...
43   smallest                (let ((answer (if (predicate (car list) (cadr  ...
44   smallest                (let ((answer (if (predicate (car list) (cadr  ...
45   smallest                (let ((answer (if (predicate (car list) (cadr  ...
46   smallest                (let ((answer (if (predicate (car list) (cadr  ...
47   smallest                (let ((answer (if (predicate (car list) (cadr  ...
48   smallest                (let ((answer (if (predicate (car list) (cadr  ...
49   smallest                (let ((answer (if (predicate (car list) (cadr  ...
50   smallest                (let ((answer (if (predicate (car list) (cadr  ...
51   smallest                (let ((answer (if (predicate (car list) (cadr  ...
52   smallest                (let ((answer (if (predicate (car list) (cadr  ...
53   smallest                (let ((answer (if (predicate (car list) (cadr  ...
54   smallest                (let ((answer (if (predicate (car list) (cadr  ...
55   smallest                (let ((answer (if (predicate (car list) (cadr  ...
56   smallest                (let ((answer (if (predicate (car list) (cadr  ...
57   smallest                (let ((answer (if (predicate (car list) (cadr  ...
58   smallest                (let ((answer (if (predicate (car list) (cadr  ...
59   smallest                (let ((answer (if (predicate (car list) (cadr  ...
60   smallest                (let ((answer (if (predicate (car list) (cadr  ...
61   smallest                (let ((answer (if (predicate (car list) (cadr  ...
62   smallest                (let ((answer (if (predicate (car list) (cadr  ...
63   smallest                (let ((answer (if (predicate (car list) (cadr  ...
64   smallest                (let ((answer (if (predicate (car list) (cadr  ...
65   smallest                (let ((answer (if (predicate (car list) (cadr  ...
66   smallest                (let ((answer (if (predicate (car list) (cadr  ...
67   smallest                (let ((answer (if (predicate (car list) (cadr  ...
68   smallest                (let ((answer (if (predicate (car list) (cadr  ...
69   smallest                (let ((answer (if (predicate (car list) (cadr  ...
70   smallest                (let ((answer (if (predicate (car list) (cadr  ...
71   smallest                (let ((answer (if (predicate (car list) (cadr  ...
72   smallest                (let ((answer (if (predicate (car list) (cadr  ...
73   smallest                (let ((answer (if (predicate (car list) (cadr  ...
74   smallest                (let ((answer (if (predicate (car list) (cadr  ...
75   smallest                (let ((answer (if (predicate (car list) (cadr  ...
76   smallest                (let ((answer (if (predicate (car list) (cadr  ...
77   smallest                (let ((answer (if (predicate (car list) (cadr  ...
78   smallest                (let ((answer (if (predicate (car list) (cadr  ...
79   smallest                (let ((answer (if (predicate (car list) (cadr  ...
80   smallest                (let ((answer (if (predicate (car list) (cadr  ...
81   smallest                (let ((answer (if (predicate (car list) (cadr  ...
82   smallest                (let ((answer (if (predicate (car list) (cadr  ...
83   smallest                (let ((answer (if (predicate (car list) (cadr  ...
84   smallest                (let ((answer (if (predicate (car list) (cadr  ...
85   smallest                (let ((answer (if (predicate (car list) (cadr  ...
86   smallest                (let ((answer (if (predicate (car list) (cadr  ...
87   smallest                (let ((answer (if (predicate (car list) (cadr  ...
88   smallest                (let ((answer (if (predicate (car list) (cadr  ...
89   smallest                (let ((answer (if (predicate (car list) (cadr  ...
90   smallest                (let ((answer (if (predicate (car list) (cadr  ...
91   smallest                (let ((answer (if (predicate (car list) (cadr  ...
92   smallest                (let ((answer (if (predicate (car list) (cadr  ...
93   smallest                (let ((answer (if (predicate (car list) (cadr  ...
94   smallest                (let ((answer (if (predicate (car list) (cadr  ...
95   smallest                (let ((answer (if (predicate (car list) (cadr  ...
96   smallest                (let ((answer (if (predicate (car list) (cadr  ...
97   smallest                (let ((answer (if (predicate (car list) (cadr  ...
98   smallest                (let ((answer (if (predicate (car list) (cadr  ...
99   smallest                (let ((answer (if (predicate (car list) (cadr  ...
100  smallest                (let ((answer (if (predicate (car list) (cadr  ...
101  smallest                (let ((answer (if (predicate (car list) (cadr  ...
102  do-loop                 (cons (smallest remainder predicate) (quote ()))
103  do-loop                 (append answer (cons (smallest remainder predi ...
104  do-loop                 (do-loop (cdr remainder) (append answer (cons  ...
105  %repl-eval              (let ((value (hook/repl-eval s-expression envi ...
106  %repl-eval/write        (hook/repl-write (%repl-eval s-expression envi ...
107  do-loop                 (begin (if (queue-empty? queue) (let ((environ ...
108  loop                    (loop (bind-abort-restart cmdl (lambda () (der ...
&lt;/pre&gt;
“I wish I could start eliminating the tail call from the second call onwards...&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Exercise 3:&lt;/b&gt; What trivial change can Louis make to his code for &lt;code&gt;smaller&lt;/code&gt; that will enable tail recursion on all but the &lt;em&gt;initial&lt;/em&gt; call to &lt;code&gt;smaller&lt;/code&gt;?  &lt;em&gt;(Hint, the &lt;/em&gt;&lt;b&gt;bold&lt;/b&gt;&lt;em&gt; text in the following backtrace shows how this differs from the first backtrace.)&lt;/em&gt;
&lt;br /&gt;
&lt;pre&gt;1 ]=&amp;gt; (louis-sort test-list &amp;lt;)

;The object (), passed as an argument to safe-car, is not a pair.
;To continue, call RESTART with an option number:
; (RESTART 1) =&amp;gt; Return to read-eval-print level 1.

2 error&amp;gt; (debug)

There are &lt;b&gt;10&lt;/b&gt; subproblems on the stack.

Subproblem level: 0 (this is the lowest subproblem level)
Expression (from stack):
    (predicate (car list) ###)
 subproblem being executed (marked by ###):
    (cadr list)
Environment created by the procedure: SMALLEST

 applied to: ((0) #[arity-dispatched-procedure 39])
The execution history for this subproblem contains 1 reduction.
You are now in the debugger.  Type q to quit, ? for commands.

3 debug&amp;gt; H
H
SL#  Procedure-name          Expression

0    smallest                (predicate (car list) (cadr list))
1    smallest                (if (predicate (car list) (cadr list)) (smalle ...
&lt;b&gt;2    smallest                (let ((answer (smallest list predicate))) answer)&lt;/b&gt;
3    do-loop                 (cons (smallest remainder predicate) (quote ()))
4    do-loop                 (append answer (cons (smallest remainder predi ...
5    do-loop                 (do-loop (cdr remainder) (append answer (cons  ...
6    %repl-eval              (let ((value (hook/repl-eval s-expression envi ...
7    %repl-eval/write        (hook/repl-write (%repl-eval s-expression envi ...
8    do-loop                 (begin (if (queue-empty? queue) (let ((environ ...
9    loop                    (loop (bind-abort-restart cmdl (lambda () (der ...
&lt;/pre&gt;
Louis seems to have gotten his wish and is currently making progress despite the existence of tail recursion.  Cy D. Fect, however, is unimpressed.  He complains “Sure, it is trivial to disable tail recursion whenever you desire, but I don't like guessing whether the compiler is going to emit a tail call, and I'd simply rather not learn.  I'd prefer some sort of &lt;em&gt;declaration&lt;/em&gt; or &lt;em&gt;decoration&lt;/em&gt; so I can explicitly tell the compiler to &lt;em&gt;not&lt;/em&gt; emit a tail call.  Something like this:&lt;br /&gt;
&lt;pre&gt;(define (smallest list predicate)
  ;; Returns the smallest element of list.
  (if (null? list)
      #f
      (if (predicate (car list) (cadr list))
          ;; This branch should leave a backtrace - CDF
          (disable-tail-recursion 
             (smallest (cons (car list) (cddr list)) predicate))
          (smallest (cdr list) predicate))))&lt;/pre&gt;
&lt;b&gt;Exercise 4:&lt;/b&gt; Implement &lt;code&gt;disable-tail-recursion&lt;/code&gt; as a macro.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Homework:&lt;/b&gt; Fix Louis's code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1738705082254774214?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1738705082254774214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1738705082254774214' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1738705082254774214'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1738705082254774214'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/04/exercises.html' title='Exercises'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8953703330690334620</id><published>2011-03-30T13:06:00.000-07:00</published><updated>2011-03-30T13:06:01.336-07:00</updated><title type='text'>Tail recursion and debugging</title><content type='html'>&lt;pre&gt;
java.lang.NullPointerException
        at java.io.FilterInputStream.close(FilterInputStream.java:172)
        at sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream.close(JarURLConnection.java:108)
        at com.alba.vware.ResourceServlet.doGet(ResourceServlet.java:396)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        at com.alba.vware.ServletDefinition.doService(ServletDefinition.java:261)
        at com.alba.vware.ServletDefinition.service(ServletDefinition.java:175)
        at com.alba.vware.ManagedServletPipeline.service(ManagedServletPipeline.java:91)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:62)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;When a tail recursion is eliminated, there's no stack frame left to
use to print a traceback when something goes wrong later.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Guido van Rossum&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;The elimination of stack frames doesn't do anything for the
algorithmic complexity of the code, but it does make debugging harder.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Guido van Rossum&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;My issue with this optimization is that you lose debugging
information.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Ian Bicking&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;Tail recursion can be easily inlined, however it is my understanding
that the Java creators specifically chose not to implement this, as it
makes resultant code hard to debug (if not impossible).&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Andrew Monkhouse&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;This will
confuse users who inadvertently wrote something recursive (the
recursion isn't obvious in the stack trace printed), and makes
debugging hard.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Guido van Rossum&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;I am a big fan of being able to get stack backtraces when I have a problem to debug. But tail call recursion silently throws away stack frames. You get great performance benefits from doing so, but I'd like an option when debugging to get at the information that has been thrown away.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;btilly&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
&lt;i&gt;[Continued on next page]&lt;/i&gt;&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt; I'm uninterested in optimizing tail recursion.&lt;/i&gt;
&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Guido van Rossum&lt;/div&gt;
&lt;pre&gt;&lt;i&gt;[Continued from previous page]&lt;/i&gt;
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.FilterDefinition.doFilter(FilterDefinition.java:167)
        at com.alba.vware.FilterChainInvoke.doFilter(FilterChainInvoke.java:58)
        at com.alba.vware.ManagedFilterPipeline.dispatch(ManagedFilterPipeline.java:118)
        at com.alba.vware.Filter.doFilter(Filter.java:113)
        at com.alba.vware.FilteredServlet$Chain.doFilter(FilteredServlet.java:176)
        at com.alba.vware.FilteredServlet.service(FilteredServlet.java:145)
        at com.alba.vware.HttpConnection.runServletFromWithinSpan(HttpConnection.java:933)
        at com.alba.vware.HttpConnection.access$000(HttpConnection.java:71)
        at com.alba.vware.HttpConnection$1.runServletFromWithinSpan(HttpConnection.java:854)
        at com.alba.vware.TraceHelper$TraceableServletRunnable$2.run(TraceHelper.java:467)
        at com.alba.vware.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
        at com.alba.vware.LocalTraceSpanBuilder.run(LocalTraceSpanBuilder.java:518)
        at com.alba.vware.TraceHelper$TraceableServletRunnable.beginNewTrace(TraceHelper.java:411)
        at com.alba.vware.TraceHelper$TraceableServletRunnable.runWithTracingEnabled(TraceHelper.java:377)
        at com.alba.vware.TraceHelper$TraceableServletRunnable.run(TraceHelper.java:339)
        at com.alba.vware.HttpConnection.runServlet(HttpConnection.java:850)
        at com.alba.vware.HttpConnection.run(HttpConnection.java:815)
        at com.alba.vware.DispatchQueue$WorkerThread.run(DispatchQueue.java:379)
&lt;/pre&gt;
&lt;blockquote&gt;&lt;i&gt;The default value for thread stack size is 128K for 32-bit server and 256K for 64-bit server.&lt;/i&gt;&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Java manual&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8953703330690334620?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8953703330690334620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8953703330690334620' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8953703330690334620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8953703330690334620'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/tail-recursion-and-debugging.html' title='Tail recursion and debugging'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-882621197331034201</id><published>2011-03-23T15:25:00.000-07:00</published><updated>2011-03-23T15:25:49.107-07:00</updated><title type='text'>Erf</title><content type='html'>I found a polynomial approximation to &lt;code&gt;Erf&lt;/code&gt;:&lt;pre&gt;(define (polynomial-erf z)
  ;; Numerical Recipies 6.2
  ;; fractional error &amp;lt; 1.2e-7
  (let* ((t (/ 1.0 (+ 1.0 (* .5 (abs z)))))
         (ans (- 1.0 (* t
                        (exp (+ (- (* z z))
                                (+ -1.26551223
                                   (* t (+ 1.00002368
                                   (* t (+ .37409196
                                   (* t (+ .09678418
                                   (* t (+ -.18628806 
                                   (* t (+ .27886807 
                                   (* t (+ -1.13520398
                                   (* t (+ 1.48851587
                                   (* t (+ -.82215223 
                                   (* t .17087277))))))))))))))))))))))))
    (if (&amp;gt;= z 0) ans (- ans))))&lt;/pre&gt;
For kicks I plotted the difference between my Taylor series expansion and the polynomial approximation.  (Since the polynomial approximation probably started life as the Taylor series,  I wasn't expecting much enlightenment.)  My Taylor series version has a tunable tolerance, though, so I dialed it up beyond the 1.2e-7 tolerance that the polynomial approximation claims.  I got this graph:&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-n8bLmm-Nobw/TYpxprxrFGI/AAAAAAAABcQ/nZ4Sf-ttdgc/s1600/erf-delta1.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="243" width="400" src="http://2.bp.blogspot.com/-n8bLmm-Nobw/TYpxprxrFGI/AAAAAAAABcQ/nZ4Sf-ttdgc/s400/erf-delta1.png" /&gt;&lt;/a&gt;&lt;/div&gt;
So what are we seeing?  First, my Taylor series version does a pretty good job for small values, but when we get to about &lt;code&gt;Erf(1.5)&lt;/code&gt; or so, you can see the beginnings of a &amp;lsquo;square wave&amp;rsquo; artifact.  The discrete jumps are caused by adding more terms to the expansion.  Down at the low end we see a smooth wiggly curve.  This is the error from the polynomial approximation.  Since both the polynomial and Taylor series are approximations, we cannot quantitatively determine how much error comes from each approximation, but we have a rough idea about what is going on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-882621197331034201?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/882621197331034201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=882621197331034201' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/882621197331034201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/882621197331034201'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/erf.html' title='Erf'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-n8bLmm-Nobw/TYpxprxrFGI/AAAAAAAABcQ/nZ4Sf-ttdgc/s72-c/erf-delta1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-886639942189029488</id><published>2011-03-23T11:39:00.000-07:00</published><updated>2011-03-23T11:39:27.568-07:00</updated><title type='text'>Continued Fractions</title><content type='html'>How did I end up back at continued fractions?  I was doing more thinking about my polling problem, and I wanted to plot some cumulative log-normal distributions.  That involves computing the &amp;lsquo;&lt;a href="http://mathworld.wolfram.com/Erf.html"&gt;error function&lt;/a&gt;&amp;rsquo;.  There are libraries for computing this, but I didn't find anything I could immediately use, so I wrote a truly simple-minded version that just expands the Taylor series:
&lt;pre&gt;(define (erf z tolerance)

  (define (erf-taylor terms)
    (* (/ 2 (sqrt pi))
       (sum 0 terms
            (lambda (n)
              (/ (* (expt -1 n) (expt z (+ (* n 2) 1)))
                 (* (factorial n) (+ (* n 2) 1)))))))

  (define (iter approx terms)
    (let ((new-approx (erf-taylor terms)))
      (if (and (&gt; new-approx -1.0)
               (&lt; new-approx 1.0)
               (&lt; (abs (- new-approx approx)) tolerance))
          new-approx
          (iter new-approx (+ terms 1)))))
  (iter 0.0 1))&lt;/pre&gt;
This was good enough to get a curve plotted, but it is a terrible way to compute &lt;code&gt;Erf&lt;/code&gt;.  Since &lt;code&gt;Erf&lt;/code&gt; is such an important function in statistics, I thought that I should put a &lt;em&gt;little&lt;/em&gt; more effort into it, so I looked around and found &amp;ldquo;&lt;a href="http://www-sop.inria.fr/members/Sylvain.Chevillard/download/papers/ChevillardRevolRNC8.pdf"&gt;Computation of the error function erf in arbitrary precision with correct rounding&lt;/a&gt;&amp;rdquo; by Chevillard and Ravol.  This paper seriously goes to town.  Their goal is to return the floating point number closest to the actual value of &lt;code&gt;Erf&lt;/code&gt; according to the rounding rules.  It isn't enough to simply calculate &lt;code&gt;Erf&lt;/code&gt; using floats, you have to keep careful track of where rounding errors can happen and go out of your way to minimize them.  This is probably more work than it is worth for me, but I assume that Chevillard and Ravol have already done the &lt;em&gt;really&lt;/em&gt; hard analysis.&lt;br /&gt;&lt;br /&gt;
Chevillard and Ravol considered an approach using continued fractions.  They dismissed it as being too slow for practical computation.  They're correct.  But it just so happens that I wrote a continued fraction library for Scheme, so although the technique is slow, using a continued fraction approximation is the easiest path to validating the faster computations.&lt;br /&gt;&lt;br /&gt;
Unfortunately, my continued fraction library is too limited to deal with non-integer coefficients, so I have to fix that first.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-886639942189029488?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/886639942189029488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=886639942189029488' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/886639942189029488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/886639942189029488'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/continued-fractions.html' title='Continued Fractions'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2012376373043207930</id><published>2011-03-18T08:15:00.000-07:00</published><updated>2011-03-18T08:15:39.790-07:00</updated><title type='text'>A couple of puzzles</title><content type='html'>&lt;ul&gt;&lt;li&gt;Write a program that finds the smallest element in a list.&lt;/li&gt;
&lt;li&gt;Write a program that, given a predicate, finds an extremum from a list.  That is, if the predicate is &lt;code&gt;&amp;lt;&lt;/code&gt;, the smallest is returned, if the predicate is &lt;code&gt;&amp;gt;&lt;/code&gt;, the largest is returned.&lt;pre&gt;(define (longer? a b) (&amp;gt; (string-length a) (string-length b)))&lt;/pre&gt;
Given &lt;code&gt;longer?&lt;/code&gt; it would find the longest string in a list.&lt;/li&gt;&lt;/ul&gt;


&lt;a href="http://research.microsoft.com/en-us/people/thoare/"&gt;C.A.R. &amp;ldquo;Tony&amp;rdquo; Hoare&lt;/a&gt; proposed a &lt;a href="http://en.wikipedia.org/wiki/Selection_algorithm"&gt;selection algorithm&lt;/a&gt; to find the &lt;i&gt;k&lt;/i&gt;th order statistic in a collection of elements.  The obvious solution is this:&lt;pre&gt;(define (list-select predicate list index)
  (list-ref (sort list predicate) index))

;; Examples:
;;
;; Find the smallest element:
;;   (list-select &amp;lt; list 0)
;;
;; Find the second longest string:
;;   (lsit-select longer? list 1)&lt;/pre&gt;
The &amp;ldquo;obvious&amp;rdquo; solution is O(n log n), but one can do better.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2012376373043207930?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2012376373043207930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2012376373043207930' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2012376373043207930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2012376373043207930'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/couple-of-puzzles.html' title='A couple of puzzles'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5467706775142051572</id><published>2011-03-10T09:41:00.000-08:00</published><updated>2011-03-10T09:41:09.839-08:00</updated><title type='text'>And from left field</title><content type='html'>Blogger is kind enough to report a few statistics about people who visit this blog.  One of the stats is &amp;ldquo;Search Keywords&amp;rdquo;, which I interpret to mean &amp;ldquo;What people typed in to Google that directed them here&amp;rdquo;.  Here are a few:
&lt;ul&gt;&lt;li&gt;continuation passing style no stack&lt;/li&gt;
&lt;li&gt;how to not write factorial functions&lt;/li&gt;
&lt;li&gt;lisp vs c++&lt;/li&gt;
&lt;li&gt;first class environment&lt;/li&gt;&lt;/ul&gt;
These aren't weird.
This one is:
&lt;ul&gt;&lt;li&gt;stairsteps in hair&lt;/li&gt;&lt;/ul&gt;
I'm baffled.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5467706775142051572?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5467706775142051572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5467706775142051572' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5467706775142051572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5467706775142051572'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/and-from-left-field.html' title='And from left field'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4374108374335471241</id><published>2011-03-09T14:38:00.000-08:00</published><updated>2011-03-09T14:38:57.894-08:00</updated><title type='text'>Pretty charts</title><content type='html'>I have collected some empirical data concerning the &lt;a href="http://funcall.blogspot.com/2011/03/more-about-that-puzzle.html"&gt;polling problem&lt;/a&gt;.  If we sort the successful polls by time and plot the ordinal fraction against time we get this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-TLpV_S7GKnc/TXfh2r7twEI/AAAAAAAABbw/i0UG9Uukhi8/s1600/distribution1.png" imageanchor="1" style=""&gt;&lt;img border="0" height="212" width="320" src="http://1.bp.blogspot.com/-TLpV_S7GKnc/TXfh2r7twEI/AAAAAAAABbw/i0UG9Uukhi8/s320/distribution1.png" /&gt;&lt;/a&gt;&lt;/div&gt;
If we plot on a logarithmic scale, it looks like this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-PZRrRcBQAf0/TXfiY1k2GFI/AAAAAAAABb4/JphufFYb2w4/s1600/distribution-log.png" imageanchor="1" style=""&gt;&lt;img border="0" height="265" width="400" src="http://3.bp.blogspot.com/-PZRrRcBQAf0/TXfiY1k2GFI/AAAAAAAABb4/JphufFYb2w4/s400/distribution-log.png" /&gt;&lt;/a&gt;&lt;/div&gt;
This looks suspiciously familiar.  My gut feeling was that there was a log-normal distribution somewhere around here.  If we try fitting a cumulative log-normal distribution to the data, we get this:
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-DjoaACU6lSE/TXfjBICZ55I/AAAAAAAABcA/pLUVHHe6Rd4/s1600/distribution-model.png" imageanchor="1" style=""&gt;&lt;img border="0" height="265" width="400" src="http://3.bp.blogspot.com/-DjoaACU6lSE/TXfjBICZ55I/AAAAAAAABcA/pLUVHHe6Rd4/s400/distribution-model.png" /&gt;&lt;/a&gt;&lt;br /&gt;(&amp;mu; = 4.3, &amp;sigma; = 1.6)&lt;/div&gt;
That is a &lt;em&gt;very&lt;/em&gt; good fit for the range of interest.&lt;br /&gt;&lt;br /&gt;
Last night I had an &amp;lsquo;Aha!&amp;rsquo; moment.  We can look at the distribution as the probability that a result will be ready when we poll (that's not the &amp;lsquo;Aha!&amp;rsquo;).  But we can &lt;em&gt;pretend&lt;/em&gt; that we made all the RPCs at exactly the same time.  If we had, then this chart shows the fraction of RPCs that finish as a function of time (not a big &amp;lsquo;Aha!&amp;rsquo;, but I'll take it).  So if we were to poll at 2 seconds, we'd find about 20% of the RPCs have completed, but if we wait until about 4.5 seconds we'd find 90% have completed.
&lt;br /&gt;&lt;br /&gt;What if we polled at 2 seconds &lt;em&gt;and&lt;/em&gt; 4.5 seconds?  Well, the 20% that completed before the poll at 2 seconds will be serviced right after that poll, but any that become ready between 2 and 4.5 seconds will have to wait until the later poll.  That will be &lt;code&gt;90 - 20 = 70%&lt;/code&gt;.  That is to say, the efficacy of the poll &amp;mdash; the marginal increase in likelihood of getting a response &amp;mdash; is proportional to the vertical difference in the graph divided by the time since the last poll.  Or, to put it yet another way, the polling frequency should be proportional to the derivative of the distribution.  Aha!&lt;br /&gt;&lt;br /&gt;
An empirical measurement of the derivative would have a lot of noise.  Fortunately, we noticed that the cumulative distribution is closely modeled by a cumulative log-normal curve.  Cumulative means integral.  The derivative is therefore simply a log-normal curve centered at the median time (about 3 seconds).  (Is this an &amp;lsquo;Aha!&amp;rsquo;, or a &amp;lsquo;D'oh!&amp;rsquo; moment?)&lt;br /&gt;&lt;br /&gt;
I think I have enough of an understanding of this problem to write some code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4374108374335471241?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4374108374335471241/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4374108374335471241' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4374108374335471241'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4374108374335471241'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/pretty-charts.html' title='Pretty charts'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-TLpV_S7GKnc/TXfh2r7twEI/AAAAAAAABbw/i0UG9Uukhi8/s72-c/distribution1.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7061840241838334255</id><published>2011-03-08T09:58:00.000-08:00</published><updated>2011-03-08T09:58:37.538-08:00</updated><title type='text'>More about that puzzle</title><content type='html'>In the &lt;a href="http://funcall.blogspot.com/2011/03/puzzle-and-challenge.html"&gt;previous post&lt;/a&gt; I described a puzzle.  I based the puzzle on a real-world problem:  I'm invoking a service with an RPC and the defined interface requires that I poll for the answer.  (I dislike polling, but I'm stuck with it.)  I have been told vaguely that the answer usually arrives &amp;lsquo;within a few seconds,&amp;rsquo; but that &amp;lsquo;sometimes it takes longer.&amp;rsquo;  (This is what passes for documentation.  I can't blame the implementors too much, actually; they themselves are interfacing with a sucky third-party API.  On the other hand, had they provided a better abstraction, then I wouldn't need to.)&lt;br /&gt;&lt;br /&gt;
So given this API, I decided to model it to try to understand it better.  Casting the problem as a betting challenge helps because I can reduce the abstract cost and benefit to a simple number that I want to maximize.  We can compare different strategies and different assumptions by comparing the &amp;ldquo;payoff&amp;rdquo;.&lt;br /&gt;&lt;br /&gt;
It makes sense to look at the trivial and degenerate strategies first as they are the simplest.  The easiest strategy is to not do anything.  That seems to be a non-starter here, but it rules out any strategy that loses money in the long run.  (You'd be surprised at how often people think that doing &lt;em&gt;something&lt;/em&gt; simply must be better than doing &lt;em&gt;nothing&lt;/em&gt;.  As Ira Gershwin penned, &amp;ldquo;It ain't necessarily so.&amp;rdquo;)&lt;br /&gt;&lt;br /&gt;
The next simplest strategy is to wait until you are &lt;em&gt;sure&lt;/em&gt; the answer is available and poll exactly once.  So how long is that?  I asked the implementors of the API if there were any point at which we &lt;em&gt;absolutely knew&lt;/em&gt; that the answer was available.  They said there was no &lt;i&gt;a priori&lt;/i&gt; time limit on getting an answer, but that they've never seen one take more than a few days.  That's discouraging because it seems to rule out any sort of guaranteed &amp;ldquo;real-time&amp;rdquo; interaction.  But since &amp;lsquo;most of the time&amp;rsquo; it takes only &amp;lsquo;a few seconds&amp;rsquo;, it might be worthwhile to partition the problem into fast and slow responses and optimize the fast case.&lt;br /&gt;&lt;br /&gt;
The third simplest strategy is poll as rapidly as possible until the answer is ready.  This will minimize the amount of time we spend in anticipation of a result, but the cost associated with polling may be too expensive (and remember, it costs nothing to do nothing).&lt;br /&gt;&lt;br /&gt;
Finally, there may be an optimal way to schedule the polling.  Consider the case if we knew for certain that 97% of the time the answer comes back in exactly 2 seconds and that the other 3% of the time it took exactly 115 seconds.  Obviously we'd poll exactly twice:  once at just after two seconds, once again just after 115.  Of course this is unlikely to be the case, but a bi-modal distribution of response times is not unusual in and of itself.&lt;br /&gt;&lt;br /&gt;
We can now characterize something about the solution:  &lt;em&gt;if&lt;/em&gt; an optimal strategy exists, it depends on several factors:&lt;ul&gt;&lt;li&gt;The cost of polling.&lt;/li&gt;&lt;li&gt;The benefit of getting a &amp;lsquo;timely&amp;rsquo; answer.&lt;/li&gt;&lt;li&gt;The distribution of response times.&lt;/li&gt;&lt;/ul&gt;
At this point I &lt;em&gt;suspect&lt;/em&gt; that the distribution can be modeled as the sum of a handful of time-shifted log-normal distributions, but that is just a gut feeling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7061840241838334255?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7061840241838334255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7061840241838334255' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7061840241838334255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7061840241838334255'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/more-about-that-puzzle.html' title='More about that puzzle'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-574557722604752571</id><published>2011-03-03T17:35:00.000-08:00</published><updated>2011-03-03T17:35:10.082-08:00</updated><title type='text'>A puzzle and challenge</title><content type='html'>Imagine you have a black box that can play a betting game.  On
the top of the box is a button, two LEDs (red and green), and a
slot in which you can insert a 25 cent piece.&lt;br /&gt;&lt;br /&gt;

You start the game by pressing the button.  This resets the box
to the initial state.&lt;br /&gt;&lt;br /&gt;

If the box is in the initial state, whenever you insert a 25 cent
piece, the red LED will light (nothing else happens and you lose
your money).  While the box is in the initial state, you may
insert as many 25 cent pieces as you wish (and they each will be
happily devoured).&lt;br /&gt;&lt;br /&gt;

The box will remain in the initial state for somewhere between 1
millisecond and 10 seconds, at which point it silently changes to
the final state.&lt;br /&gt;&lt;br /&gt;

In the final state, if you insert a 25 cent piece, the green LED
will light, your 25 cent piece will be returned and the game is
over.  However, you may be awarded a bonus.  The bonus starts at
one dollar the instant the box changes to the final state, but the
bonus is reduced by one cent every 10 milliseconds after the state
change.&lt;br /&gt;&lt;br /&gt;

Once in the final state, the box remains there until the button
is pressed to start the next round.&lt;br /&gt;&lt;br /&gt;

The challenge:  develop and implement a strategy that maximizes your
return.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-574557722604752571?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/574557722604752571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=574557722604752571' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/574557722604752571'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/574557722604752571'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/puzzle-and-challenge.html' title='A puzzle and challenge'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6064742663146959556</id><published>2011-03-01T12:26:00.000-08:00</published><updated>2011-03-01T12:26:49.570-08:00</updated><title type='text'>Fifty Years Ago</title><content type='html'>&lt;pre&gt;*
*      EVALQ   A SUCCESSOR TO THE APPLY OPERATOR, THE GRAND NEW
*              (AS OF 1 MARCH 1961) THE EVALQUOTE OPERATOR.
*
&lt;/pre&gt;
A &lt;a href="http://en.wikipedia.org/wiki/Universal_Turing_machine"&gt;universal Turing machine&lt;/a&gt; is an abstract ‘machine’ that can simulate any other Turing machine.&lt;br /&gt;
A &lt;a href="http://en.wikipedia.org/wiki/Universal_function"&gt;universal function&lt;/a&gt; is the mathematical analogue of a universal Turing machine.  A universal function is a computable function that can be parameterized to compute any other computable function.  The fact that universal functions exist (by the utm theorem) means that one can write an interpreter.  (Alternatively, an interpreter for a Turing complete language can be easily shown to be a universal function.)&lt;br /&gt;
In &lt;i&gt;&lt;a href="http://www-formal.stanford.edu/jmc/recursive/recursive.html"&gt;Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I&lt;/a&gt;&lt;/i&gt; (there is no Part II), McCarthy states:
&lt;br /&gt;
&lt;blockquote&gt;
There is an S-function &lt;i&gt;apply&lt;/i&gt; with the property that if &lt;i&gt;f&lt;/i&gt; is an S-expression for an S-function &lt;i&gt;f′&lt;/i&gt; and &lt;i&gt;args&lt;/i&gt; is a list of arguments of the form (&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt;,...,&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;n&lt;/sub&gt;), where &lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt;,...,&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;n&lt;/sub&gt; are arbitrary S-expressions, then &lt;i&gt;apply&lt;/i&gt;[&lt;i&gt;f&lt;/i&gt;;&lt;i&gt;args&lt;/i&gt;] and &lt;i&gt;f′&lt;/i&gt;[&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt;,...,&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;n&lt;/sub&gt;] are defined for the same values of &lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt;,...,&lt;i&gt;arg&lt;/i&gt;&lt;sub&gt;n&lt;/sub&gt;, and are equal when defined.&lt;/blockquote&gt;
This is not a vacuous statement.  It says (more precisely), suppose there is a mathematical partial function &lt;i&gt;f′&lt;/i&gt; which is computable for some arguments.  Then, there is a &lt;i&gt;program&lt;/i&gt; (called &lt;i&gt;f&lt;/i&gt;), which will compute exactly the same answers as the abstract mathematical partial function &lt;i&gt;f′&lt;/i&gt;.  &lt;i&gt;Furthermore&lt;/i&gt;, the LISP program &lt;i&gt;apply&lt;/i&gt;, when given the program &lt;i&gt;f&lt;/i&gt; and some particular arguments, computes the exact same thing as if the function &lt;i&gt;f′&lt;/i&gt; were &lt;em&gt;directly&lt;/em&gt; called on the arguments.  In other words, LISP I's &lt;i&gt;apply&lt;/i&gt; operator is universal.&lt;br /&gt;
&lt;br /&gt;
By March 1 1961 it was realized that although &lt;i&gt;apply&lt;/i&gt; is universal, it is not necessarily &lt;em&gt;primitive&lt;/em&gt;.  The user version of &lt;i&gt;apply&lt;/i&gt; is trivially defined as:
&lt;br /&gt;
&lt;pre&gt;(defun quote-args (arglist)
  (map 'list (lambda (arg) (cons 'quote arg)) arglist))

(defun lisp1-apply (f arglist)
  (eval (cons f (quote-args arglist))))&lt;/pre&gt;
This is the origin of the &lt;code&gt;evalquote&lt;/code&gt; operator.&lt;br /&gt;
&lt;br /&gt;
In February 1961, Dan Edwards recoded &lt;code&gt;OVERLORD&lt;/code&gt; (the original batch-mode ‘REPL’) to use &lt;code&gt;EVALQUOTE&lt;/code&gt; rather than &lt;code&gt;APPLY&lt;/code&gt; for top-level execution.
&lt;br /&gt;
&lt;blockquote&gt;
EVALQUOTE — Reads pairs of LISP statements (atoms or atomic symbols) and considers the first as a function and the second as a list of quoted arguments for the function.  Pairs are read in until a card with the atomic symbol STOP is encountered or a READ error is found.  The pairs are then evaluated one at a time and the results printed.&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;—&amp;nbsp;Lisp 1.5 Programmer's Manual&lt;/div&gt;
Here is a LISP program from about this time:
&lt;pre&gt;DEFINE ((
(MEMBER (LAMBDA (A X) (COND ((NULL X) F)
     ((EQ A (CAR X)) T) (T (MEMBER A (CDR X))) )))
(UNION (LAMBDA (X Y) (COND ((NULL X) Y) ((MEMBER
     (CAR X) Y) (UNION (CDR X) Y)) (T (CONS (CAR X)
     (UNION (CDR X) Y))) )))
(INTERSECTION (LAMBDA (X Y) (COND ((NULL X) NIL)
     ((MEMBER (CAR X) Y) (CONS (CAR X) (INTERSECTION
     (CDR X) Y))) (T (INTERSECTION (CDR X) Y)) )))
))
INTERSECTION ((A1 A2 A3) (A1 A3 A5))
UNION ((X Y Z) (U V W X))&lt;/pre&gt;
The commas have disappeared, the main loop now uses the two-argument &lt;code&gt;EVALQUOTE&lt;/code&gt; rather than the three-argument &lt;code&gt;APPLY&lt;/code&gt;, and some rudimentary indentation is present.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6064742663146959556?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6064742663146959556/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6064742663146959556' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6064742663146959556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6064742663146959556'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/03/fifty-years-ago.html' title='Fifty Years Ago'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3355559025792319601</id><published>2011-02-28T15:32:00.000-08:00</published><updated>2011-02-28T15:32:50.246-08:00</updated><title type='text'>No stack?  No problem.</title><content type='html'>&lt;blockquote&gt;
“We have no badges. In fact, we don't need badges. I don't have to show you any stinking badges...”&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;—&amp;nbsp;&lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/The_Treasure_of_the_Sierra_Madre"&gt;The Treasure of the Sierra Madre&lt;/a&gt;&lt;/em&gt;,&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/B._Traven"&gt;B. Travern&lt;/a&gt;&lt;/blockquote&gt;
&lt;hr /&gt;
I really blew it with that last post.  &lt;em&gt;Mea maxima culpa.&lt;/em&gt; &lt;br /&gt;&lt;hr /&gt;
The IBM 704 didn't have a stack.&lt;br /&gt;
This was not unusual at the time.  Most computer languages at the time had no need of a stack at all.  Algol, however, was a different story.  &lt;a href="http://en.wikipedia.org/wiki/Friedrich_L._Bauer"&gt;Friedrich L. (Fritz) Bauer&lt;/a&gt; had, a few years earlier, &lt;a href="http://www.freepatentsonline.com/3047228.pdf"&gt;invented the stack&lt;/a&gt; in order to support recursive descent evaluation of expressions.  This appeared to be the best way to support the recursion and block structure that ALGOL required.  As Alan Perlis notes:
&lt;br /&gt;
&lt;blockquote&gt;
It was ALGOL 60 that really pointed a finger at, focused on the
absolute necessity of learning how to define, control and
manipulate stacks.  ALGOL 60 would have been impossible to
adequately process in a reasonable way without the concept of
stacks.  Though we had stacks before, only in ALGOL 60 did stacks
come to take a central place in the design of processors.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;—&lt;a href="http://en.wikipedia.org/wiki/Alan_Perlis"&gt;Alan J. Perlis&lt;/a&gt;, &lt;em&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=1198354"&gt;Transcripts of  Presentation&lt;/a&gt;&lt;/em&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;
Not having a stack &lt;em&gt;can&lt;/em&gt; make it a bit of a challenge to program, but &lt;a href="http://en.wikipedia.org/wiki/Steve_Russell"&gt;Steve “Slug” Russell&lt;/a&gt; invented a different technique.  The assembly code of LISP I was written in &lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Continuation-passing_style"&gt;continuation-passing style&lt;/a&gt;&lt;/em&gt;.  (Russell did not name this technique; the phrase “continuation-passing style” seems to have been coined by Sussman and Steele in 1975.)&lt;br /&gt;
&lt;br /&gt;
When a program is converted to continuation-passing style, all control transfer can be expressed with &lt;code&gt;jump&lt;/code&gt; and &lt;code&gt;indirect jump&lt;/code&gt; operations.  This does not eliminate the need for temporary storage — any piece of re-entrant or recursive code will need to save and restore values in use as it calls subroutines — but it allows you to separate the control flow from the temporary storage management.
&lt;br /&gt;
&lt;blockquote&gt;
Closed subroutines in LISP are given a standard calling sequence.  The arguments of the subroutines are placed in order in the AC, the MQ, and locations called ARG3 and ARG4.&lt;/blockquote&gt;
&lt;blockquote&gt;
After the arguments have been provided, the subroutine is entered by a &lt;code&gt;TSX SUBR, 4&lt;/code&gt; where &lt;code&gt;SUBR&lt;/code&gt; is the location of the first instruction of the subroutine.  The subroutine ends with its value in the AC and the instruction &lt;code&gt;TRA 1,4&lt;/code&gt; which returns control to the instruction after the &lt;code&gt;TSX&lt;/code&gt; that set IR4.  Note that any other program can be executed between this &lt;code&gt;TSX&lt;/code&gt; and the &lt;code&gt;TRA 1,4&lt;/code&gt; so long as the contents of IR4 are restored to the value set by the &lt;code&gt;TSX&lt;/code&gt; before the &lt;code&gt;TRA&lt;/code&gt; is executed.  A subroutine restores all index registers it uses to the value they had on entering the subroutine.&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;—&amp;nbsp;S. Russell, Artificial Intelligence Project — RLE and MIT Computation Center, &lt;em&gt;Writing and Debugging Programs&lt;/em&gt; — &lt;a href="ftp://publications.ai.mit.edu/ai-publications/pdf/AIM-006.pdf"&gt;Memo 6&lt;/a&gt;
&lt;/blockquote&gt;
We can see this in the LISP 1.5 assembly code:&lt;br /&gt;
&lt;pre&gt;       REM
       REM APPEND(L1,L2)=
       REM (L1=0 YIELDS L2,1 YIELDS CONS(CAR(L1),APPEND(CDR(L1),L2))
A      HED
APPEND TNZ APNP1
       XCA
       &lt;span class="Apple-style-span" style="color: #b45f06;"&gt;TRA 1,4&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #e69138;"&gt;       &lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;** Invoke continuation (return)&lt;/span&gt;&lt;/i&gt;

 APNP1 &lt;span class="Apple-style-span" style="color: #0b5394;"&gt;SXD AS1,4&lt;/span&gt;     &lt;i&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;** Store continuation in memory&lt;/span&gt;&lt;/i&gt;
       &lt;span class="Apple-style-span" style="color: #b45f06;"&gt;TSX $SAVE,4&lt;/span&gt;   &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;i&gt;** Call&lt;/i&gt; SAVE &lt;i&gt;subroutine&lt;/i&gt;&lt;/span&gt;
       TXL     $END2,,CWR1+2      SAVE 2 ITEMS
       PDX 0,4
       CLA 0,4
       STO CWR1
       ANA DECM
       &lt;span class="Apple-style-span" style="color: #b45f06;"&gt;TSX APPEND,4&lt;/span&gt;  &lt;span class="Apple-style-span" style="color: #38761d;"&gt;** &lt;i&gt;Recursive call to&lt;/i&gt; APPEND&lt;/span&gt;
       XCA
       LXA CWR1,4
       PXD 0,4
       &lt;span class="Apple-style-span" style="color: #b45f06;"&gt;TSX UNSAVE,4&lt;/span&gt;  &lt;span class="Apple-style-span" style="color: #38761d;"&gt;** &lt;i&gt;Call&lt;/i&gt; UNSAVE &lt;i&gt;to restore temps&lt;/i&gt;&lt;/span&gt;
       &lt;span class="Apple-style-span" style="color: #0b5394;"&gt;LXD AS1,4&lt;/span&gt;     &lt;span class="Apple-style-span" style="color: #38761d;"&gt;** &lt;i&gt;Restore continuation to register&lt;/i&gt;&lt;/span&gt;
       &lt;span class="Apple-style-span" style="color: #b45f06;"&gt;TRA $CONS&lt;/span&gt;     &lt;span class="Apple-style-span" style="color: #38761d;"&gt;** &lt;i&gt;Tail call&lt;/i&gt; CONS&lt;/span&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3355559025792319601?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3355559025792319601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3355559025792319601' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3355559025792319601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3355559025792319601'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/no-stack-no-problem.html' title='No stack?  No problem.'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1299534943649072032</id><published>2011-02-24T12:33:00.000-08:00</published><updated>2011-02-28T15:36:16.822-08:00</updated><title type='text'>Where did the stack go?</title><content type='html'>&lt;i&gt;&lt;span class="Apple-style-span" style="color: #cc0000;"&gt;[This post doesn't describe things the way I'd like to.  Please see the subsequent post.]&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;

&lt;strike&gt;The IBM 704 didn't have a stack.&lt;br /&gt;
&lt;br /&gt;
This was not unusual at the time.  Although stacks were known about for years before, low-level languages did not make much use of them.  Early FORTRAN certainly didn't need a stack, so IBM didn't bother with a hardware implementation.&lt;br /&gt;
&lt;br /&gt;
Not having a stack does make it a bit of a challenge to program.  For example, when you call a subroutine, where does the return address go?&lt;br /&gt;
&lt;br /&gt;
The IBM 704 had an instruction &lt;code&gt;TSX&lt;/code&gt; (Transfer and Set Index) that was designed for subroutine linkage.  &lt;code&gt;TSX&lt;/code&gt; would do two things.  First, it loaded a register with the two's-complement value of the program counter.  (The IBM 704 was much better at subtraction than addition.  The two's complement of the program counter made it easier to dispatch because subtracting a two's complement number gives the same result as adding the uncomplemented number.) Second, it loaded the program counter with the subroutine address.  Loading the program counter would cause an unconditional jump to the subroutine.&lt;br /&gt;
&lt;br /&gt;
There was obviously a data path from the instruction register to the program counter — that's how the target address got from the instruction stream to the program counter.  Likewise, there was a data path from the program counter to the register set.  However, there doesn't appear to be a data path from the register set back in the other direction.  So we can use the &lt;code&gt;TSX&lt;/code&gt; instruction to call a subroutine, but once there we need to do a nasty trick to get back.  That trick is to end the subroutine with an unconditional jump (opcode &lt;code&gt;TRA&lt;/code&gt;).  When we enter the subroutine, we expect the return address to be in one of the registers (by convention, LISP used register 4).  The first thing the subroutine does is to save the return address in the target field of the &lt;code&gt;TRA&lt;/code&gt; instruction.  This modifies the code so that the unconditional jump at the end takes us back to where the subroutine is called.&lt;br /&gt;
&lt;br /&gt;
But what if the subroutine needs to be re-entrant?&lt;br /&gt;
&lt;br /&gt;
Ultimately, you need a stack (or a heap).  There are several options for implementing one.  The obvious idea of allocating a block of memory and keeping a pointer to the top of stack was not obviously the &lt;em&gt;best&lt;/em&gt; idea.  Without dedicated hardware, operations like push and pop become quite expensive.  You have to fetch the stack pointer from memory, perform an addition or subtraction, do an indirect memory reference, and write the new stack pointer back to memory.  (And if you thought the x86 didn't have enough registers, the IBM 704 had only 3 index registers.)&lt;br /&gt;
&lt;br /&gt;
Another method is to use a linked list as a stack.  This is not obviously a &lt;em&gt;bad&lt;/em&gt; idea.  Once the linked list is created at program initialization time, pushing and popping can be done via pointer chasing.  This avoids having to use the ALU for adding and subtracting the stack pointer.  Furthermore, you didn't have to guess how much stack space to reserve.  with only 32,000 words of memory, you didn't want to waste any on unused stack reserve.  For these reasons, both IPL and LISP I used a ‘push-down list’ to implement re-entrant subroutines.&lt;/strike&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1299534943649072032?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1299534943649072032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1299534943649072032' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1299534943649072032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1299534943649072032'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/where-did-stack-go.html' title='Where did the stack go?'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2175176405049438645</id><published>2011-02-23T14:31:00.000-08:00</published><updated>2011-02-23T14:31:23.480-08:00</updated><title type='text'>A harder puzzle</title><content type='html'>Suppose I have a procedure that needs to make temporary use of some expensive resource.  The usual way to code this up is something like this:&lt;pre&gt;
(defun foo (x)
  (let ((resource nil))   ; or #f or whatever
    (unwind-protect
        (progn (setq resource (obtain-resource pool))
               (compute x resource))
      (if (not (null resource))
          (return-resource pool resource)))))&lt;/pre&gt;
There are two problems with this.  The first is a minor race condition where the resource can be lost if an asynchronous interrupt is taken right after &lt;code&gt;obtain-resource&lt;/code&gt; returns but just before the value is assigned to the variable.  We'll ignore that problem for now.  The bigger problem is that we cannot easily spot the separation between the parts of &lt;code&gt;foo&lt;/code&gt; concerned with resource management and the parts needed for computing the return value.&lt;br /&gt;&lt;br /&gt;
What we want to do is abstract out the resource management:&lt;pre&gt;
(defun foo (x)
  (call-with-resource resource-pool
    (lambda (resource)
      (compute x resource))))

(defun call-with-resource (pool receiver)
  (let ((resource nil))
    (unwind-protect
        (progn (setq resource (obtain-resource pool))
               (funcall receiver resource))
      (if (not (null resource))
          (return-resource pool resource))))) 

&lt;/pre&gt;
(One could use macros here, too.)&lt;br /&gt;&lt;br /&gt;
Now we can see that &lt;code&gt;foo&lt;/code&gt; just supplies an additional argument to a call to &lt;code&gt;compute&lt;/code&gt;.  As an additional bonus, we have a simple idiom that correctly encapsulates the acquisition and release of our resource.  Other code that has the &amp;lsquo;boilerplate&amp;rsquo; needed to manage the resource can be simplified to use our wrapper.  It is less likely that resources are dropped by accidentally copying the boilerplate incorrectly.  This sort of wrapper code is frequently found in Lisp or Scheme.&lt;br /&gt;&lt;br /&gt;
The puzzle is &amp;ldquo;How do you do this in Java?&amp;rdquo;  To be more specific, suppose I have this code:&lt;pre&gt;
class Foo {
    ...
    public Answer method1 (int x) throws BadRequest {
        Resource resource = null;
        try {
            resource = pool.obtainResource();
            return computeAnswer (x, resource);
        } finally {
            if (resource != null)
                pool.returnResource(resource);
        }
    }

    private Answer computeAnswer (int x, Resource r) throws BadRequest {
        ....
    }
}

class Bar {
   ...
   public void method2 (Boolean flag, String name) throws NoSuchEntry {
        ExpensiveObject resource = null;
        try {
            resource = expensiveObjectPool.obtainResource();
            if (flag)
               resource.addName(name);
            doSomething(resource); 
        } finally {
            if (resource != null)
                expensiveObjectPool.returnResource(resource);
        }
    }

    private void doSomething (ExpensiveObject expo) throws NoSuchEntry {
        ....
    }      
}&lt;/pre&gt; 
and I want to write something more like this:
&lt;pre&gt;class Foo {
    ...
    public Answer method1 (int x) throws BadRequest {
        // WRAPPER CODE HERE
        return computeAnswer(x, resource);
        // POSSIBLE WRAPPER EPILOGUE
    }
 
    private Answer computeAnswer (int x, Resource r) throws BadRequest {
        ....
    }
}

class Bar {
   ...
   public void method2 (Boolean flag, String name) throws NoSuchEntry {
        // WRAPPER CODE HERE;
            if (flag)
               resource.addName(name);
            doSomething(resource); 
        // POSSIBLE WRAPPER EPILOGUE HERE
    }

    private void doSomething (ExpensiveObject expo) throws NoSuchEntry {
        ....
    }      
}&lt;/pre&gt; 
Where the wrapper and possible epilogue (if needed) are some relatively simple,
easy to use constructs like a method call or inner class declaration or whatever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2175176405049438645?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2175176405049438645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2175176405049438645' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2175176405049438645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2175176405049438645'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/harder-puzzle.html' title='A harder puzzle'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6600701263088544428</id><published>2011-02-23T12:07:00.000-08:00</published><updated>2011-02-23T12:07:22.942-08:00</updated><title type='text'>An easy puzzle</title><content type='html'>Suppose I have some code like this:&lt;pre&gt;
(defun foo (x)
  (wrapper-macro
    (bar 42 x)))&lt;/pre&gt;
Where &lt;code&gt;wrapper-macro&lt;/code&gt; simply prints &amp;lsquo;Normal exit&amp;rsquo; or &amp;lsquo;Throw&amp;rsquo; as control returns from &lt;code&gt;bar&lt;/code&gt; through &lt;code&gt;foo&lt;/code&gt;.  (If &lt;code&gt;bar&lt;/code&gt; returns normally, all the return values are returned from &lt;code&gt;foo&lt;/code&gt; after &lt;code&gt;wrapper-macro&lt;/code&gt; prints.  If &lt;code&gt;bar&lt;/code&gt; exits via a throw, then the throw continues after &lt;code&gt;wrapper-macro&lt;/code&gt; prints.)&lt;br /&gt;&lt;br /&gt;
The challenge:  Implement &lt;code&gt;wrapper-macro&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;
(If you wish, imagine that &lt;code&gt;wrapper-macro&lt;/code&gt; simply expands to this:&lt;pre&gt;
(defun foo (x)
  (wrapper-function
    (lambda ()
      (bar 42 x))))&lt;/pre&gt;
and the challenge is to implement &lt;code&gt;wrapper-function&lt;/code&gt;.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6600701263088544428?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6600701263088544428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6600701263088544428' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6600701263088544428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6600701263088544428'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/easy-puzzle.html' title='An easy puzzle'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8324207892324952437</id><published>2011-02-18T07:47:00.000-08:00</published><updated>2011-02-18T09:05:43.252-08:00</updated><title type='text'>An early LISP program (circa Feb. 1960)</title><content type='html'>&lt;pre&gt;       TST M948-371-P. FOX-EXERCISE 1
DEFINE
(((COLLAPSE,(LAMBDA,(L),(COND,
   ((ATOM,L), (CONS,L,NIL))
   ((NULL,(CDR,L)),
      (COND,((ATOM,(CAR,L)),L),(T,(COLLAPSE,(CAR,L)))))
   (T,(APPEND,(COLLAPSE,(CAR,L)),(COLLAPSE,(CDR,L))))
))))) ()
COLLAPSE ((((A,B),((C))),((D,(E,F)),(G),((H))))) ()
COLLAPSE ((A,(B,(C,(D,(E))),F,(G,(H,J))))) ()
COLLAPSE ((((((A),B),C),D),E)) ()
   STOP))))))))))STOP
        FIN M948-371-P. FOX-EXERCISE 1&lt;/pre&gt;
Notes:&lt;ol&gt;
&lt;li&gt;This example and the quotes below were taken from the LISP I manual by &lt;a href="http://en.wikipedia.org/wiki/Phyllis_Fox"&gt;Phyllis Fox&lt;/a&gt;.  The output from the program contains these two lines:&lt;br/&gt;
 &lt;code&gt;APPLY OPERATOR AS OF SEPTEMBER 1, 1959&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;THE TIME IS NOW  2/16 1139.5&lt;/code&gt;&lt;br /&gt;
so we can date the sample run.&lt;/li&gt;
&lt;li&gt;Each line above was punched on a separate card.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;TST&lt;/code&gt; (or &lt;code&gt;SET&lt;/code&gt;) card indicates the beginning of the program.  The &lt;code&gt;FIN&lt;/code&gt; card indicates the end.&lt;/li&gt;
&lt;li&gt;This is followed by triplets of the form &amp;lt;&lt;i&gt;function&lt;/i&gt;&amp;gt;, &amp;lt;&lt;i&gt;argument-list&lt;/i&gt;&amp;gt;, &amp;lt;&lt;i&gt;environment&lt;/i&gt;&amp;gt;.  Instead of &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;eval&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;, the main loop is more like &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;apply&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;STOP&lt;/code&gt; card has lots of extra close parens in order to keep the reader from consuming the entire card deck if the programmer didn't correctly close all the parens.&lt;/li&gt;
&amp;mdash; &amp;ldquo;&lt;i&gt;The read program reads until it finds the correct number of final parenthesis.&lt;/i&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;S-expressions were originally supposed to have commas between the elements.  The LISP I manual explains:  &amp;ldquo;&lt;i&gt;The commas in writing S-expressions may be omitted.  This is an accident.&lt;/i&gt;&amp;rdquo; The author of the reader took a shortcut and treated whitespace as commas.  &amp;ldquo;&lt;i&gt;The current version of the read program interprets a blank (space) as a comma, so that no blanks are allowed within atomic symbols.&lt;/i&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;i&gt;LISP II will be able to handle both integers and floating point numbers, but in LISP I integers are not allowed. ... Numbers are brought into a LISP program by being defined within S-expressions, and they must always be quoted.  For example, the following expression is correct&lt;/i&gt;, &lt;code&gt;(SUM,(QUOTE,0.6),X)&lt;/code&gt;&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;&lt;i&gt;Values of compiled functions are computed about 60 times faster than the S-expressions for the functions could be interpreted...  After a function has been compiled, it can be used as if it had been defined, but of course it will run much faster than it would have as an interpreted expression.&lt;/i&gt;&amp;rdquo;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8324207892324952437?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8324207892324952437/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8324207892324952437' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8324207892324952437'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8324207892324952437'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/early-lisp-program.html' title='An early LISP program (circa Feb. 1960)'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-372239701617335455</id><published>2011-02-17T10:32:00.000-08:00</published><updated>2011-02-17T10:32:43.007-08:00</updated><title type='text'>Observations on the Feeling of the Ugly and Insignificant</title><content type='html'>&lt;a href="http://www.blogger.com/profile/15407174467644060056"&gt;vsm001&lt;/a&gt; said...&lt;br /&gt;
&lt;i&gt; I neglected to add my biggest objection to Louis's project, the lack of a strictly (or lazily) functional subset.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;
Louis told me he is planning on writing a book about interpreter implementation.  I have offered to write prolegomena for any future meta-circularity, but Louis doesn't seem too keen on the idea.
&lt;br /&gt;&lt;br /&gt;
Anyway...&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/15407174467644060056"&gt;vsm001&lt;/a&gt; went directly to the meta-point of many of my posts:  &lt;em&gt;This is no way to go about designing a language.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;
&lt;b&gt;BUT&lt;/b&gt;, I wanted to explore a particular issue in the design space of languages, not whether we should be in the space in the first place.  In particular, let us assume &lt;em&gt;some&lt;/em&gt; plausible rationale for inventing a language and &lt;em&gt;then&lt;/em&gt; ask the questions that vsm001 raised.&lt;br /&gt;&lt;br /&gt;
vsm001 asked,&lt;br /&gt;
&lt;i&gt;What are the characteristics of problems that Reason is well-suited to solve?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;
I'll rephrase this.  What are the characteristics of problems that would be better solved by a language that has two complementary &amp;lsquo;modes&amp;rsquo; of operation as opposed to a language in which a single mode suffices?  In other words, neither of the two modes of Reason taken separately is quite powerful enough to be Turing complete, you really need &lt;em&gt;both&lt;/em&gt; of them; under what situations would this provide an advantage over using a single, Turing complete mode?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-372239701617335455?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/372239701617335455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=372239701617335455' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/372239701617335455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/372239701617335455'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/observations-on-feeling-of-ugly-and.html' title='Observations on the Feeling of the Ugly and Insignificant'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7428514048222873002</id><published>2011-02-15T12:02:00.000-08:00</published><updated>2011-02-15T12:02:05.885-08:00</updated><title type='text'>Critique of Reason</title><content type='html'>&lt;blockquote&gt;
&lt;i&gt;A language will not succeed without a good name. I have recently invented a very good name and now I am looking for a suitable language.&lt;/i&gt; &lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span align="right" width="100%"&gt;— Donald Knuth&lt;/span&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;br /&gt;
Louis Reasoner is developing a new computer language.  I'm letting him write this post.
&lt;br /&gt;
&lt;hr /&gt;
“I have already done the most important part:  the name of my language is &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt;.&lt;br /&gt;
&lt;br /&gt;
“The second most important thing is to come up with a trope.  This will enable me to defend my language decisions with a pithy reply and call it a design philosophy.  My trope is ‘reasonableness’.  &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt; will adhere to the philosophy of &lt;i&gt;reasonableness&lt;/i&gt;.  Anything in my language is, by definition, reasonable.  Anything omitted is naturally unreasonable.  Here is some more design philosophy:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Small is more reasonable than big.
&lt;/li&gt;
&lt;li&gt;Fast is more reasonable than slow.&lt;/li&gt;
&lt;li&gt;Useful is more reasonable than useless.&lt;/li&gt;
&lt;li&gt;Good is more reasonable than bad.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;etc., etc., etc....&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
I'll generate more later.&lt;br /&gt;
&lt;br /&gt;
&amp;ldquo;After the name and the self-styled philosophy, the next important thing is the syntax.  The syntax of &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt; is complicated, but reasonable.  Bear with me.  Although it might be a bit difficult to explain, it is, after sufficient practice, natural to use.&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt; borrows heavily from Lisp and Scheme.  Most of the programming in &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt; is done in &amp;lsquo;Lisp&amp;rsquo; mode.  Lisp mode is exactly what you think it would be:  you write programs just like you would in Lisp, but with a few modifications to make things more reasonable.
&lt;ul&gt;
&lt;li&gt;Prefix notation for everything by default, with these exceptions:
&lt;ul&gt;
&lt;li&gt;Infix notation for arithmetic. &amp;mdash; Let's just capitulate on this one.  Operator precedence will be fleshed out later.&lt;/li&gt;
&lt;li&gt;Excess parenthesis are ignored where it is unambiguous.  You can pretty much always add parenthesis to make something clearer or to override operator precedence.&lt;/li&gt;
&lt;li&gt;Function calls have the operator on the &lt;em&gt;outside&lt;/em&gt; of the parenthesis.  Not only is this more natural, it avoids weird interactions with operator precedence.  Arguments are separated by commas.&lt;/li&gt;
&lt;li&gt;Postfix notation for post-increment and post-decrement. &amp;mdash; I just like these.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;No &amp;lsquo;special&amp;rsquo; forms.  We get rid of 
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;define&lt;/code&gt; &amp;mdash; Lisp code tends to creep towards the right margin.  Removing internal definitions makes the code &amp;lsquo;flatter&amp;rsquo; and therefore easier to read.  &lt;em&gt;(Besides, it's hard to efficiently compile internal definitions.)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;begin&lt;/code&gt; &amp;mdash;  No good reason to include it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cond&lt;/code&gt; &amp;mdash; Too many parenthesis.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;let&lt;/code&gt; &amp;mdash; Again, too many parenthesis.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;lambda&lt;/code&gt; &amp;mdash; This is just too advanced.  Mere mortals can define a named procedure like anyone else would.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;letrec&lt;/code&gt; &amp;mdash; As if &lt;code&gt;lambda&lt;/code&gt; wasn't confusing enough!  Who comes up with this stuff?&lt;/li&gt;
&lt;li&gt;&lt;code&gt;quote&lt;/code&gt; &amp;mdash; Too confusing.  &lt;em&gt;Actually, I wanted to leave &lt;/em&gt;&lt;code&gt;quote&lt;/code&gt;&lt;em&gt; in, but with infix and postfix in the mix I couldn't figure out where the
quotation ended.  I decided to punt.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Assignment is allowed.  This is technically a &amp;lsquo;special form&amp;rsquo;, but it is so useful that I had to leave it in.&lt;/li&gt;
&lt;/ul&gt;
&amp;ldquo;Lisp mode is distinguished by its use of &lt;em&gt;nesting&lt;/em&gt; as the primary means of combination.  In fact, sequential combinations are disallowed.  Lisp mode constructs are created compositionally from other Lisp mode constructs or primitives.  Lisp mode is where most of the primitive procedures of the language are available.&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;In order to radically simplify Lisp mode I had to introduce &amp;lsquo;Program&amp;rsquo; mode.
Program mode is more imperative than Lisp mode, so I tried to reduce the functionality and power of Program mode so that people would favor Lisp mode.  Program mode has these features:
&lt;ul&gt;&lt;li&gt;Special forms &amp;mdash; Flow control, variable declaration and binding, conditionals, etc. are available in Program mode.&lt;/li&gt;
&lt;li&gt;No artificially rigid syntax &amp;mdash; Program mode is not really infix, prefix, or postfix.  Each construct defines its own syntax.  This improves readability for the built-in special forms.  For example, the &lt;code&gt;if&lt;/code&gt; construct can have a traditional &lt;code&gt;else&lt;/code&gt; clause rather than just having two or three subconstructs like in Lisp.&lt;/li&gt;
&lt;li&gt;No user-defined special forms &amp;mdash; The user doesn't have to memorize any additional special forms beyond the built-in ones.&lt;/li&gt;
&lt;li&gt;No arbitrary nesting &amp;mdash; In Program mode, you can only nest a construct if the enclosing construct permits it.  There &lt;em&gt;is&lt;/em&gt; nesting, it is just controlled.&lt;/li&gt;
&lt;li&gt;Concatenation for a means of combination &amp;mdash;  Lisp mode is obviously recursively evaluated.  This isn't needed in Program mode because arbitrary nesting is disallowed.  Instead,
user constructs in Program mode are built by concatenation of Program mode primitives.&lt;/li&gt;
&lt;li&gt;Easy switching to Lisp mode &amp;mdash; You can always concatenate a Lisp mode construct with a Program mode construct.  &lt;em&gt;Originally, I didn't want to do this, but I ended up duplicating a lot of the Lisp mode functionality.  By allowing the programmer to switch to Lisp mode pretty much whenever he wants, I avoided having to duplicate a lot of code.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&amp;ldquo;When you write a procedure in &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt;, you start in Program mode.  As I mentioned, you can switch to Lisp mode whenever you feel like it, but there is no way to switch back (&lt;em&gt;this isn't strictly true, you can mimic the ability to switch back by use of a function call.  The function body starts in Program mode.&lt;/em&gt;)  You can define a procedure in either Program mode or Lisp mode.  That is, you can explicitly mark a procedure as available in Program mode only or in Lisp mode only.  Of course since you can always switch to Lisp mode, it makes no discernible difference
if you define a procedure as Lisp mode only; you can use it in Program mode.   But if you define a procedure in Program mode only, you simply cannot use it from Lisp mode.  (It will be visible, you just can't call it.)&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;I could go on for hours about how variables are looked up, but I don't want to bore everyone.  I would like some feedback about my ideas so far, though.&lt;br /&gt;
&lt;hr&gt;
How about it?  Would any readers care to critique the design of &lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Reason&lt;/b&gt;&lt;/span&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7428514048222873002?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7428514048222873002/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7428514048222873002' title='15 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7428514048222873002'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7428514048222873002'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/critique-of-reason.html' title='Critique of Reason'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5094489417314364049</id><published>2011-02-14T14:32:00.000-08:00</published><updated>2011-02-14T14:32:59.795-08:00</updated><title type='text'>I whine too much.</title><content type='html'>&lt;i&gt;Mea culpa.&lt;/i&gt;&lt;pre&gt;
   ...
   for (Foo foo : permute(fooList)) {
        operateOnFoo (foo);
    }
   ...

  private static final Random rng = new Random();

  private static &amp;lt;E&amp;gt; List&amp;lt;E&amp;gt; permute (List&amp;lt;E&amp;gt; list) {
    List&amp;lt;E&amp;gt; answer = Lists.newArrayList (list);
    Collections.shuffle (answer, rng);
    return answer;
  }&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5094489417314364049?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5094489417314364049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5094489417314364049' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5094489417314364049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5094489417314364049'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/i-whine-too-much.html' title='I whine too much.'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8204782499004680423</id><published>2011-02-08T17:42:00.000-08:00</published><updated>2011-02-08T17:42:20.521-08:00</updated><title type='text'>More about shuffle.</title><content type='html'>In my last post, I asked why&lt;br /&gt;
&lt;code&gt;public static void shuffle(List&amp;lt;?&amp;gt; list)&lt;/code&gt;
was given a &amp;lsquo;B&amp;rsquo; grade.  A few readers didn't see the
problem, so I thought I'd clarify.&lt;br /&gt;&lt;br /&gt;

I was writing code to perform some operations on the elements of a collection.  Multiple copies of the code will be running.  I want to avoid having each copy being synchronized with the others, so it makes sense to iterate over the list elements in a non-deterministic order.  This will not prevent multiple instances of the code from occasionally &amp;lsquo;colliding&amp;rsquo; on a single object, but it will make this case the exception rather than the rule.&lt;br /&gt;&lt;br /&gt;
I originally wrote the code using a &lt;code&gt;Set&amp;lt;Foo&amp;gt;&lt;/code&gt; rather than a &lt;code&gt;List&amp;lt;Foo&amp;gt;&lt;/code&gt; because there is no natural ordering of &lt;code&gt;Foo&lt;/code&gt; objects.  The code looked like this:&lt;pre&gt;
    for (Foo foo : fooSet) {
        operateOnFoo (foo);
    }&lt;/pre&gt;
where &lt;code&gt;fooSet&lt;/code&gt; was an instance variable declared as &lt;code&gt;Set&amp;lt;Foo&amp;gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;
A &lt;code&gt;Set&lt;/code&gt; is an &lt;em&gt;unordered&lt;/em&gt; abstraction.  Obviously, an &lt;code&gt;iterator&lt;/code&gt; on a &lt;code&gt;Set&lt;/code&gt; will return the objects is &lt;em&gt;some&lt;/em&gt; order, but abstractly, there is no meaningful way to &amp;lsquo;change&amp;rsquo; the order of the &lt;code&gt;Set&lt;/code&gt; itself.  A &lt;code&gt;List&lt;/code&gt;, on the other hand, is an &lt;em&gt;ordered&lt;/em&gt; abstraction that imposes a &lt;em&gt;external&lt;/em&gt; order on the elements.  (An &lt;code&gt;array&lt;/code&gt; imposes the additional unnecessary constraints of compactedness on the indexes and random access.)  Changing the instance variable from &lt;code&gt;Set&amp;lt;Foo&amp;gt;&lt;/code&gt; to a &lt;code&gt;List&amp;lt;Foo&amp;gt;&lt;/code&gt; was trivial.&lt;br /&gt;&lt;br /&gt;
The problem is now to &amp;lsquo;iterate pseudorandomly&amp;rsquo;.  Pseudorandom iteration is not an uncommon operation, so I assumed there was a way to do it.  Pseudorandom iteration is not common
enough that a special iteration construct would be defined for it, so I assumed I would simply use a normal iterator and iterate over a permutation of the list.  What immediately came to mind was something like:&lt;pre&gt;    for (Foo foo : fooList.permute()) {
        operateOnFoo (foo);
    }&lt;/pre&gt;
That doesn't work.&lt;br /&gt;&lt;br /&gt;
So Java doesn't provide a &amp;lsquo;permute&amp;rsquo; method on a list.  I vaguely recalled that Java had something called &amp;lsquo;shuffle&amp;rsquo; rather than &amp;lsquo;permute&amp;rsquo;.  However, the &lt;code&gt;List&lt;/code&gt; class doesn't have a &amp;lsquo;shuffle&amp;rsquo; method either.  None of the methods on a &lt;code&gt;List&lt;/code&gt; will permute it.  That is strange because permuting a list is a fairly common operation.&lt;br /&gt;&lt;br /&gt;
I was &lt;em&gt;sure&lt;/em&gt; that I had seen &amp;lsquo;shuffle&amp;rsquo; &lt;em&gt;somewhere&lt;/em&gt;, so I hauled out &lt;code&gt;grep&lt;/code&gt; to search for some code that called it.  I found some and chased down the documentation.  The &lt;code&gt;shuffle&lt;/code&gt; method is a static method in the &lt;code&gt;Collections&lt;/code&gt; class.  This means that I have to use a different syntax:&lt;pre&gt;    for (Foo foo : Collections.shuffle(fooList)) {
        operateOnFoo (foo);
    }&lt;/pre&gt;
That doesn't work.&lt;br /&gt;&lt;br /&gt;
The &lt;code&gt;shuffle&lt;/code&gt; method mutates its argument but does not return a value.  This means I cannot simply call the method as an expression, but I have to hoist the call to the nearest &amp;lsquo;Command&amp;rsquo; level:&lt;pre&gt;    Collections.shuffle(fooList);
    for (Foo foo : fooList) {
        operateOnFoo (foo);
    }&lt;/pre&gt;
That works, but now I have to revisit my original design:  is it OK to directly shuffle the fooList, or should I copy it first?  Fortunately, I don't need a copy.&lt;br /&gt;&lt;br /&gt;
To recap, what I wanted to write was this:
&lt;pre&gt;    for (Foo foo : fooList.permute()) {
        operateOnFoo (foo);
    }&lt;/pre&gt;what I had to write was this:
&lt;pre&gt;    Collections.shuffle(fooList);
    for (Foo foo : fooList) {
        operateOnFoo (foo);
    }&lt;/pre&gt;
By making shuffle &amp;lsquo;return&amp;rsquo; &lt;code&gt;void&lt;/code&gt;, the author has relegated the method to &lt;em&gt;command&lt;/em&gt; contexts only.  I happened to want to use it in an &lt;em&gt;expression&lt;/em&gt; context.&lt;br /&gt;&lt;br /&gt;
I'm sure a lot of readers are wondering &amp;ldquo;So what?&amp;rdquo;  It is in fact a trivial point, and now that I've discovered how to permute a list I doubt I'll encounter this particular problem in the future.  But the point is that Java distinguishes between &lt;em&gt;commands&lt;/em&gt; and &lt;em&gt;expressions&lt;/em&gt;.  You are prohibited from using a &lt;em&gt;command&lt;/em&gt; where an &lt;em&gt;expression&lt;/em&gt; is called for.  However, you &lt;em&gt;are&lt;/em&gt; permitted to use an &lt;em&gt;expression&lt;/em&gt; where a &lt;em&gt;command&lt;/em&gt; is called for.  The programmer has to keep track of which things are &lt;em&gt;commands&lt;/em&gt; because they require a command context.  The programmer doesn't have to remember which things are &lt;em&gt;expressions&lt;/em&gt; because they can be used in either context.  By making &lt;code&gt;shuffle&lt;/code&gt; a command, the author has added yet another item to my mental &amp;ldquo;remember these aren't expressions&amp;rdquo; list.  If &lt;code&gt;shuffle&lt;/code&gt; returned the shuffled list, I wouldn't have to think about it at all.&lt;br /&gt;&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/04144052171693893368"&gt;Arcane Sentiment&lt;/a&gt; noted that &amp;ldquo; Java uses the return type as a way of declaring that the operation has side effects... &amp;rdquo;.  I guess I'm weird because I use the return type to declare the type of object that will be returned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8204782499004680423?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8204782499004680423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8204782499004680423' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8204782499004680423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8204782499004680423'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/more-about-shuffle.html' title='More about shuffle.'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5807002319803153124</id><published>2011-02-04T12:16:00.000-08:00</published><updated>2011-02-04T12:16:54.338-08:00</updated><title type='text'>What's wrong with this?</title><content type='html'>The &lt;code&gt;java.util.Collections&lt;/code&gt; library has this method:&lt;br /&gt;
&lt;code&gt;public static void shuffle(List&amp;lt;?&amp;gt; list)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;
Were this homework, I'd give it a solid &amp;lsquo;B&amp;rsquo;.  Readers are encouraged to suggest improvements.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5807002319803153124?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5807002319803153124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5807002319803153124' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5807002319803153124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5807002319803153124'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/02/whats-wrong-with-this.html' title='What&apos;s wrong with this?'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4867971557617554243</id><published>2011-01-31T10:44:00.000-08:00</published><updated>2011-01-31T10:44:54.964-08:00</updated><title type='text'>Replies to comments</title><content type='html'>&lt;a href="http://www.blogger.com/profile/13416750891822431224"&gt;steck&lt;/a&gt; said...&lt;br /&gt;
&lt;em&gt;Haskell type classes give a consistent interface to different kinds of numbers (among other things).  Would that do here?&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;
It would solve the problems with the built-in number hierarchy.  Does Haskell allow you to add user defined subtypes to the built-in number types?&lt;br /&gt;&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/08443579312529087120"&gt;Jevon&lt;/a&gt; said...&lt;br /&gt; 
&lt;em&gt; Are you saying that we shouldn&amp;#39;t develop using design patterns?&lt;/em&gt;
No, there's nothing wrong with the pattern &lt;em&gt;per se&lt;/em&gt;.  I'm saying that if we have programming concept that is important enough and ubiquitous enough that we can identify it and name it (for example, &amp;ldquo;The Factory Pattern&amp;rdquo; or &amp;ldquo;Singletons&amp;rdquo;), then there should be a way of &lt;em&gt;abstracting&lt;/em&gt; it so that the pattern is replaced by something much more lightweight, or, if possible, nothing at all.&lt;br /&gt;&lt;br /&gt;
&lt;em&gt;You can&amp;#39;t argue against Factory objects using Factorial as an example. That&amp;#39;s like arguing against using Windows when you&amp;#39;re using Notepad as an example.&lt;/em&gt;&lt;br /&gt;
Notepad might be an effective example for certain types of arguments.  Factorial obviously shouldn't be encapsulated and turned into a first-class object, it's absurd.  But the language &lt;em&gt;does&lt;/em&gt; require that it be encapsulated in &lt;em&gt;some&lt;/em&gt; kind of object, nonetheless.&lt;br /&gt;&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/02334444138117915241"&gt;Michael&lt;/a&gt; said...&lt;br /&gt;
&lt;em&gt;Java is verbose, way too verbose in areas that should be concise.&lt;/em&gt;&lt;br /&gt;
True, but I'm not necessarily complaining about the verbosity.  I'm complaining that there is no reasonable way to avoid, eliminate, or abbreviate the verbosity.&lt;br /&gt;&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/09875316335816494943"&gt;Hardware Critic&lt;/a&gt; said...&lt;br /&gt; 
&lt;em&gt;His point is that Java has created a culture where developers over-generalize (violating the &lt;/em&gt;en vogue&lt;em&gt; You Ain&amp;#39;t Gonna Need It principle) and create frameworks rather than customized solutions. You turned it on its side and asked &amp;quot;why should developers &lt;/em&gt;ever&lt;em&gt; have to do this junk&amp;quot; and made it a criticism of the Java language.&lt;/em&gt;&lt;br /&gt;Just so.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;
But in doing so, you take code decorated with &amp;quot;don&amp;#39;t do this&amp;quot; and then point to it as an example of Java&amp;#39;s failings.&lt;br /&gt;You say &amp;quot;but what about the 1% of people who need all that extra nonsense?&amp;quot;, but remember Mr. Woody&amp;#39;s point is that developers should create bespoke solutions providing only the power necessary to solve the problem at hand rather than large general frameworks.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;
I don't think we are contradicting each other.  Let's take the &amp;ldquo;Singleton&amp;rdquo; pattern as an example.  Mr. Woody and I both agree that a Singleton would be an unnecessary complication to the factorial class, but we disagree on &lt;em&gt;why&lt;/em&gt;.  If you look at the Wikipedia article on &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singletons&lt;/a&gt;, you'll see that there are three examples of how to write singletons in Java:
&lt;pre&gt;// Examples taken from Wikipedia
public class Singleton {
 
    private static final Singleton INSTANCE = new Singleton();
 
    // Private constructor prevents instantiation from other classes
    private Singleton() {
    }
 
    public static Singleton getInstance() {
        return INSTANCE;
    }
 
}

// Solution suggested by Bill Pugh
public class Singleton {
 
   // Private constructor prevents instantiation from other classes
   private Singleton() {
   }
 
   /**
    * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
    * or the first access to SingletonHolder.INSTANCE, not before.
    */
   private static class SingletonHolder { 
     public static final Singleton INSTANCE = new Singleton();
   }
 
   public static Singleton getInstance() {
     return SingletonHolder.INSTANCE;
   }
 
 }

// Modern way suggested by Joshua Bloch
 public enum Singleton {
   INSTANCE;
 }
&lt;/pre&gt;
All three are missing my point.  They say, &amp;ldquo;The correct way to use singletons is to write your code like this.&amp;rdquo;  What they &lt;em&gt;ought&lt;/em&gt; to say is &amp;ldquo;The correct way for an implementation of singletons to behave is as if your code were written like this.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
A programmer who decides to use singletons (correctly or incorrectly) ought to be able to write something like:
&lt;pre&gt;public singleton FactorialUtil
{
    public static int factorial(int n)
    {
        if (n == 0) return 1;
        return n * factorial(n-1);
    }
}&lt;/pre&gt;
Yes, it is stupid to do this for something like the factorial program, but it clearly states my (poorly considered) intention, was trivial to do, trivial to undo, and best of all, theoretically allows me to change the implementation of singletons from &amp;ldquo;traditional&amp;rdquo; to &amp;ldquo;Pugh style&amp;rdquo; without having to look at all the places singletons are used.&lt;br /&gt;&lt;br /&gt;
I'd have to post a much larger program and then spend time arguing the merits of singletons if I had to give a &amp;ldquo;real world&amp;rdquo; example.
&lt;br /&gt;&lt;br /&gt;&lt;em&gt;
Your point that Java requires significant boilerplate in order to say what needs to be said is valid, if not particularly novel. Even so, using code which was written in an intentionally convoluted way to criticize Java&amp;#39;s convolution is like using the winner of the Obfuscated C Code contest to demonstrate that C is difficult to read.&lt;/em&gt;&lt;br /&gt;
It is hard to make concise arguments against convolution without needlessly convoluting a concise piece of code.  A situation like this in real life usually involves a truly huge pile of awful code which makes the blog post far too large and contains many additional problems that hide the point I'm trying to make.&lt;br /&gt;&lt;br /&gt;
&lt;a href="http://www.blogger.com/profile/03095166606444968520" &gt;Jason Wilson&lt;/a&gt;  said...
&lt;em&gt;The Development Chaos Theory article is largely concerned with factories.  Factories are used all the time in Scheme and nobody ever complains because both the use and definitions are easy and natural:&lt;br /&gt;&lt;br /&gt;USE:&lt;br /&gt;((*factorial-function-factory*) 5)&lt;br /&gt;&lt;br /&gt;POSSIBLE DEF:&lt;br /&gt;(fluid-let (*factorial-function-factory*&lt;br /&gt;  (lambda (n) ....))&lt;br /&gt;&lt;br /&gt;How *factorial-function-factory* got defined should not matter to the code depending on it.  It&amp;#39;s there.  I promise.  (Guice gives absolutely no more guarantees that it&amp;#39;s defined and it is the best in class dynamic variable  err, dependency injection framework for Java).&lt;br /&gt;&lt;br /&gt;The Development Chaos Theory article is of course ridiculous for treating fact as a function that needs to be so abstracted, but without dynamic variables, this really is a necessary pattern in Java in many real world cases.&lt;/em&gt;&lt;br /&gt;
Exactly.  There's just one refinement I'd suggest.  &lt;code&gt;(let ((factorial (make-instance &amp;lt;factorial-function&amp;gt;))) (factorial 5))&lt;/code&gt;  Object frameworks like CLOS provide a &amp;lsquo;universal factory&amp;rsquo; generic function.  And I'd suggest this definition of &lt;code&gt;
&amp;lt;factorial-function&amp;gt;&lt;/code&gt;&lt;pre&gt;(defclass &amp;lt;factorial-function&amp;gt; () (:metaclass singleton))&lt;/pre&gt;
The definition of the &lt;code&gt;singleton&lt;/code&gt; metaclass would contain code analagous to Bill Pugh's implementation.&lt;br /&gt;&lt;br /&gt;
But this doesn't answer Mr. Woody's objection that this is &lt;em&gt;completely&lt;/em&gt; unnecessary.  In that case, I suggest this &lt;em&gt;alternative&lt;/em&gt; definition of &lt;code&gt;
&amp;lt;factorial-function&amp;gt;&lt;/code&gt;&lt;pre&gt;
;; Unnecessary
;; (defclass  &amp;lt;factorial-function&amp;gt; () (:metaclass singleton))

(defmethod make-instance ((class (eql (find-class '&amp;lt;factorial-function&amp;gt;))) &amp;rest initargs)
    #'factorial)&lt;/pre&gt;
I have overloaded &lt;code&gt;make-instance&lt;/code&gt; in this one case to not even instantiate an object but to return the factorial procedure as a natural singleton.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4867971557617554243?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4867971557617554243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4867971557617554243' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4867971557617554243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4867971557617554243'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/replies-to-comments.html' title='Replies to comments'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5778419089905830252</id><published>2011-01-28T15:04:00.000-08:00</published><updated>2011-01-28T15:04:09.949-08:00</updated><title type='text'>HowWhy  (not) to write Factorial in Java.</title><content type='html'>In “&lt;a href="http://chaosinmotion.com/blog/?p=622"&gt;Development Chaos Theory&lt;/a&gt;”, William Woody laments the habits of bad Java programmers.  I blame the language.&lt;br /&gt;
&lt;br /&gt;
Before I start ranting, let me first say that I agree completely with Mr. Woody.  If you haven't read his article, I suggest you do now.
&lt;br /&gt;&lt;br /&gt;
Let's follow the example.
&lt;br /&gt;
&lt;pre&gt;/** 
 * @author wwoody
 */
public static int factorial(int n)
{
    if (n == 0) return 1;
    return n * factorial(n-1);
}&lt;/pre&gt;
This is presented as a typical way someone might write this in Java.  I might have written it slightly differently:
&lt;br /&gt;
&lt;pre&gt;public static int factorial(int n)
{
    return &lt;span class="Apple-style-span" style="background-color: #fff2cc;"&gt;(n == 0) ? 1 : n * factorial (n - 1)&lt;/span&gt;;
}&lt;/pre&gt;
There is only a subtle difference between these.  &lt;code&gt;return&lt;/code&gt;, in its fully general form, is a non-local exit.  It returns out of the enclosing &lt;em&gt;method&lt;/em&gt; instead of out of the enclosing &lt;em&gt;form&lt;/em&gt;.  The difference becomes obvious if you attempt to manually inline the factorial method.
&lt;br /&gt;
&lt;pre&gt;public static foo (int x)
{
    int y = &lt;span class="Apple-style-span" style="background-color: #fff2cc;"&gt;(x == 0) ? 1 : x * factorial (x - 1)&lt;/span&gt;;
    &lt;em&gt;...etc.&lt;/em&gt;
}

public static bar (int x)
{
    int y = &lt;span class="Apple-style-span" style="background-color: #f4cccc;"&gt;if (x == 0) return 1;&lt;/span&gt;
            &lt;span class="Apple-style-span" style="background-color: #f4cccc;"&gt;return n * factorial(n-1);&lt;/span&gt;
    &lt;em&gt;...etc.&lt;/em&gt;
}&lt;/pre&gt;
Either way appears to be acceptable Java to me.&lt;br /&gt;
&lt;br /&gt;
There should already be warning bells ringing.  I have to admit that I didn't hear them
the first time I looked at this code, though.  I'm so inured to this crap that I missed a glaring problem.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt; Why do these methods have type declarations?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt; Java doesn't do type inference.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio&lt;/b&gt;: Ok, that's lame, but why not just declare everything to be &lt;code&gt;Object&lt;/code&gt;?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt; Objects are too general.  The &lt;code&gt;*&lt;/code&gt; method doesn't work on them.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt; Of course!  We want the most general type that supplies &lt;code&gt;==&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, and &lt;code&gt;-&lt;/code&gt; operations.  So let's use &lt;code&gt;Number&lt;/code&gt;.&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  Hold your horses, cowboy.  Arithmetic doesn't work on &lt;code&gt;Number&lt;/code&gt;s.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  What?  Whyever not?!&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  Arithmetic only works on &lt;code&gt;byte&lt;/code&gt;, &lt;code&gt;double&lt;/code&gt;,
 &lt;code&gt;float&lt;/code&gt;, &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;long&lt;/code&gt;, and
 &lt;code&gt;short&lt;/code&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  &lt;code&gt;factorial&lt;/code&gt; should work on any of these.  Why do I have to pick one?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  The semantics of these types aren't compatible.  They behave quite differently at the very ends of their ranges.  There is no way to unify them under a superclass and still preserve the subclass semantics.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  umm... whatever.  What about that &lt;code&gt;static&lt;/code&gt; thingy?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  That doesn't matter.  You aren't using any objects.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  If it doesn't matter, why do I have to specify it?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  It would matter if you &lt;em&gt;were&lt;/em&gt; using objects.  It tells the compiler that free identifiers should have class scope.  By specifying &lt;code&gt;static&lt;/code&gt;, you're indicating that you want lexical scope.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  But that doesn't matter because I'm not using any objects.&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt; Right.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  If it doesn't matter, why do I have to specify it?&lt;br /&gt;
&lt;br /&gt;
Then Mr. Woody wraps the method in a utility class:
&lt;br /&gt;
&lt;pre&gt;/** 
 * @author wwoody
 */
public class FactorialUtil
{
    public static int factorial(int n)
    {
        if (n == 0) return 1;
        return n * factorial(n-1);
    }
}&lt;/pre&gt;
and suggests an iterative implementation
&lt;br /&gt;
&lt;pre&gt;/** 
 * @author wwoody
 */
public class FactorialUtil
{
    public static int factorial(int n)
    {
        int ret = 1;
        for (int i = 1; i &amp;lt;= n; ++i) ret *= i;
        return ret;
    }
}&lt;/pre&gt;
&lt;b&gt;Simplicio:&lt;/b&gt; Ummm....&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  You don't want to know.  In this case, we're not really using the class, but you'll want it later to avoid namespace conflicts.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt; I guess... Isn't namespace management is more of a configuration control issue than a datatype issue?  Wouldn't I want these to be orthogonal issues?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  They &lt;em&gt;can&lt;/em&gt; be handled orthogonally, but that requires some serious hacking.  Right now all you want is a simple &lt;code&gt;factorial&lt;/code&gt; problem, so just use the default.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  What default?&lt;br /&gt;
&lt;b&gt;Salviati:&lt;/b&gt;  Just pick a name.  Remember, though, the class name should be the same as the file name.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Simplicio:&lt;/b&gt;  If it is the default, why do I have to do &lt;em&gt;anything&lt;/em&gt;?&lt;br /&gt;
&lt;br /&gt;
Mr. Woody now suggests that &lt;code&gt;BigInteger&lt;/code&gt; is the right return type.  We'll fix the code:
&lt;br /&gt;
&lt;pre&gt;public class FactorialUtil
{
    public static BigInteger factorial(int n)
    {
        if (n == 0) return BigInteger.ONE;
        return BigInteger.valueOf(n).multiply(factorial(n-1));
    }
}

&lt;em&gt;alternatively...&lt;/em&gt;
/** 
 * @author wwoody
 */
public class FactorialUtil
{
    public static BigInteger factorial(int n)
    {
        BigInteger ret = BigInteger.ONE;
        for (int i = 1; i &amp;lt;= n; ++i) ret = ret.multiply(BigInteger.valueOf(i));
        return ret;
    }
}&lt;/pre&gt;
What we're seeing here is already serious problem.  Changing the &lt;em&gt;range&lt;/em&gt; of the output is a trivial change, yet it requires large changes to the code.  Here we have the original code and the modified code with the changes highlighted.&lt;br /&gt;
&lt;pre&gt;// &lt;em&gt;before changes...&lt;/em&gt;
/** 
 * @author wwoody
 */
public class FactorialUtil
{
    public static &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;int&lt;/span&gt; factorial(int n)
    {
        &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;int&lt;/span&gt; ret = &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;1&lt;/span&gt;;
        for (int i = 1; i &amp;lt;= n; ++i) ret &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;*=&lt;/span&gt; i;
        return ret;
    }
}
// &lt;em&gt;after changes...&lt;/em&gt;
/** 
 * @author wwoody
 */
public class FactorialUtil
{
    public static &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;BigInteger&lt;/span&gt; factorial(int n)
    {
        &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;BigInteger&lt;/span&gt; ret = &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;BigInteger.ONE&lt;/span&gt;;
        for (int i = 1; i &amp;lt;= n; ++i) ret &lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;= ret.multiply(BigInteger.valueOf(&lt;/span&gt;i&lt;span class="Apple-style-span" style="background-color: #ea9999;"&gt;))&lt;/span&gt;;
        return ret;
    }
}&lt;/pre&gt;&lt;br /&gt;
Sometimes, when you are building a big system, you want to transparently install a far-reaching package.  This doesn't happen often, but it happens more often than you might think.  Take, for example, the &lt;a href="http://groups.csail.mit.edu/mac/users/gjs/6946/refman.txt"&gt;scmutils&lt;/a&gt; library.  This library augments the standard generic arithmetic in MIT Scheme so that the usual arithmetic operators can handle vectors, matrices, and functions in addition to integers, rationals and reals.  No changes need to be made to the code that &lt;em&gt;calls&lt;/em&gt; the arithmetic methods.  This makes life a lot easier for developers who will not have to remember whether to use the built-in arithmetic or to switch to the extended package.&lt;br /&gt;&lt;br /&gt;
&lt;br /&gt;
Mr. Woody now points out that one might want to memoize the answers.&lt;br /&gt;
&lt;pre&gt;/** 
 * @author wwoody
 */
public class FactorialUtil
{
    static HashMap&lt;integer,biginteger&gt; cache = new HashMap&lt;integer,biginteger&gt;();

    public static BigInteger factorial(int n)
    {
        BigInteger ret;

        if (n == 0) return BigInteger.ONE;
        if (null != (ret = cache.get(n))) return ret;
        ret = BigInteger.valueOf(n).multiply(factorial(n-1));
        cache.put(n, ret);
        return ret;
    }
}&lt;/integer,biginteger&gt;&lt;/integer,biginteger&gt;&lt;/pre&gt;
To quote, “easy enough.”&lt;br /&gt;
&lt;br /&gt;
Except it isn't.  Memoization is a general technique that has nothing to do with the factorial program.  Yet it isn't abstracted out of the problem.  Tom White wrote an &lt;a href="http://onjava.com/pub/a/onjava/2003/08/20/memoization.html"&gt;article&lt;/a&gt; on how to use &lt;em&gt;Dynamic Proxy Classes&lt;/em&gt; to perform this abstraction.  The code is a bit convoluted, but that doesn't matter because when all is said and done, we can just memoize that call to factorial.&lt;br /&gt;
&lt;br /&gt;
That's the theory, anyway.  It turns out that you'll need to build an &lt;code&gt;interface&lt;/code&gt; to the factorial class and then memoize that:
&lt;br /&gt;
&lt;pre&gt;/** 
 * @author wwoody
 */
public interface FactorialAlgorithm 
{
  public BigInteger factorial(final int n);
}&lt;/pre&gt;
&lt;pre&gt;
/** 
 * @author wwoody
 */
public class FactorialUtil implements FactorialAlgorithm
{
    public BigInteger factorial(int n)
    {
        BigInteger ret = BigInteger.ONE;
        for (int i = 1; i &amp;lt;= n; ++i) ret = ret.multiply(BigInteger.valueOf(i));
        return ret;
    }
}&lt;/pre&gt;
&lt;pre&gt;FactorialAlgorithm originalFactorial = new FactorialUtil();
FactorialAlgorithm memoizedFactorial =
   (FactorialProgram) Memoizer.memoize(new FactorialUtil());&lt;/pre&gt;
That's better, but there's still a problem.  All the places in the code where you used to call &lt;code&gt;FactorialUtil.factorial(n)&lt;/code&gt; now need to change to use the interface instead: &lt;code&gt;memoizedFactorial.factorial(n)&lt;/code&gt;.  And every caller has to have access to an instance of the dynamic proxy class at runtime.&lt;br /&gt;&lt;br /&gt;
Let's continue.  Mr. Woody points out that we want to select which version of factorial to use at runtime.  After all, we don't even need the BigInteger version if the actual data only contains single digit numbers.  To do this, he suggests a factory class that can examine configuration data and instantiate the appropriate implementation.  I won't bore you with the details.&lt;br /&gt;&lt;br /&gt;
Mr. Woody then asserts:
&lt;blockquote&gt;Sure, there are circumstances where a pluggable architecture would be desirable or even necessary&amp;mdash;but that comes up so rarely it’s not even funny. About 99% of the time I see code like this, it’s completely and utterly useless. It’s obscuring the purpose of the code&amp;mdash;replacing a two or three line utility (max!) with dozens or even hundreds of lines of self-important masturbatory Java bullshit. Sure, it may make you feel good&amp;mdash;but it makes an ugly mess of it that future developers will have to clean up, or more likely just avoid like the plague.&lt;/blockquote&gt;
Again, I want to stress that I agree with Mr. Woody and I'm not attempting to argue against him.  
And here I'd like to interject and raise a point.  What about the rare situations?  About 1% of the time you really &lt;em&gt;do&lt;/em&gt; want a pluggable architecture, and code like this is &lt;em&gt;not&lt;/em&gt; completely useless.  The problem is that you &lt;em&gt;still&lt;/em&gt; need &amp;ldquo;dozens or even hundreds of lines of self-important masturbatory (but necessary) Java bullshit.&amp;rdquo;  Since there is a need for a pluggable architecture, you can be sure that future developers won't be trying to clean it up.  Unfortunately, that leaves &amp;ldquo;avoid like the plague&amp;rdquo; as our option.&lt;br /&gt;&lt;br /&gt;
Mr. Woody says:
&lt;blockquote&gt;The biggest complaint I have with many Java developers is that they develop a whole bunch of really bad habits. Specifications are unclear, or they think someday the code may need to be extended into a different direction. So they write a whole bunch of overblown architectural nonsense, sight unseen, thinking that the additional crap someday will help out and make things easier.&lt;/blockquote&gt;
But how does this differ from the case where the additional crap really does make things easier?  The code doesn't change simply because it becomes more useful.  It is still a whole bunch of overblown architectural nonsense.  The only difference is that you are forced to use this crap because it is the only way to get things done when the simple solution is insufficient.&lt;br /&gt;&lt;br /&gt;
My complaint with Java is that it tends to exacerbate a bad situation.  Small conceptual changes to code, like changing an int to a BigInteger, end up being large textual changes.  Larger conceptual changes, like adding a Factory object or a dynamically pluggable implementation, cannot be abstracted out.  This leads to big piles of additional crap that have to be replicated all over the place.  The language is unfriendly to change and modern software development is all about managing changes to the body of code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5778419089905830252?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5778419089905830252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5778419089905830252' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5778419089905830252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5778419089905830252'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/how-why-not-to-write-factorial-in-java.html' title='&lt;s&gt;How&lt;/s&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;color: #a64d79; font-family: &apos;Comic Sans MS&apos;, Arial, sans-serif;&quot;&gt;Why&lt;/span&gt;  (not) to write Factorial in Java.'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2746365197995270793</id><published>2011-01-28T11:00:00.000-08:00</published><updated>2011-01-28T11:00:26.127-08:00</updated><title type='text'>A day in the life</title><content type='html'>I seem to have a career as a professional software engineer. &amp;nbsp;Don't get me wrong, I love doing it, but somehow my avocation became my vocation. &amp;nbsp;C'est la guerre.&lt;br /&gt;
&lt;br /&gt;
Last night I was thinking about what my job really entails and it is a bit different from what I usually think and tell people. &amp;nbsp;The exciting part is taking a poorly formed concept, refining it to a very detailed and well-formed formal concept, translating the ideas to software, and making a tool or service that people can use. &amp;nbsp;There is a tedious part, too. &amp;nbsp;Frankly, I don't find it too monotonous because it involves a lot of puzzle solving and finding creative solutions, but it is necessary work that doesn't seem&lt;i&gt; logically &lt;/i&gt;necessary, and that tends to dampen my enthusiasm for doing it.&lt;br /&gt;
&lt;br /&gt;
I spend a lot of time just “plumbing”. &amp;nbsp;There is a &lt;i&gt;lot&lt;/i&gt; of infrastructure where I work. &amp;nbsp;In all the projects I've worked on, the vast majority of the code has already been written. &amp;nbsp;So the very first phase of software development is identifying the infrastructure subcomponents that the project should depend upon. &amp;nbsp;This is pretty easy to do. &amp;nbsp;Any basic project will always have these components:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;A web server front-end with the following properties:
&lt;ul&gt;
&lt;li&gt;Automated load balancing.&lt;/li&gt;
&lt;li&gt;Automated failover.&lt;/li&gt;
&lt;li&gt;High availability.&lt;/li&gt;
&lt;li&gt;Resistance against DOS attacks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Persistent storage or a database with these properties:
&lt;ul&gt;
&lt;li&gt;Geographically separate replicas.&lt;/li&gt;
&lt;li&gt;Regular backups.&lt;/li&gt;
&lt;li&gt;Tools for manual editing and revision of stored data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Software attendants to keep it running &amp;lsquo;unattended&amp;rsquo;.
&lt;/ul&gt;
My current project involves selling things (like all businesses need to do on occasion).  There is infrastructure to handle purchases, refunds, deal with fraud, etc.  We'll also need some more infrastructure to handle user authorization and authentication.  And I didn't mention the infrastructure needed to deliver the purchased items.  When it all comes down to it, there isn't a whole lot of logic involved in the project itself.  Almost all the functionality comes from the underlying infrastructure.  Our team spends a lot of time plugging it together.
That doesn't mean that it is easy or that it doesn't involve any creativity.&lt;br /&gt;&lt;br /&gt;
I've found on most projects I work on that there is always some piece of software that I intend to use but I have only very vague ideas about how it might work.  My task might be to hook it up.&lt;br /&gt;&lt;br /&gt;  Of course I spend several days thoroughly reading and understanding the copious documentation.&lt;br /&gt;&lt;br /&gt;
This is what I &lt;em&gt;really&lt;/em&gt; do:  I know that the end user is going to be sitting in front of his web browser and at some point click on something.  This will eventually trigger a method call that performs the requested operation.  Let's assume the user wants to buy something and that the mouse click the user made was the last one before the purchase (the one that asks &amp;ldquo;Ok to charge your credit card?&amp;rdquo;).  What can I deduce?
&lt;ol&gt;
&lt;li&gt;There ought to be a method that ultimately handles the &amp;lsquo;purchase&amp;rsquo;.&lt;/li&gt;
&lt;li&gt;Since buying something must be a very common operation, I expect there to be some easy way to charge the user's credit card.  
&lt;ol&gt; &lt;li&gt;I first look for the &amp;lsquo;quick start&amp;rsquo; guide or the FAQ. &lt;/li&gt;
&lt;li&gt;If I can't find an answer there, I look at the table of contents of the detailed documentation.&lt;/li&gt;
&lt;li&gt;A lot of the time there isn't any documentation or if there is, I can't find it.  The end result is the same.  If there is no documentation, then I think whether there are similar projects that might want to use the same infrastructure in the same way.  I'll eventually find some code that actually works.&lt;/li&gt;
&lt;li&gt;Now comes a trick.  I sketch out in my head a few possible protocol designs.  There should be a way, given a user and an item, to &amp;ldquo;begin&amp;rdquo; the process of purchasing.  There should be a way to determine if the process has completed.  There should be a way to determine the outcome of the process.  Each of these mechanisms should exist as separate calls because we might have to re-do any part of the process if the computer crashes during the purchase.  But since the &lt;em&gt;usual&lt;/em&gt; case will involve rapid turnaround and no crashes, there should be an abstraction that handles the entire process from end to end.  I poke around in the docs and in the source code to see if these things exist.&lt;/li&gt;
&lt;li&gt;Now I analyze what I've found and make a guess at the sophistication of the design and the programmer.  If I see an API that involves &lt;em&gt;continuation-passing style&lt;/em&gt; or a variant (Java callbacks are poor-man's CPS), then I expect a high level of sophistication from the API.  I expect there to be a &amp;lsquo;standard&amp;rsquo; way of purchasing something and I expect that all the edge cases are handled in a reasonable way.  Why?  Anyone that successfully uses a complex concept like continuation-passing style has most likely applied a lot of serious thought to the API.&lt;/li&gt;
&lt;li&gt;On the other hand, if I see an API that involves a lot of methods that return void and must be called in the right order or they won't work, or an API with ambiguous methods like &lt;code&gt;checkPurchase()&lt;/code&gt; and &lt;code&gt;validatePurchase()&lt;/code&gt; (which one do I use?), or one where the arguments must be strings that will then be parsed to something that makes more sense,
or APIs that throw only a single catch-all error (or just return null on success or maybe null on failure), then I expect that I'm going to have to think hard about all the edge cases myself and I'm going to have to wade through a lot of examples to determine the right &amp;lsquo;magic&amp;rsquo;  Why?  People that write APIs like this aren't thinking.  They code up the first solution that comes into their head and when they are done, they call it an API.  It is likely that they either didn't think there &lt;em&gt;were&lt;/em&gt; edge cases, or it didn't occur to them that they should abstract them away.&lt;/li&gt;
&lt;/ol&gt;
&lt;li&gt;So I finally determine what methods need to be called.  I look at the argument lists of the methods and I look at the arguments passed in to the servlet.  These are generally isomorphic in some way, but it is typically the case that the servlet is being passed a string representation and the underlying method needs an object.  If the API isn't completely idiotic, it will provide parsers and unparsers for the data that represent major concepts.  So the servlet might get a string that represents a user and a string that represents what he wants to purchase.  Now I have to figure out how to call the method.
&lt;ol&gt;&lt;li&gt;If the API is well designed, there might even be a method that takes the strings directly from the servlet and does all the work including checking inventory and scheduling order fulfillment.  This is the rare case.&lt;/li&gt;
&lt;li&gt;If the API is pretty good, then I'll probably have to make the appropriate calls to parse the servlet arguments to actual data, handle errors, and validate the input.  Then, with the parsed arguments in hand I can call the purchase method.&lt;/li&gt;
&lt;li&gt;If the API is lame, then after the argument parsing I'll have to check the database to see if there is inventory and somehow reserve it.  Then I'll run the purchase methods (which will not be unified into one abstraction, but consist of five methods that need to be called in the right order).  Then I'll have to see if the purchase succeeded, and if not, return the reserved item to inventory, or if it did, arrange for the item to be delivered.&lt;/li&gt;
&lt;/ol&gt;&lt;/ol&gt;
So how do I know how to use the API if it is undocumented?  The simple answer is this:  look for methods that have the same type signature as the objects that are at hand in the servlet.  There probably won't be very many.  Now look at the names of the methods and see if any make sense.  The &lt;code&gt;easyPurchase(User user, Item item)&lt;/code&gt; seems a lot more likely than the &lt;code&gt;getReceipt(User user, Collection&lt;Item&gt; items)&lt;/code&gt;.  A really good API uses names that practically shout out their purpose.&lt;br /&gt;&lt;br /&gt;
Finally I try out the code and see if it works.  If it does, I call it day.  If not, then it is time to twiddle, tweak, and frob things.  If the API is good, then I'll get informative error messages that tell me what I did wrong.  Something along the lines of &amp;ldquo;Error:  user id is an email address, did you forget to call parseUser()?&amp;rdquo; instantly tell me what I'm doing wrong.  Something along the lines of &amp;ldquo;null pointer exception&amp;rdquo; followed by a stack trace filled with methods I never heard of before now tell me nothing whatsoever.&lt;br /&gt;
&lt;hr&gt;
This is work.  It isn't extremely difficult, but it does require practice, skill, and imagination.  It also isn't really engineering.  It is more like plumbing.  Get this stuff here and put it over there, and you might need an adapter fitting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2746365197995270793?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2746365197995270793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2746365197995270793' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2746365197995270793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2746365197995270793'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/day-in-life.html' title='A day in the life'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2941718254254483473</id><published>2011-01-24T15:00:00.000-08:00</published><updated>2011-01-24T15:00:22.944-08:00</updated><title type='text'>A bit of history</title><content type='html'>The computers of the 50s were very primitive machines.  The IBM
704, for example, had 4096 words of ferrite core memory (later
expandable up to 32768 words) with an access time of 17 milliseconds.
The Central Processing Unit, which was not a monolithic silicon chip,
but a cabinet full of vacuum tubes, could execute 40 thousand
instructions per second (twenty-five microsecond basic execution
cycle).&lt;br /&gt;&lt;br /&gt;

It cost $50,000 a month just to &lt;em&gt;rent&lt;/em&gt; one.  (That's
more than $4 million a year in today's dollars).  And this was one of the most advanced
machines available at the time.  These days, the level 1 cache control
would put this kind of power to shame.&lt;br /&gt;&lt;br /&gt;

The computer languages at the time were bizarre to say the least.  Of
course no one at all had any experience programming, let alone
designing languages to make programming easier.  The conventional wisdom at the time was that &amp;lsquo;information processing&amp;rsquo; required an approach that differed
fundamentally from &amp;lsquo;numeric calculation,&amp;rsquo; so people tried out all sorts of weird ideas.  One idea was &lt;em&gt;string processing&lt;/em&gt;.  The COMIT language was one of the earliest string processing languages that was based around the idea of rewrite rules.  It is sort of like &lt;code&gt;sed&lt;/code&gt; on acid: 
&lt;pre&gt;
(8             PROGRAM TO BRING IN A NUMBER OF CONSTITUENTS AND PRINT OUT-
               ALL OF THE N FACTORIAL PERMUTATIONS OF THEM)
                       (PROBLEM SUGGESTED BY B. ULVESTAD)

INPUT                                $ = Q + 1 + N       //*RSA1              INPUT
*                                    N = QL + QR/.1                               *
NUMBER Q + $ + $1 +  QL +  $ + QR  + N = 1 + 2 + 4 + 3 + 5 + 7/.*6 + 6/.I1   NUMBER
*              Q + QL + $ + N + $ + QR = 3 + 2 + 6/.1 + 4 + 5                     *
PRINT                          $1 + QL = 2 + 1          //*WAB2               PRINT
*                 QL + $ + $1 + QR + N = 2 + Q + 3 + 1 + 5 + 4                    *
PERMUTE $1 + Q + $1 + $ + QL + $ + QR + N = 3 + 2 + 4 + 1 + 5 + 6 + 7 + 8/.D1     *
TEST               QL + $ + QR + $/.G0 = 1 + 3 + 2 + 4                       NUMBER
MOVE               $1 + Q + $ + QR + 1 = 2 + 1 + 3 + 5 + 4                  PERMUTE
&lt;/pre&gt;
Yngve, Victor H. 1958. &amp;ldquo;A programming language for mechanical translation.&amp;rdquo;  &lt;i&gt;Mechanical Translation&lt;/i&gt; 5 (1). 25-41&lt;br /&gt;&lt;br /&gt;

The &lt;em&gt;information processing language&lt;/em&gt;, IPL, on the other hand is more like assembly code with linked list support:
&lt;pre&gt;
            &lt;u&gt;COMMENTS&lt;/u&gt;                &lt;u&gt;TYPE&lt;/u&gt;  &lt;u&gt;NAME&lt;/u&gt;  &lt;u&gt;PQ&lt;/u&gt;  &lt;u&gt;SYMB&lt;/u&gt;   &lt;u&gt;LINK&lt;/u&gt;

Type-9 card                          9
                                     1
Type-2 cards define regions.         2     A                1
The B-Region consists of             2     B                1
 one cell, named "B0" or just "B".   2     I                1
                                     2     L                2
The R-region has 2 cells,            2     R                2
 named "R0" and "R1".                2     v                1
                                     2     (                1
                                     2     )                1
Type-1 cards are for comments.       1
                                     1
Type-5, Q=1 says "DATA FOLLOWS."     5           1

L1---(AI(A v B))                          LI        0
                                                    (
                                                    A
                                                    I
                                                    (
                                                    A
                                                    v
                                                    B
                                                    )
                                                    )        0

Type-5, Q=blank says "ROUTINES       5
 FOLLOW."                            1
                                     1
R1 prints the list L1.               1
                                     1
Q=3 says "TRACE THIS ROUTINE."            R1     13 L1
                                                    J151    0

P or Q = 0 can be left blank.

Type-5, SYMB=R1 says execute R1      5              R1
&lt;/pre&gt;
Correspondence between Hugh S. Kelley and Chuck Baker.&lt;br /&gt;&lt;br /&gt;
These languages differ from &lt;a href="http://en.wikipedia.org/wiki/INTERCAL"&gt;INTERCAL&lt;/a&gt; in that their designers were serious.&lt;br /&gt;&lt;br /&gt;
A notable exception was the language ALGOL.
&lt;pre&gt;begin integer i; real y; real array a[0:10];
   real procedure f(t); real t; value t;
     f := sqrt(abs(t)) + 5*t^3;
   for i := 0 step 1 until 10 do read(a[i]);
   for i := 10 step -1 until 0 do
     begin y := f(a[i]);
           if y &amp;gt; 400 then write(i, "TOO LARGE")
           else write(i,y);
     end
   end&lt;/pre&gt;
(taken from Wikipedia article on the 
&lt;a href="http://en.wikipedia.org/wiki/Trabb_Pardo%E2%80%93Knuth_algorithm"&gt;Trabb Pardo-Knuth&lt;/a&gt; algorithm)&lt;br /&gt;&lt;br /&gt;
ALGOL doesn't look unusual to the modern eye.  That in itself is testimony to the fact that ALGOL was years ahead of its time.  As you can imagine, though, it was well beyond the capability of most computers to compile and run an ALGOL program.&lt;br /&gt;&lt;br /&gt;
When McCarthy started the &amp;ldquo;Advice Taker&amp;rdquo; project, he proposed a new language LISP that would be based around the linked-list paradigm of IPL and the &lt;a href="http://en.wikipedia.org/wiki/Lambda_calculus"&gt;λ-calculus&lt;/a&gt; of &lt;a href="http://en.wikipedia.org/wiki/Alonzo_Church"&gt;Alonzo Church&lt;/a&gt;.  One of the goals of the language was to deliberately move away from the Turing-inspired mechanistic model of computation (Turing machine) and towards a more mathematical way of programming based upon recursion.  (Incidentally, ALGOL was designed to support recursion, but the very first ALGOL implementations punted because it was too complicated to support and users didn't know how to use it.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2941718254254483473?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2941718254254483473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2941718254254483473' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2941718254254483473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2941718254254483473'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/bit-of-history.html' title='A bit of history'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4551352627966043007</id><published>2011-01-19T12:50:00.000-08:00</published><updated>2011-01-19T12:50:21.520-08:00</updated><title type='text'>Fifty Years Ago</title><content type='html'>&lt;blockquote&gt;
The character-reading functions make it possible to read characters one by one from data records.  The choice of input medium is determined by sense switch 1, though at a future time mode-set facilities may be added so that input may be taken from any medium.  This description will be given in terms of &lt;a href="http://en.wikipedia.org/wiki/Punched_card"&gt;hollerith cards&lt;/a&gt;&amp;nbsp;[&lt;i&gt;sic&lt;/i&gt;] as input; the procedure for tape is completely analogous.  However, the tape records must be 72 characters long.&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;
Paul Abrahams, &lt;i&gt;Artificial Intelligence Project&lt;br /&gt;&lt;a href="http://hdl.handle.net/1721.1/6097"&gt;RLE and MIT Computation Center Memo 22a&lt;/a&gt;&lt;br /&gt;Character-Handling Facilities in the LISP System&lt;/i&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
In the months following McCarthy's initial description of ‘&lt;a href="http://hdl.handle.net/1721.1/6096"&gt;A Symbol Manipulating Language&lt;/a&gt;’, Steve Russell translated McCarthy's &lt;i&gt;eval&lt;/i&gt; into IBM 704 machine code and the first LISP was born.  By 1961 the implementation of Lisp 1.5 was well under way and a number of new libraries were being written.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Hollerith cards were the main input medium in
those days.  They were a step up from punched paper tape, though.  In fact,
punched cards were pretty much the only input medium until online input became
available.&lt;/blockquote&gt;
&lt;div style="text-align: right;"&gt;
Paul Abrahams, &lt;i&gt;personal correspondence&lt;/i&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Lisp had &lt;em&gt;read&lt;/em&gt;, &lt;em&gt;eval&lt;/em&gt;, and &lt;em&gt;print&lt;/em&gt;, but the computer itself was shared by the MIT Community.  You would submit your card deck for processing and come back some time later to get the printout. &amp;nbsp;The REPL was run in batch mode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4551352627966043007?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4551352627966043007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4551352627966043007' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4551352627966043007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4551352627966043007'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/fifty-years-ago.html' title='Fifty Years Ago'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4968869429295188243</id><published>2011-01-18T09:04:00.000-08:00</published><updated>2011-01-18T09:04:02.975-08:00</updated><title type='text'>Answers for Faré</title><content type='html'>&lt;a href="http://www.blogger.com/profile/14063105144178880818"&gt;Faré&lt;/a&gt;
said...&lt;br /&gt;
&lt;i&gt;Problem is that indeed you need to do something about those slots
without keyword initializers, slots that are computed from other slots
(e.g. hash values), slots that are initialized from a counter
(e.g. OID), slots that are actually plumbing from a larger structure
(e.g. indexes back into other objects), etc.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;

You would think so, but it turns out you don't.&lt;br /&gt;&lt;br /&gt;

When an object is created for the &lt;em&gt;very first&lt;/em&gt; time, you
&lt;em&gt;must have&lt;/em&gt; already written code to deal with slots without
keyword initializers, slots computed from other slots, slots that are
initialized from a counter, slots that are plumbing, etc. or you
wouldn't have been able to create the object.  When the object is
re-instantiated from the persistent store, there is no reason you
cannot simply perform those operations (mutatis mutandis) again.
&lt;br /&gt;&lt;br /&gt;

But what if these operations are not idempotent?  Actually, we already
know they are not.  Each time we call the constructor, we ought to be
getting a brand new object, so we don't want the operations to be
idempotent.  But note that the object is constructed exactly once per
&amp;lsquo;session&amp;rsquo; &amp;mdash; the constructor is &lt;em&gt;never&lt;/em&gt; called
twice without dropping all references to the constructed object
in-between the calls.  Therefore, it is not possible to ever
&lt;em&gt;observe&lt;/em&gt; two separate calls to the constructor.  (By
&amp;lsquo;observe&amp;rsquo; I mean, &amp;ldquo;You cannot write an extensional program that
returns 0 if exactly one call to the constructor occurs, but returns 1
otherwise.&amp;ldquo;)&lt;br /&gt;&lt;br /&gt;

Certainly one could, through reflection and other mechanisms write
code that intensionally exposes the implementation, but one can
&lt;em&gt;always&lt;/em&gt; write code that deliberately breaks an abstraction
barrier.  Although it &lt;em&gt;seems&lt;/em&gt; far too easy to break this
abstraction barrier by something as mundane as computing a slot value
from other slots, in practice it turns out that you won't want to.
Again, this can be derived from an information-theoretic argument.  At
the point of invoking the constructor, the program has provided all
the information necessary to correctly initialize the new instance.
Any other information used is, by definition,
&amp;lsquo;implicit&amp;rsquo;.&lt;br /&gt;&lt;br /&gt;

Let us assume, for a brief moment,
that the implementation depends critically upon the implicit part of
the initialization process.  I simply argue that critical dependence
upon implicit information is a serious bug, regardless of whether
persistence is brought into the picture or not.  If the implicit
information is &lt;em&gt;designed&lt;/em&gt; to be implicit, then the onus is upon
the designer to &lt;em&gt;hide&lt;/em&gt; the implicit dependency well enough that
the client code need not be aware of it.&lt;br /&gt;&lt;br /&gt;

 So let us assume
the opposite:  the implementation does &lt;em&gt;not&lt;/em&gt; depend cricitally
upon the implicit part of the initialization process.  Well, if there
is no critical implicit dependence, there are no bugs that occur
because of a critical implicit dependence.&lt;br /&gt;&lt;br /&gt; 

&lt;i&gt;The approach still works, but is actually very low-level, and calls for a
higher-level interface of some sort, lest your whole system keep a
very low-level feel.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;

Not at all.  In ChangeSafe, the abstraction of a &lt;em&gt;versioned
object&lt;/em&gt; is built directly upon the persistent object abstraction
by layering yet another set of MOP customizations on the existing
ones that implement persistence.  There is no higher-level interface
beyond the normal CLOS interface, yet there is very little code that
needs to have explicit calls to the persistence API.&lt;br /&gt;&lt;br /&gt;

I doubt these arguments will persuade anyone, so I suggest trying to
implement things this way and seeing for yourself.&lt;br /&gt;&lt;br /&gt;
 
And this reminds me of another thing.  Earlier you asked why
&amp;lsquo;pointer swizzling&amp;rsquo;  was performed on reading rather than
upon loading of the persistent object.  I mentioned a few reasons, but
I forgot one really important one:  it allows you to build persistent
circular structure without needing mutable objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4968869429295188243?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4968869429295188243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4968869429295188243' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4968869429295188243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4968869429295188243'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/answers-for-fare.html' title='Answers for Faré'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1377219055469778457</id><published>2011-01-13T10:18:00.000-08:00</published><updated>2011-01-13T10:18:22.384-08:00</updated><title type='text'>Some Bells and Whistles</title><content type='html'>There are a few bells and whistles that I added to my persistent
store.  The first is multiple extents (that is, more than one
persistent store open and participating in a transaction).  This is
fairly easy to add.  The only tricky part is ensuring that a
transaction that involves multiple extents either fully commits or
aborts across all participating stores.  The way I chose to implement
this is by choosing a single particular persistent store to be the
transaction master.  The commit record in the transaction master is
the one that holds the authoritative record of whether the entire
transaction has committed.&lt;br /&gt;&lt;br /&gt;

The commit proceeds in two phases.  In the first phase, each
non-master store performs a &amp;lsquo;conditional commit&amp;rsquo;.  This
involves flushing the pending writes to the backing store and writing
a special commit record that refers to the transaction master.  Once
each non-master store has written the special commit record, the
commit record is written to the master store.&lt;br /&gt;&lt;br /&gt;

If nothing unusual happens, processing may continue as in the normal
case.  The interesting thing happens when the non-master store is
first opened.  If the most recent commit record in a store is a
&amp;lsquo;conditional commit&amp;rsquo;, then it is necessary to check the
transaction master to see if &lt;em&gt;it&lt;/em&gt; committed.  Typically, the
relationship between the different stores is that there is one master
and one or more &amp;lsquo;satellite&amp;rsquo; stores.  Therefore, it is
likely that the transaction master is already open and within a
transaction when the satellite store is opened, so the master commit
record will be easily at hand.  If not, then the code recursively
opens the master store to determine if the conditional commit of the
satellite is valid.  This adds a little amount of bookkeeping to the
commit code, but it isn't particularly complex.&lt;br /&gt;&lt;br /&gt;

&lt;h3&gt;Nested Transactions and Multi-version Concurrency Control
(MVCC)&lt;/h3&gt;

My original plan had been to avoid the complexities of nested
transactions and MVCC.  I designed this as a &lt;em&gt;simple&lt;/em&gt; store,
and I figured that a good number of applications would not need nested
transactions.  I discovered almost immediately that I was wrong.  If
nested transactions are disallowed and a procedure needs to start a
transaction, it has to determine whether an existing transaction is in
progress.  If it is not, then the procedure needs to begin the
transaction and ensure it is committed when it exits.  On the other
hand, if there &lt;em&gt;is&lt;/em&gt; an existing transaction, the procedure
should &amp;lsquo;join&amp;rsquo; that transaction and let whoever started the
transaction decide whether or not to commit.  This isn't so bad if you
can segregate your procedures into &amp;lsquo;top-level&amp;rsquo; (ones that
&lt;em&gt;always&lt;/em&gt; start and commit a transaction) and &amp;lsquo;subroutines&amp;rsquo;
(ones that &lt;em&gt;never&lt;/em&gt; start and commit a transaction, but expect
there to be one in place before being called).  Unfortunately,
&lt;em&gt;recursive&lt;/em&gt; procedures cannot be in both categories
simultaneously.  A possible workaround is to have duplicate code
tailored for each use case, but then the programmer would have to
remember which version to call under which circumstances, or we'd have
to avoid using recursion.  Since this is clearly unacceptable, I bit
the bullet and implemented nested transactions.&lt;br /&gt;&lt;br /&gt;

With the current design, nested transactions turn out to be pretty
simple.  When a non-nested transactions starts, it gets a copy of the
most recent &lt;code&gt;object-map&lt;/code&gt; which it uses for OID resolution.
When a &lt;em&gt;nested&lt;/em&gt; transaction starts, it gets a copy of the
&lt;em&gt;current&lt;/em&gt; &lt;code&gt;object-map&lt;/code&gt; from the immediately
enclosing transaction.  The nested transaction gets to see the
intermediate state of the enclosing transaction.  If the nested
transaction commits, it does not write a commit record to the store.
Instead, the &lt;code&gt;object-map&lt;/code&gt; from the nested transaction is
used as the &lt;code&gt;object-map&lt;/code&gt; of the enclosing transaction when
control is returned.  Thus the enclosing transaction gets to see the
state that the nested transaction committed.  When the enclosing
transaction commits, the &lt;code&gt;object-map&lt;/code&gt; (which includes the
nested transaction updates) is written to the store and committed.
&lt;br /&gt;&lt;br /&gt;

If the enclosing transaction aborts, the nested transaction state is
simply dropped on the floor and becomes inaccessible.  The interesting
question is how to handle the case where the &lt;em&gt;nested&lt;/em&gt;
transaction aborts.  In this case, we return control to the enclosing
transaction, but we discard the &lt;code&gt;object-map&lt;/code&gt; from the
nested transaction.  The enclosing transaction therefore sees no
effect at all from the nested transaction.  The enclosing transaction
has the opportunity to itself abort (in which case &lt;em&gt;all&lt;/em&gt; the
intermediate state is discarded), to commit (in which case
&lt;em&gt;only&lt;/em&gt; the effect of the enclosing transaction is made
permanent), or to perhaps continue processing and begin more nested
transactions.&lt;br /&gt;&lt;br /&gt;

In effect, nested transactions act like software transactional
memory.&lt;br /&gt;&lt;br /&gt;

At this point, one can see how MVCC can be easily implemented.  Each
concurrent thread runs its own transactions with its own
&lt;code&gt;object-map&lt;/code&gt;.  Since all OID resolution is performed
against the &lt;code&gt;object-map&lt;/code&gt; associated with the current
(thread local) transaction, each concurrent transaction sees only its
view of the persistent store.  (This is a necessary condition, but it
is not sufficient.  We have to ensure that committed transactions can
be given a serial order to preserve the isolation between
transactions.  We do this by recording in each transaction the OIDs of
every persistent object read and written within the transaction.  When
the transaction attempts to commit, the set of reads and writes is
compared against the set of objects read and written by any
other parallel transaction that has committed since this one started.
If there is an overlap, we abort.  That is, we use optimistic
locking.)&lt;br /&gt;&lt;br /&gt;

(This should answer Fare's question about why OID resolution is
performed on each read rather than being done just once when the store
is opened.)&lt;br /&gt;&lt;br /&gt;

These features involve adding a good chunk of bookkeeping code, but
the code is straightforward, albeit tedious.  Good testing code is
vital to ensuring that this all works as it should.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1377219055469778457?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1377219055469778457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1377219055469778457' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1377219055469778457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1377219055469778457'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/some-bells-and-whistles.html' title='Some Bells and Whistles'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7552545562136490182</id><published>2011-01-07T16:46:00.000-08:00</published><updated>2011-01-07T16:46:02.164-08:00</updated><title type='text'>Schema evolution finessed</title><content type='html'>Schema evolution is the bête noire of the object-oriented database world.  It is probably the most labor intensive and error prone activity that an end-user is likely to attempt.  The root problem is that the metadata about persistent objects is implicitly replicated in several ways.&lt;br /&gt;&lt;br /&gt;

The big advantage of object-oriented databases is that they unify the query language with the &amp;lsquo;business logic&amp;rsquo; language.  You access and navigate persistent objects in the exact same way you access and navigate the ordinary data structures in the language.  The obvious benefit is that the mechanisms of persistence and querying are hidden behind the object abstraction.  But this means that the definition of the data structures are performing double duty.  Data structure definitions are used by the compiler to generate the appropriate primitive operations in the code, but they also are needed by the database component to generate the persistent representation of objects.  If the data definition changes, objects that conform to the old definition will no longer work.&lt;br /&gt;&lt;br /&gt;

Programmers generally expect that a recompile is all that is needed to change how a program handles data structures.  But if the data definition is used by the database for object storage and retrieval then changing the data definition may change the persistent representation and make it impossible to retrieve data.  (Or worse, it could silently retrieve the data incorrectly.)&lt;br /&gt;&lt;br /&gt;

It turns out that if persistent objects are immutable then there is a way to finesse the issue of schema evolution.&lt;br /&gt;&lt;br /&gt;

In CLOS, objects are created and initialized when the programmer invokes &lt;code&gt;make-instance&lt;/code&gt;.  There is a well-defined series of operations that take place and the resulting object is returned to the caller.  The important thing here is the &lt;em&gt;intent&lt;/em&gt; of the programmer.  The arguments given to &lt;code&gt;make-instance&lt;/code&gt; contain the specific information that the programmer has determined is needed to correctly initialize the object.  The returned instance will depend on the argument values and any default values that are supplied in the class definition.  From an information theoretic view, the argument list to &lt;code&gt;make-instance&lt;/code&gt; and the resulting instance &lt;em&gt;ought&lt;/em&gt; to contain the same information.  So rather than attempting to persist the resulting instance, we instead persist the argument list to &lt;code&gt;make-instance&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;

The immediate objection to this is that there is no way to know what on earth &lt;code&gt;make-instance&lt;/code&gt; constructed!  It &lt;em&gt;could&lt;/em&gt; be the case that &lt;code&gt;make-instance&lt;/code&gt; decides to return NIL.  There could be a very complex initialization protocol that defaults certain slot values and computes other slot values from the initargs.  &lt;em&gt;This doesn't matter.&lt;/em&gt;  The programmer is working at the abstraction level where the entire process is kicked off by the invocation of &lt;code&gt;make-instance&lt;/code&gt;, and thus his &lt;em&gt;intent&lt;/em&gt; is simply to create an instance of an object that is parameterized by the given initargs.&lt;br /&gt;&lt;br /&gt;

When we retrieve an object from the database, we don't attempt to retrieve the representation of the constructed object, we instead retrieve the arguments that were handed to &lt;code&gt;make-instance&lt;/code&gt; and simply invoke &lt;code&gt;make-instance&lt;/code&gt; again to re-create the object.&lt;br /&gt;&lt;br /&gt;

Now suppose that we have a database where we are modeling automobiles.  Let us assume that we have already stored thousands of automobile instances and that each instance contains, say, the number of doors and the color of the automobile.  At some point we decide that we no longer care about the number of doors, but we do want to know the make and model of the automobile.  We change the definition of the automobile class in the program.  When we invoke &lt;code&gt;make-instance&lt;/code&gt;, we now have a different set of initargs.  However, the legacy objects in the database are reconstructed by calling &lt;code&gt;make-instance&lt;/code&gt; with the old argument lists.  This is easily dealt with.  The older argument lists will have initargs describing the number of doors and the color of the car.  We arrange for &lt;code&gt;make-instance&lt;/code&gt; to ignore any initargs that are unused, and we require the programmer to supply &amp;lsquo;reasonable defaults&amp;rsquo; for initargs that are not supplied.  Thus when retrieving an older object, the count of the number of doors will be ignored, and a default value will be supplied for the make and model.&lt;br /&gt;&lt;br /&gt;

Note that we no longer require a schema to describe the layout of objects in the database.&lt;br /&gt;&lt;br /&gt;

There are drawbacks to this strategy.  First, we are making the assumption that all the relevant information for object creation is supplied in the call to &lt;code&gt;make-instance&lt;/code&gt;.  A perverse programmer can easily bypass this assumption.  However, it doesn't seem unreasonable to require that programmers either use the object creation protocol in the intended manner, or to specifically arrange for auxiliary helper objects to be created that hold any missing relevant information.  This is meant as a tool for programmers, not as a fool-proof system.  (Incidentally, the full-blown system I wrote allows the programmer to declare certain slots as transient.  This allows a programmer to cache information needed for the runtime without forcing the information to be persisted.)  Second, we give up the ability to side effect persistent objects.  (As I have noted in previous posts, we can mimic side effects reasonably easy.)&lt;br /&gt;&lt;br /&gt;

These disadvantages are minor compared to the difficulties of schema evolution.&lt;br /&gt;&lt;br /&gt;

I'm happy to answer questions about this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7552545562136490182?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7552545562136490182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7552545562136490182' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7552545562136490182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7552545562136490182'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/schema-evolution-finessed.html' title='Schema evolution finessed'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7477865068897670432</id><published>2011-01-04T11:50:00.000-08:00</published><updated>2011-01-04T11:50:43.015-08:00</updated><title type='text'>EQL Specializers</title><content type='html'>&lt;a href="http://p-cos.net/"&gt;Pascal Costanza&lt;/a&gt; asked an interesting question: &lt;i&gt;Why are &lt;code&gt;EQL&lt;/code&gt;
specializers convenient for smooth integration with object
instantiation?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;

My original answer was simply that when you want to customize
&lt;code&gt;make-instance&lt;/code&gt; for a particular class of objects that you
end up writing methods like this:&lt;pre&gt;
  (defmethod make-instance ((class (eql (find-class 'foo))) ...
&lt;/pre&gt;
This is doable without &lt;code&gt;EQL&lt;/code&gt; specializers, but it would be
kludgy.&lt;br /&gt;&lt;br /&gt;


While thinking about this some more, though, it occurred to me that
&lt;code&gt;EQL&lt;/code&gt; specializers are probably a necessary element for reflective
programming.&lt;br /&gt;&lt;br /&gt;

When you reflectively program the object system, you operate at a
meta-level where abstractions such as classes are reified as concrete
instances of a meta-class.  At the reflected level, object instances
are no longer the data being manipulated.  Instead, object classes are
used to represent sets of instances, and the classes themselves are
represented by instances of meta-class objects.&lt;br /&gt;&lt;br /&gt;

When you cross abstraction levels in this way, you need a set of
level-shifting primitives.  One of the most important of these is
quotation.  Quotation is level-shifting primitive that lifts (injects)
an instance from beneath the abstraction level to the level itself.&lt;br /&gt;&lt;br /&gt;

In CLOS, &lt;code&gt;EQL&lt;/code&gt; specializers are the quotation mechanism for
method dispatch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7477865068897670432?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7477865068897670432/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7477865068897670432' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7477865068897670432'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7477865068897670432'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2011/01/eql-specializers.html' title='EQL Specializers'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7459573942861570657</id><published>2010-12-20T11:29:00.000-08:00</published><updated>2010-12-20T11:29:47.987-08:00</updated><title type='text'>Side effects</title><content type='html'>Before continuing on with transactions I want to describe how side
effects are implemented.  Objects in the persistent store are
immutable, so we really cannot modify an existing object.  We can,
however, allocate a brand new object that differs from the old one
only in that the &amp;lsquo;side-effected&amp;rsquo; fields have different
values from fields in the original object.  We'll enter this new
object in the &lt;code&gt;object-map&lt;/code&gt;, but instead of assigning it a
fresh OID, we'll re-use the OID from the original object as well.
&lt;br /&gt;&lt;br /&gt;

The &lt;code&gt;object-map&lt;/code&gt;, as you may recall, is also a pure
functional object.  Adding an entry does not mutate any part of the
&lt;code&gt;object-map&lt;/code&gt; but instead makes a new &lt;code&gt;object-map&lt;/code&gt; that shares as much structure as possible with the old
one.  Any OID dereferencing that happens under the old &lt;code&gt;object-map&lt;/code&gt; will continue to see the original object with its original
contents.  Dereferencing an OID under the new &lt;code&gt;object-map&lt;/code&gt; will see the new version of the object with the
&amp;lsquo;modified&amp;rsquo; field.  We mimic side effects by creating a
whole new world where everything is identical to the original except
for the thing that appears to change.&lt;br /&gt;&lt;br /&gt;

Normally, one would expect that creating a new world every time you
wish to mutate an object would be prohibitively expensive.  But since
the objects and the &lt;code&gt;object-map&lt;/code&gt; itself are immutable, we
can re-use them freely.  This makes it reasonably efficient.  Creating
a new world takes time proportional to the logarithm of the number of
objects persistently stored.  Even having a huge number of objects
adds very little time and space overhead to simulate mutation.  
&lt;br /&gt;&lt;br /&gt;

You may think this is an awfully roundabout way to do something
simple.  After all, why not do the traditional thing of simply
maintaining a snapshot of the current consistent state of the world
and actually mutating it?  This would require modifying the logging
strategy slightly.  A special mutation record would have to be written
to the log to echo the mutation being performed in memory.  If the
machine crashes, the log could be read forward to re-do the mutations
that were in progress at crash time.  Alternatively, it could be read
backwards to undo the mutations that ought to be undone if the
transaction didn't commit.&lt;br /&gt;&lt;br /&gt;

The rationale for this roundabout solution is simplicity.  It is hard
to make transactions work correctly &lt;em&gt;every single time&lt;/em&gt; given
the fact that a hard failure can occur at any moment at all.  Use
Google to search for &amp;ldquo;transaction bug&amp;rdquo; and take a look at
how easy it is to make subtle mistakes.  By making it impossible to
mutate existing persistent store records and indexes, we guarantee
that bugs in the transaction layer simply cannot affect earlier,
successful transactions.  Cleanup and recovery of the persistent store
remain as easy and trivial as before:  we simply find the most recent
valid commit record.  There are no undo or redo logs to process.
The transaction algorithm can be proven correct by inspection.
&lt;br /&gt;&lt;br /&gt;

Once we have &amp;lsquo;mutation&amp;rsquo;, we'll need to ensure that we can
maintain consistency when we use it.  We want the persistent store to
behave as if the mutations had some serial order to them.  We augment
each transaction object with some more bookkeeping information.  Each
transaction must record which objects it dereferences, allocates, and
&amp;lsquo;mutates&amp;rsquo; before it commits.  We'll also add a transaction
manager object which examines transactions before they are committed
to determine if a serial ordering can still be computed.  If there is
a single thread performing transactions, then a serial ordering is
virtually guaranteed.  But if multiple concurrent threads run
transactions in parallel, we have to make sure that each transaction
runs in isolation from each other, and that the sets of locations read
and written do not intersect with other transactions.  If the
transaction manager finds a conflict, it aborts one of the
transactions.&lt;br /&gt;&lt;br /&gt;

Again, we note that this implementation can easily handle conflicts
because it is very simple.  Aborting a transaction is easier than
committing it.  You simply discard the transaction and you
&lt;em&gt;don't&lt;/em&gt; write a commit record for it.  Allowing transaction to
proceed and only checking for conflicts at commit time is an
&amp;lsquo;optimistic&amp;rsquo; strategy.  In many situations an
&amp;lsquo;optimistic&amp;rsquo; concurrency strategy can perform better than
a &amp;lsquo;pessimistic&amp;rsquo; one.  With a slight change it is easy to
go to a &amp;lsquo;pessimistic&amp;rsquo; model.  In a pessimistic model,
conflicting transactions are detected when a field is mutated.  If the
mutated field has been read within another transaction, then the other
transaction may be working with stale data if it commits before this
one.  A pessimitic model is slightly simpler to understand because you
check the validity of each operation just before performing it.
However, an optimistic model performs very well if concurrent changes
to the exact same objects do not often occur. &lt;br /&gt;&lt;br /&gt;
&lt;hr /&gt;
While trying to bring this code back to life I encountered two bugs in
MIT/GNU Scheme.  The first was a bug in a rare corner case of
structure definition.  The second was caused by the fact that the
floating point layout changed between the 32 and 64 bit releases.
I've fixed these, but I have a more interesting problem.&lt;br /&gt;&lt;br /&gt;

The MIT Scheme object system, SOS, is derived from many of the ideas
in Tiny CLOS.  It is missing, however, a fully functional MOP.  In
addition, method dispatch is done only on the types of arguments.
This makes it tricky to do &amp;lsquo;EQL specializers&amp;rsquo;.  EQL
specializers are necessary to smoothly integrate object
instantiation.  You can work around this limitation in some ways, but
it would be much better if the implementation had this as a built-in
feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7459573942861570657?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7459573942861570657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7459573942861570657' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7459573942861570657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7459573942861570657'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/12/side-effects.html' title='Side effects'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4727086534355619955</id><published>2010-12-17T09:42:00.000-08:00</published><updated>2010-12-17T09:42:27.305-08:00</updated><title type='text'>Transactions, part I</title><content type='html'>Faré has persuaded me to post actual working and tested code.  It
seems that enough has changed since I switched computers and the code
that &lt;em&gt;was&lt;/em&gt; working is working no longer.  (The problem has
nothing to do with my code — a shared library referred to by Scheme
seems to have moved and Scheme came crashing down.)  I'll get things
working and show the live code.  Until then, we'll have to make do
with illustrative code fragments.&lt;br /&gt;&lt;br /&gt;

Given the index structure I described over the past two days, you can
easily see that we have solved the problem of internal and external
references.  We use OIDs as a sort of &amp;lsquo;pointer&amp;rsquo;, and we
modify the access mechanisms to hide the redirection.  An analagous
modification to &lt;code&gt;make-instance&lt;/code&gt; gives us aggregate objects
by initializing the instance slots with the appropriate OIDs.&lt;br /&gt;&lt;br /&gt;

The next thing to deal with is transactions.  These are very easy to
implement using this design.  We have provided no mechanism to rewrite
any data in the backing store; it is opened in append-only mode.
When we augment the &lt;code&gt;object-map&lt;/code&gt; to associate new OIDs with
new objects, we construct new &lt;code&gt;object-map&lt;/code&gt; nodes and append
them to the backing store, but we do not modify any existing
&lt;code&gt;object-map&lt;/code&gt; nodes.  If we were to ignore the new
&lt;code&gt;object-map&lt;/code&gt; and re-use the old one, we would not be able
to access the new objects.  The entire object graph would appear to us
as if time had stopped at the point when the old
&lt;code&gt;object-map&lt;/code&gt; was created.  This is the key to implementing
transactions.&lt;br /&gt;&lt;br /&gt;

When we begin a transaction, we create a transaction object and copy
the most recent &lt;code&gt;object-map&lt;/code&gt; root node to it.  As we create
objects we update the transaction object with augmented
&lt;code&gt;object-map&lt;/code&gt;.  If the transaction fails, we simply discard it.
The &lt;em&gt;next&lt;/em&gt; transaction is initialized with either the new
&lt;code&gt;object-map&lt;/code&gt; (if the prior transaction committed) or the
old &lt;code&gt;object-map&lt;/code&gt; (if the prior transaction aborted).  There
is no need to &amp;lsquo;undo&amp;rsquo; anything because persistent objects
cannot be mutated.&lt;br /&gt;&lt;br /&gt;

When the computer shuts down (either by a crash or planned outage) and
is restarted, we use the information in the backing store to restore
the state of the program.  We need to find the most recent, but valid,
root of the &lt;code&gt;object-map&lt;/code&gt;.  Since we cannot plan crashes,
we might find objects and &lt;code&gt;object-map&lt;/code&gt; nodes at the tail
of the backing store that were written by a transaction that was
in progress when the crash happened.  We want to ignore these because
they represent intermediate state.  The trick is this:  when a
transaction commits we append a special &amp;lsquo;commit record&amp;rsquo; to
the backing store.  The commit record will contain the location
(within the store) where the root node of the &lt;code&gt;object-map&lt;/code&gt;
is stored.  When the process restarts, it scans the backing store to
find the latest valid commit record and it initializes from there.
Any objects that were allocated after that commit record are simply
ignored.&lt;br /&gt;&lt;br /&gt;

If transactions usually commit and the computer rarely crashes, then
the most recent commit record will usually be the very last record in
the backing store.  If the computer crashes a lot, or if transactions
are usually aborted, then it is likely that the backing store would
accumulate abandoned objects.  One could develop a way of reclaiming
that storage.&lt;br /&gt;&lt;br /&gt;

Here is an actual commit record:
&lt;pre&gt;((:commit-record-starts)
 (:record-format 0.4)
 (:timestamp 3331389370)
 (:object-map-offset 5971200)
 (:previous-record-offset 5970432)
 (:reason "Update user context.")
 (:commit-record-ends))&lt;/pre&gt;
The commit record has start and end markers so we can identify
incomplete commit records.  The &lt;code&gt;object-map&lt;/code&gt; is at location
5971200 in the backing store, and the previous commit record is at
location 5970432.  (For extra safety, the commit record should contain
a CRC or hash of the &lt;code&gt;object-map&lt;/code&gt;.  It should probably
contain a CRC or hash of itself in order to make it self-validating.
Or you can punt.)&lt;br /&gt;&lt;br /&gt;

The &lt;code&gt;:reason&lt;/code&gt; is just a string.  It is not used for
anything, but it is extremely important nonetheless.  The
&lt;code&gt;:reason&lt;/code&gt; gives us an audit trail in the event of a
catastrophic failure.  This is part of the &amp;ldquo;belt and suspenders&amp;rdquo;
safety mechanism.  The backing store may kept for a long time, perhaps
even many years.  Although we will protect the data with multiple
mechanisms to reduce the probability of simultaneous failures, our
last line of defense is to manually inspect the backing store
records.  The &lt;code&gt;:reason&lt;/code&gt; field will make this much
easier.&lt;br /&gt;&lt;br /&gt;

Ok, now for some code to illustrate.  The actual code has a number of
bells and whistles, and I'll show them later, but it is best to start
with a stripped down version.
&lt;pre&gt;
(defconstant *transaction-dispositions*
  '(:running :committing :aborting :committed :aborted))

;; running = transaction should commit upon return,
;;           but abort if a throw occurs
;;
;; aborting = transaction is still running, but it must abort upon exit
;; committing = transaction is still running, but it must commit
;;              upon exit, even if throwing
;;
;; aborted = transaction is over, it aborted
;; committed = transaction is over, it committed
(deftype transaction-disposition () `(member ,@*transaction-dispositions*))

(eval-when (:load-toplevel :compile-toplevel :execute)
  (defvar *current-transaction*)
  (setf (documentation '*current-transaction* 'variable)
        "The current transaction.  Not bound if we are not in a transaction."))

;;; Transactions
(defclass transaction ()
  ((disposition :accessor transaction/disposition
                :initform :running
                :type transaction-disposition)
   (reason      :accessor transaction/reason
                :initarg :reason
                :initform "Unknown"
                :type string)
   (object-map :accessor transaction/object-map
               :initarg  :object-map)))
&lt;/pre&gt;
The code for running a transaction is conceptually simple, but the
bells and whistles obscure the simplicity.  I'll
present a stripped-down version first and then show the full version
in a later post.
&lt;pre&gt;
(defun call-with-transaction (pstore reason receiver)
  (let ((transaction   nil)
        (normal-return nil)
        (abort-reason  "Non-local exit from call-with-transaction."))
      (unwind-protect
          (progn
            ;; This is the only place that transactions are created.
            (setq transaction
                  (make-instance
                   :object-map (persistent-store/object-map pstore)
                   :reason reason))
            (multiple-value-prog1
                (let ((*current-transaction* transaction))
                   (funcall receiver transaction)))
              (setq normal-return t)))

        ;; If the transaction is null, we never even got started.
        (unless (null transaction)
          (ecase (transaction/disposition transaction)
             ;; If we return normally and no one decided to commit
             ;; or abort before now, we commit.
            (:running (if normal-return
                          (transaction/do-commit transaction)
                          (progn
                            (setf (transaction/reason transaction) abort-reason)
                            (transaction/do-abort  transaction))))
            (:committing (transaction/do-commit transaction))
            (:aborting   (transaction/do-abort  transaction))))))

;; Aborting is simple.
(defun transaction/do-abort (transaction)
  "Perform the necessary work to abort the transaction."
  (assert (or (eq (transaction/disposition transaction) :aborting)
              (eq (transaction/disposition transaction) :running)))
  (setf (transaction/disposition transaction) :aborted))

;; Committing is simple, too.  Just write a commit record.
(defun transaction/do-commit (transaction)
  "Perform the necessary work to commit the transaction."
  (assert (or (eq (transaction/disposition transaction) :committing)
              (eq (transaction/disposition transaction) :running)))
   (let* ((object-map (transaction/object-map transaction))
          (pstore (object-map/pstore object-map)))
     (persistent-store/commit pstore
         :object-map object-map
         :reason (transaction/reason transaction))
     (setf (transaction/disposition transaction) :committed)))
&lt;/pre&gt;
More posts to follow...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4727086534355619955?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4727086534355619955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4727086534355619955' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4727086534355619955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4727086534355619955'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/12/transactions-part-i.html' title='Transactions, part I'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-960428313364364163</id><published>2010-12-15T12:31:00.000-08:00</published><updated>2010-12-17T11:21:04.311-08:00</updated><title type='text'>More persistence</title><content type='html'>In my last post, I described how to map OIDs to persistent objects by
means of a functional, weight-balanced, binary tree.  In this post, I
will describe how to implement aggregate objects.  I'm going to start
with a high-level view and drill down to the details.  I'm afraid at
this point I'm going to switch to Common Lisp and CLOS.  Don't worry,
though, if you just pretend that &lt;code&gt;defclass&lt;/code&gt; is a synonym
for &lt;code&gt;define-structure&lt;/code&gt;, you won't be far off.&lt;br /&gt;&lt;br /&gt;

Here's a simple CLOS class definition:
&lt;pre&gt;
(defclass test-class ()
  ((name :initarg :name
         :initform 'zippy)))
&lt;/pre&gt;
Objects of class &lt;code&gt;test-class&lt;/code&gt; have a single field which is
called &lt;code&gt;name&lt;/code&gt;.  This class definition adds a method to
&lt;code&gt;make-instance&lt;/code&gt; that works as follows:
&lt;pre&gt;
  ;; make an instance where the name is the symbol GRIFFY 
  (defvar test-instance-1 (make-instance 'test-class :name 'griffy))

  ;; alternatively, use the default name of ZIPPY
  (defvar test-instance-2 (make-instance 'test-class))
&lt;/pre&gt;
In addition, we can use &lt;code&gt;slot-value&lt;/code&gt; to extract the name:
&lt;pre&gt;
  (slot-value test-instance-1 'name)
  =&amp;gt; GRIFFY

  (slot-value test-instance-2 'name)
  =&amp;gt; ZIPPY
&lt;/pre&gt;
And that's that.  (And you thought CLOS was complicated.)&lt;br /&gt;&lt;br /&gt;

A persistent class is defined as follows:&lt;pre&gt;
(defclass test-class ()
  ((name :initarg :name
         :initform 'zippy))
  (:metaclass persistent-standard-class)
  (:schema-version 0))&lt;/pre&gt;
The &lt;code&gt;:metaclass&lt;/code&gt; specifier tells CLOS that we want
instances to be persistent.  The &lt;code&gt;:schema-version&lt;/code&gt; is a bit
of magic that protects against the unlikely, but possible nasty case
that over time a class definition might evolve where a slot name is
accidentally re-used.  In such a case, the code will need to
disambiguate which class definition was intended and it can use the
&lt;code&gt;:schema-version&lt;/code&gt;.  You can safely ignore this by following
this simple rule:  If you ever modify the slots in a persistent class,
you should increment the &lt;code&gt;:schema-version&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;

So what is different?  On the surface, practically nothing changes.
The calls to &lt;code&gt;make-instance&lt;/code&gt; and &lt;code&gt;slot-value&lt;/code&gt;
work just as before.  There are four changes that happen &amp;lsquo;under
the covers&amp;rsquo;&lt;ol&gt;&lt;li&gt;The object returned by
&lt;code&gt;make-instance&lt;/code&gt; will be a persistent object.&lt;/li&gt;
&lt;li&gt;Two additional slots are allocated.  The first contains the OID of
the instance itself, the second contains the persistent store where
the instance was allocated.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;name&lt;/code&gt; slot in the object will contain the OID of
the persistent name rather than a Lisp object.
&lt;code&gt;make-instance&lt;/code&gt; is modified to extract the OIDs of its
arguments to initialize this slot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;slot-value&lt;/code&gt; must be modified to dereference the OID
that is actually in the slot.&lt;/li&gt;&lt;/ol&gt;
These modifications are easily made using the CLOS MOP.&lt;br /&gt;&lt;br /&gt;

We use the meta-object protocol to override
&lt;code&gt;slot-value-using-class&lt;/code&gt; as follows:
&lt;pre&gt;
(defmethod clos:slot-value-using-class ((class persistent-standard-class)
                                        (object persistent-standard-object)
                                        slot)
   (persistent-object/find 
     (persistent-standard-object/pstore object)
     (call-next-method)))
&lt;/pre&gt;
The call to &lt;code&gt;call-next-method&lt;/code&gt; invokes the underlying
mechanism for reading a slot value.  But we're not storing the actual
slot value in the slot, we are storing the OID of the actual slot
value, so &lt;code&gt;call-next-method&lt;/code&gt; will return that OID.  We look
up the returned OID in the persistent store to get the value.  (In
order to support multiple persistent stores, we need to know which
store contains the value.  We require that all subfields of an object
be allocated in the same persistent store as the containing
object.)&lt;br /&gt;&lt;br /&gt;
The modifications to &lt;code&gt;make-instance&lt;/code&gt; are more complex.
We actually don't modify &lt;code&gt;make-instance&lt;/code&gt; directly, but
instead we modify &lt;code&gt;clos:shared-initialize&lt;/code&gt; (which is
invoked by &lt;code&gt;make-instance&lt;/code&gt; as part of the instance
allocation protocol).&lt;pre&gt;
;; Override the primary shared-instance method
;; in order to deal with persistent slots.
(defmethod clos:shared-initialize ((instance persistent-standard-object) slot-names
                                   &amp;rest initargs
                                   &amp;key persistent-store oid
                                   &amp;allow-other-keys)
    ;; We have to wrap the initargs and initforms
    ;; in persistent-objects and create an initializer
    ;; for this object.
    (let* ((class (class-of instance))

           (init-plist (compute-persistent-slot-initargs class
                                                         (or persistent-store  *default-persistent-store*)
                                                         initargs))

           (oid (persistent-object/save
                     (make-initializer class
                                       (class-schema-version class)
                                       init-plist)
                     (or persistent-store  *default-persistent-store*)
                     oid)))

      (apply #'call-next-method instance slot-names (nconc init-plist initargs))
      (setf (persistent-standard-object/oid instance) oid)
      instance))

(defun compute-persistent-slot-initargs (class persistent-store initargs)
  "Scan over the persistent effective slots in CLASS,
   determine the value to be assigned to each slot, either
   from the initargs or from the initfunction, then
   using the persistent-initarg as a key, construct a
   plist for use in the persistent initializer and in
   the inner call to shared-initialize."
  (let ((result nil))
    (iterate (((slot-initargs slot-initfunction slot-persistent-initarg)
               (map-fn '(values t t symbol)
                       #'effective-slot-initialization-info
                       (scan-class-persistent-effective-slots class))))
      (let ((initial-value (slot-initial-value initargs slot-initargs slot-initfunction
                                               (clos::slot-unbound-value))))
        (unless (eq initial-value (clos::slot-unbound-value))
          (push slot-persistent-initarg result)
          (push (slot-value-&amp;gt;persistent-node persistent-store initial-value) result))))
    (nreverse result)))
&lt;/pre&gt;
In &lt;code&gt;compute-persistent-slot-initargs&lt;/code&gt;, you can see the call
to &lt;code&gt;slot-value-&amp;gt;persistent-node&lt;/code&gt; that extracts the OID
from the initarg.  In &lt;code&gt;shared-initialize&lt;/code&gt;, the call to
&lt;code&gt;persistent-object/save&lt;/code&gt; writes an &lt;em&gt;initialization
record&lt;/em&gt; to the store and then allocates and initializes the
transient, in-memory version of the object.&lt;br /&gt;&lt;br /&gt;
These are the essential changes to the MOP to implement the basic
persistence mechanism.&lt;br /&gt;&lt;br /&gt;
More details to come in the next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-960428313364364163?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/960428313364364163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=960428313364364163' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/960428313364364163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/960428313364364163'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/12/more-persistence.html' title='More persistence'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4681425616947909876</id><published>2010-12-14T14:04:00.000-08:00</published><updated>2010-12-14T14:04:41.439-08:00</updated><title type='text'>Oh yeah, about that persistent store....</title><content type='html'>In April of last year I was describing a simple persistent object
store.  I never finished.  &lt;i&gt;Mea culpa&lt;/i&gt;.  I was thinking about it again
and I realize why.  The next step in the implementation is a really
big one.  We're going to solve five unrelated problems in one fell
swoop:&lt;ol&gt;&lt;li&gt;Transactions — we will add the ability to roll-back partially
       completed operations.&lt;/li&gt;

    &lt;li&gt;Aggregate objects — up to now, we only allow primitive objects
       to be persisted.  We will add the mechanism to allow aggregate
       structures to be stored and retrieved.&lt;/li&gt;

    &lt;li&gt;Side effects — the backing store is opened in append mode, so
       mutation of existing objects is not possible.  Since we only
       allow primitive immutable objects to be stored, this is not an
       issue.  Once we have aggregate objects, however, we will want
       to simulate the ability to side-effect these objects.  The
       transaction system will have to know how to undo these effects
       if the transaction aborts.&lt;/li&gt;

    &lt;li&gt;Schema migration — Persistent objects live a long time.  Over
       time, it is usually the case that we will want to change what
       fields are contained in an aggregate object.  Removing a field
       is easy, but adding or renaming an existing field can be tricky
       because legacy objects will be missing the field.  Furthermore,
       if the aggregate object model is rich (for example, if it
       supports inheritance), some changes to the model might require
       making extensive changes to the existing persistent objects.&lt;/li&gt;

    &lt;li&gt;Internal and external references — up to now, an object cannot
       refer to another object.  There is also no way to refer to a
       particular persistent object other than by directly using it.
       For example, although we could store two different strings in
       the persistent store, and we can recover both, we cannot
       identify which one is &amp;lsquo;first&amp;rsquo; and which one is &amp;lsquo;second&amp;rsquo;.&lt;/li&gt;&lt;/ol&gt;

I haven't figured a way to truly separate these five different
features, so this post is going to be a long and complex one.
&lt;br/&gt;&lt;br /&gt;
We need to introduce object identifiers (OIDs).  An OID is an integer
that refers to a unique persistent object.  Every persistent object in
a particular persistent store is given a different OID (we do not
require that OIDs are universally unique).
&lt;br/&gt;&lt;br /&gt;
At this point, let me illustrate the code.
&lt;pre&gt;
(define-structure (object-map-entry
                   (type list)
                   (conc-name object-map-entry/)
                   (constructor %make-object-map-entry
                                (object-id address cached-value)))
  (object-id #f read-only #t)
  (address #f read-only #t)

  ;; *** A slot holding the cached value greatly improves
  ;;     performance!
  (cached-value #f read-only #t)
  )

&lt;/pre&gt;
Each &lt;code&gt;object-map-entry&lt;/code&gt; associates an
&lt;code&gt;object-id&lt;/code&gt; with an &lt;code&gt;address&lt;/code&gt;.  The
&lt;code&gt;address&lt;/code&gt; is the location within the backing store where
the object has been serialized.  The &lt;code&gt;cached-value&lt;/code&gt; not
only speeds up object retrieval, it ensures that every dereference of
an OID yields the same &lt;code&gt;EQ?&lt;/code&gt; result. &lt;em&gt;Extrinsic identity
— the existence of a universal &amp;lsquo;identically equal&amp;rsquo; predicate — is
a key assumption of Lisp, so it is important to avoid violating this
assumption.&lt;/em&gt;
&lt;br/&gt;&lt;br /&gt;
We will be maintaining a data structure that maps OIDs to objects.
This data structure will itself need to be persistent.  Over time, we
expect the ratio of new objects to old objects to decrease, so a data
structure that supports incremental update will be much more efficient
than one that requires wholesale replacement.  A weight-balanced
binary tree is one way of implementing this map.
&lt;br/&gt;&lt;br /&gt;
A tree has two kinds of nodes:  leaf nodes, which hold a single
&lt;code&gt;object-map-entry&lt;/code&gt;, and branch nodes, which hold sub-trees
in addition to an &lt;code&gt;object-map-entry&lt;/code&gt;.  Object lookup
requires descending into the tree to find the
&lt;code&gt;object-map-entry&lt;/code&gt; with the correct OID.

&lt;pre&gt;
(define (persistent-tree/descend object-id current-tree best-tree)
  (cond ((null? current-tree) best-tree)
        ((&amp;lt; object-id 
               (object-map-entry/object-id (persistent-tree/object-map-entry current-tree)))
         (persistent-tree/descend object-id 
                                  (persistent-tree/left-child current-tree) best-tree))
        (else
         (persistent-tree/descend object-id
                                  (persistent-tree/right-child current-tree) current-tree))))

(define (persistent-tree/find-entry root object-id)
  (let ((best-tree (persistent-tree/descend object-id root '())))
    (if (null? best-tree)
        #f
        (let ((entry (persistent-tree/object-map-entry best-tree)))
          (if (&amp;lt; (object-map-entry/object-id entry) object-id)
              #f
              entry)))))
&lt;/pre&gt;

Adding an entry to the OID tree is much more complex.  Binary trees
work best when they are balanced, so when we add a node to the tree we
may want to rebalance the tree.  This may require creation of new
internal nodes of the tree.  In addition, we want our tree to be
persistent, so any new nodes must be written to the backing store.
However, we want the tree to be efficient — adding a node and
rebalancing the tree should not require too much computation and disk
traffic.  
&lt;br/&gt;
This particular implementation uses a `functional binary
tree'.  Updates to the tree do not modify existing data structures.
Instead, new nodes are allocated and as much of the existing tree as
possible is re-used.  (See Stephen Adams `Implementing Sets
Efficiently in a Functional Language' &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.1134"&gt;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.1134&lt;/a&gt;
for the details on the algorithms.)  Here is the code:
&lt;pre&gt;
(define-structure (persistent-tree
                   (conc-name persistent-tree/)
                   (constructor make-persistent-tree (left-child-address
                                                      right-child-address
                                                      %weight
                                                      %address
                                                      left-child
                                                      right-child
                                                      object-map-entry)))

  ;; Address of left child of the tree.
  ;; This field is persistent.
  (left-child-address #f read-only #t)

  ;; Address of right child of the tree.
  ;; This field is persistent.
  (right-child-address #f read-only #t)

  ;; Weight of this tree.
  ;; This field is persistent.
  (%weight #f read-only #t)

  ;; Where the persistent version is in the durable store.
  ;; This field is transient and reconstructed upon deserialization.
  (%address #f read-only #t)

  ;; Cached left child.
  ;; A transient copy of the deserialized left child.
  (left-child #f read-only #t)

  ;; Cached right child.
  ;; A transient copy of the deserialized right child.
  (right-child #f read-only #t)

  ;; The object map entry stored at the root of this tree.
  (object-map-entry #f read-only #t))

(define (persistent-tree/make-leaf durable-store entry)
  (let* ((weight 1)
         ;; Serialize the persistent information from the
         ;; object-map-entry.  (the object-id and the address).
         (address (primitive-serialize-leaf durable-store (object-map-entry/address entry))))
    (make-persistent-tree 0 0 weight address '() '() entry)))

(define (primitive-serialize-leaf durable-store entry-address)
  (write-leaf-record! 
   durable-store
   (lambda (oport)
     ;; store the delta because it is likely to be a small number.
     (write entry-address oport))))

(define (persistent-tree/make-branch durable-store left-child right-child entry)
  (if (and (null? left-child)
           (null? right-child))
      (persistent-tree/make-leaf durable-store entry)
      (let* ((weight (+ 1
                        (persistent-tree/weight left-child)
                        (persistent-tree/weight right-child)))
             (left-child-address (persistent-tree/address left-child))
             (right-child-address (persistent-tree/address right-child))
             ;; Serialize the addresses of the
             ;; left and right child, and the persistent information 
             ;; from the object-map-entry (the object-id and the address).
             (address 
              (primitive-serialize-branch durable-store
                                          left-child-address
                                          right-child-address
                                          (object-map-entry/address entry))))
        (make-persistent-tree left-child-address
                              right-child-address
                              weight
                              address
                              left-child
                              right-child
                              entry))))

(define (primitive-serialize-branch durable-store
                                    left-child-address
                                    right-child-address
                                    entry-address)
  (write-branch-record!
   durable-store
   (lambda (output-port)
     (write left-child-address output-port)
     (write-char #\space output-port)
     (write right-child-address output-port)
     (write-char #\space output-port)
     (write entry-address output-port))))

(define (persistent-tree/add durable-store root new-entry)
  (if (null? root)
      (persistent-tree/make-leaf durable-store new-entry)
      (let ((root-entry (persistent-tree/object-map-entry root))
            (left-child (persistent-tree/left-child root))
            (right-child (persistent-tree/right-child root)))
        (cond ((&amp;lt; (object-map-entry/object-id new-entry)
                  (object-map-entry/object-id root-entry))
               (persistent-tree/t-join 
                durable-store 
                (persistent-tree/add durable-store left-child new-entry)
                right-child
                root-entry))
              ((&amp;lt; (object-map-entry/object-id root-entry)
                  (object-map-entry/object-id new-entry))
               (persistent-tree/t-join
                durable-store 
                left-child
                (persistent-tree/add durable-store right-child new-entry)
                root-entry))
              (else
               (persistent-tree/make-branch durable-store 
                                            left-child right-child
                                            new-entry))))))

(define (persistent-tree/t-join durable-store left-child right-child entry)
  (let ((l.n (persistent-tree/weight left-child))
        (r.n (persistent-tree/weight right-child)))
    (cond ((&amp;lt; (+ l.n r.n) 2)
           (persistent-tree/make-branch durable-store left-child right-child entry))

          ((&amp;gt; r.n (* 5 l.n))
           (persistent-tree/l-join durable-store left-child right-child entry))

          ((&amp;gt; l.n (* 5 r.n))
           (persistent-tree/r-join durable-store left-child right-child entry))

          (else
           (persistent-tree/make-branch durable-store left-child right-child entry)))))

(define (persistent-tree/l-join durable-store left-child right-child entry)
  (if (&amp;lt; (persistent-tree/weight (persistent-tree/left-child right-child))
         (persistent-tree/weight (persistent-tree/right-child right-child)))
      (persistent-tree/single-l durable-store left-child right-child entry)
      (persistent-tree/double-l durable-store left-child right-child entry)))

(define (persistent-tree/single-l durable-store x r entry)
  (persistent-tree/make-branch 
   durable-store 
   (persistent-tree/make-branch durable-store 
                                x (persistent-tree/left-child r) entry)
   (persistent-tree/right-child r)
   (persistent-tree/object-map-entry r)))

(define (persistent-tree/double-l durable-store x r entry)
  (let ((r.l (persistent-tree/left-child r)))
    (persistent-tree/make-branch 
     durable-store
     (persistent-tree/make-branch durable-store
                                  x
                                  (persistent-tree/left-child  r.l)
                                  entry)
     (persistent-tree/make-branch durable-store
                                  (persistent-tree/right-child r.l)
                                  (persistent-tree/right-child r)
                                  (persistent-tree/object-map-entry r))
     (persistent-tree/object-map-entry r.l))))

(define (persistent-tree/r-join durable-store left-child right-child entry)
  (if (&amp;lt; (persistent-tree/weight (persistent-tree/right-child left-child))
         (persistent-tree/weight (persistent-tree/left-child left-child)))
      (persistent-tree/single-r durable-store left-child right-child entry)
      (persistent-tree/double-r durable-store left-child right-child entry)))

(define (persistent-tree/single-r durable-store l z entry)
  (persistent-tree/make-branch
   durable-store
   (persistent-tree/left-child l)
   (persistent-tree/make-branch durable-store
                                (persistent-tree/right-child l)
                                z
                                entry)
   (persistent-tree/object-map-entry l)))

(define (persistent-tree/double-r durable-store l z entry)
  (let ((l.r (persistent-tree/right-child  l)))
    (persistent-tree/make-branch 
     durable-store
     (persistent-tree/make-branch durable-store
                                  (persistent-tree/left-child  l)
                                  (persistent-tree/left-child  l.r)
                                  (persistent-tree/object-map-entry l))
     (persistent-tree/make-branch durable-store
                                  (persistent-tree/right-child l.r)
                                  z
                                  entry)
     (persistent-tree/object-map-entry l.r))))
&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;
In the next post, I will describe how we use this structure to implement transactions, simulate side-effects, and turn schema migration into a non-issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4681425616947909876?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4681425616947909876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4681425616947909876' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4681425616947909876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4681425616947909876'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/12/oh-yeah-about-that-persistent-store.html' title='Oh yeah, about that persistent store....'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8922314871991639708</id><published>2010-10-18T12:23:00.000-07:00</published><updated>2010-10-18T12:23:35.890-07:00</updated><title type='text'>No ILC for me</title><content type='html'>Alas, I'm unable to attend ILC 2010.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8922314871991639708?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8922314871991639708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8922314871991639708' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8922314871991639708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8922314871991639708'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/10/no-ilc-for-me.html' title='No ILC for me'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5359233119906174019</id><published>2010-09-02T10:16:00.000-07:00</published><updated>2010-09-02T10:16:38.355-07:00</updated><title type='text'>For your amusement...</title><content type='html'>Some computer &lt;a href="http://en.wikipedia.org/wiki/Tom_Swifty"&gt;Tom Swifties&lt;/a&gt;:
&lt;ul&gt;
&lt;li&gt;“I thought I would free up more memory on the second pass,” Tom recollected.&lt;/li&gt;
&lt;li&gt;“You should always check the pre-conditions,” Tom asserted.&lt;/li&gt;
&lt;li&gt;“Did you use SSL?” Tom asked cryptically.&lt;/li&gt;
&lt;li&gt;“If one of those is smaller, put it first,” Tom ordered weakly.&lt;/li&gt;
&lt;li&gt;“Command continuations discard values,” Tom said expressionlessly.&lt;/li&gt;
&lt;li&gt;“That isn't null or a cons cell,” Tom said listlessly.&lt;/li&gt;
&lt;li&gt;“Does this return an answer?” Tom asked haltingly.&lt;/li&gt;
&lt;li&gt;“This program implicitly depends upon time,” Tom stated.&lt;/li&gt;
&lt;li&gt;“Maybe it's in Reverse Polish Notation,” Tom put forth.&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/8288194986820249216-5359233119906174019?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5359233119906174019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5359233119906174019' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5359233119906174019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5359233119906174019'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/09/for-your-amusement.html' title='For your amusement...'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-9164370651576208522</id><published>2010-08-20T08:53:00.000-07:00</published><updated>2010-08-20T08:53:51.975-07:00</updated><title type='text'>INTERNATIONAL LISP CONFERENCE 2010 - HIGHLIGHTS and CALL for PAPERS</title><content type='html'>&lt;pre&gt;With the usual apologies to those who receive multiple copies of this...

 INTERNATIONAL LISP CONFERENCE 2010 - HIGHLIGHTS and CALL for PAPERS 

Important Dates:
~~~~~~~~~~~~~~~~

 * Deadline for all submissions (FIRM): September 6, 2010
 * Early registration: September 16, 2010
 * Author notification: September 20, 2010
 * Final paper due (in electronic form): October 5, 2010
 * Conference: October 19-21, 2010


Invited Speakers:
~~~~~~~~~~~~~~~~~

We are proud to announce that, for the 2010 edition, we will have the
following invited talks:

 * Lawrence Hunter
     Building a Mind for Life

 * Jans Aasman
     AllegroGraph and the Linked Open Data Cloud

 * Marc Feeley
     Gambit Scheme: Inside Out

 * Peter Seibel
     Common Lisp Standardization: The Good, the Bad, and the Ugly

 * Don Syme
     F#: Taking Succinct, Efficient, Typed Functional Programming 
     into the Mainstream

 * Lowel Hawkinson
     Lisp for Breakthrough Products

More information about speakers and talks is available at
&lt;a href="http://www.international-lisp-conference.org/2010/speakers"&gt;http://www.international-lisp-conference.org/2010/speakers&lt;/a&gt;


Registration:
~~~~~~~~~~~~~

Rates for Early Registration (before or on September 16, 2010)

ALU member
 &amp;amp; ACM member      $355
 &amp;amp; ACM non member  $390
 &amp;amp; Student         $150

ALU Individual Sponsors
 &amp;amp; ACM member      $280
 &amp;amp; ACM non-member  $315
 &amp;amp; Student         n/a

non-member of ALU
 &amp;amp; ACM member      $430
 &amp;amp; ACM non-member  $465
 &amp;amp; Student         $165

Rates for Late Registration (after September 16, 2010 &amp;amp; Onsite)

ALU member
 &amp;amp; ACM member      $440
 &amp;amp; ACM non member  $485
 &amp;amp; Student         $185

ALU Individual Sponsors
 &amp;amp; ACM member      $365
 &amp;amp; ACM non-member  $410
 &amp;amp; Student         n/a

non-member of ALU
 &amp;amp; ACM member      $515
 &amp;amp; ACM non-member  $560
 &amp;amp; Student         $200

Due to colocation, registration must be done using ILC/SPLASH'10
unified registration forms available at &lt;a href="http://splashcon.org/"&gt;http://splashcon.org/&lt;/a&gt;

Please note that the registration page (page 3) has the option "SPLASH
(OOPSLA/Onward!)" selected by default.  If you are only planning to
attend ILC, don't forget to deselect that option.


Travel and Accommodation:
~~~~~~~~~~~~~~~~~~~~~~~~~

SouthWest Airlines offers low fares into Reno but requires booking
online at &lt;a href="http://www.southwest.com/"&gt;www.southwest.com&lt;/a&gt;

John Ascuaga's Nugget offers reduced rates for ILC participants.
Please, visit &lt;a href="http://splashcon.org/"&gt;http://splashcon.org/&lt;/a&gt; to obtain the group code.


Scope:
~~~~~~

Lisp is one of the greatest ideas from computer science and a major
influence for almost all programming languages and for all
sufficiently complex software applications.

The International Lisp Conference is a forum for the discussion of
Lisp and, in particular, the design, implementation and application of
any of the Lisp dialects.  We encourage everyone interested in Lisp to
participate.

We invite high quality submissions in all areas involving Lisp
dialects and any other languages in the Lisp family, including, but
not limited to, ACL2, AutoLisp, Clojure, Common Lisp, ECMAScript,
Dylan, Emacs Lisp, ISLISP, Racket, Scheme, etc.

Topics may include any and all combinations of Lisp and:

 * Language design and implementation
 * Language critique
 * Language integration, inter-operation and deployment
 * Applications (especially commercial)
 * 'Pearls' (of wisdom)
 * Experience reports and case studies
 * Reflection, meta-object protocols, meta-programming
 * Domain-specific languages
 * Programming paradigms and environments
 * Parallel and distributed computing
 * Software evolution
 * Theorem proving
 * Scientific computing
 * Data mining
 * Semantic web

We also encourage submissions about known ideas as long as they are
presented in a new setting and/or in a highly elegant way.

Authors concerned about the appropriateness of a topic may communicate
by electronic mail with the program chair prior to submission.

Accepted papers will be published in the ACM Digital Library (PENDING).

Papers must be written in English and submitted electronically at
&lt;a href="http://www.easychair.org/conferences?conf=ilc2010"&gt;http://www.easychair.org/conferences?conf=ilc2010&lt;/a&gt; in PDF or WORD
format.  Final submissions must not exceed 15 pages and need to use
the ACM format, for which templates can be found at:
&lt;a href="http://www.acm.org/sigs/pubs/proceed/template.html"&gt;http://www.acm.org/sigs/pubs/proceed/template.html&lt;/a&gt;.

Each paper should explain its contributions in both general and
technical terms, identifying what has been accomplished, explaining
why it is significant, and comparing it with previous work. Authors
should strive to make their papers understandable to a broad audience.
Each paper will be judged according to its significance, novelty,
correctness, clarity, and elegance.

The official language of the conference is English.  Some further
information is available at the conference web site, with more details
added later.  See: &lt;a href="http://www.international-lisp-conference.org/"&gt;http://www.international-lisp-conference.org/&lt;/a&gt;

Technical Program:
~~~~~~~~~~~~~~~~~~

Original submissions in all areas related to the conference themes are
invited for the following categories.

 * Papers: Technical papers of up to 15 pages that describe original
   results or explain known ideas in new and elegant ways.

 * Demonstrations: Abstracts of up to 4 pages for demonstrations of
   tools, libraries, and applications.

 * Tutorials: Abstracts of up to 4 pages for in-depth presentations
   about topics of special interest for at least 90 minutes and up to
   180 minutes.

 * Workshops: Abstracts of up to 4 pages for groups of people who
   intend to work on a focused topic for half a day.

 * Panel discussions: Abstracts of up to 4 pages for discussions about
   current themes. Panel discussion proposals must mention panel
   members who are willing to partake in a discussion.

 * Lightning talks: Abstracts of up to one page for talks to last for
   no more than 5 minutes.

Depending on the technical content, each submitted paper will be
classified by the program committee as either a technical paper or as
an experience paper; and authors will be informed about this
classification.  Note that all interesting submissions are considered
valuable contributions to the success of the ILC series of
conferences.  As in past ILC's since 2007, accepted papers in both
categories will be presented at the conference, included in the
proceedings, and submitted to the ACM digital library.


Organizing Committee:
~~~~~~~~~~~~~~~~~~~~~

 * General Chair:
   JonL White - The Ginger IceCream Factory of Palo Alto, ALU

 * Program Chair:
   Antonio Leitao - Instituto Superior Tecnico/INESC-ID

 * Conference Treasurer:
   Duane Rettig - Franz, Inc., ALU Director

 * Publicity Chair:
   Daniel Herring - ALU Director

 * ALU Treasurer:
   Rusty Johnson - TASC, Inc., ALU Director


Program Committee:
~~~~~~~~~~~~~~~~~~

 * Antonio Leitao - Instituto Superior Tecnico/INESC-ID, Portugal
 * Alex Fukunaga - University of Tokyo, Japan
 * Charlotte Herzeel - Vrije Universiteit Brussel, Belgium
 * Christophe Rhodes - Goldsmiths College, University of London, UK
 * Didier Verna - EPITA Research and Development Laboratory, France
 * Duane Rettig - Franz, Inc., USA
 * Giuseppe Attardi - University of Pisa, Italy
 * Jeff Shrager - Symbolic Systems Program, Stanford University, USA
 * Joe Marshall - Google, Inc., USA
 * Julian Padget - University of Bath, UK
 * Keith Corbett - Clozure Associates, USA
 * Kent Pitman - PTC, USA
 * Manuel Serrano - INRIA Sophia Antipolis, France
 * Marc Feeley - University of Montreal, Canada
 * Marie Beurton-Aimar University of Bordeaux 1, France
 * Mark Stickel - SRI International, USA
 * Matthias Felleisen - Northeastern University, USA
 * Scott McKay - ITA Software, USA


Contacts:
~~~~~~~~~

 * Questions: ilc10-organizing-committee at alu.org

 * Program Chair: ilc2010 at easychair.org

For more information, see &lt;a href="http://www.international-lisp-conference.org/"&gt;http://www.international-lisp-conference.org/&lt;/a&gt;
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-9164370651576208522?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/9164370651576208522/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=9164370651576208522' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/9164370651576208522'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/9164370651576208522'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/international-lisp-conference-2010.html' title='INTERNATIONAL LISP CONFERENCE 2010 - HIGHLIGHTS and CALL for PAPERS'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2660299699778202871</id><published>2010-08-18T09:41:00.000-07:00</published><updated>2010-08-18T09:41:41.028-07:00</updated><title type='text'>P ≠ NP (part 2 correction)</title><content type='html'>In the previous post I said that one example of an NP problem is “Check if two computer programs always produce the same output.”  &lt;a href="http://www.blogger.com/profile/16923431648214439769"&gt;jkff&lt;/a&gt; commented:&lt;blockquote&gt;The "check if two computer programs always produce the same output" is not NP. It's simply undecidable and cannot be solved in any amount of time.&lt;/blockquote&gt;
I blew it and oversimplified the statement.  At &lt;a href="http://en.wikipedia.org/wiki/List_of_NP-complete_problems"&gt;Wikipedia&lt;/a&gt;, they have a list of commonly known NP-complete problems and on that list is “Inequivalence of simple functions.” I seriously mangled the meaning because I was daydreaming about assembly code.  What I should have done is put some restrictions on what sort of computer program I meant.&lt;br /&gt;&lt;br /&gt;
First, we have to restrict ourselves to programs that we can prove will always return an answer within a given amount of time.  A computer program that does not have any loops, backward jumps (gotos), subroutine calls, or exceptions should simply run from from start to finish.  Second, we do not allow the program to save any state between runs; the output must be a pure function of the input.  Furthermore, we restrict the input to a finite set (for example, integers that expressible in a single 32-bit word).  Now suppose we have two such programs.  To prove they are not equivalent, we need to find a 32-bit integer input that makes each program give a different answer.  By trial and error we will eventually find such an input or exhaustively show that there is none.  However, if someone were to claim that a particular input produced different output, then it is easy to check by simply trying it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2660299699778202871?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2660299699778202871/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2660299699778202871' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2660299699778202871'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2660299699778202871'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/p-np-part-2-correction.html' title='P ≠ NP (part 2 correction)'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-9100799382785398819</id><published>2010-08-17T12:02:00.000-07:00</published><updated>2010-08-18T08:57:46.981-07:00</updated><title type='text'>P ≠ NP (part 2)</title><content type='html'>As I mentioned in my last post, P and NP are commonly encountered complexity classes.  Knowing what complexity class a problem is in can give us some idea of how difficult it may be to solve the problem.  So what's the difference between P and NP?
I don't want to get into the technical definition of P and NP, so I'm going to make broad generalizations that aren't technically rigorous, but will give you a feel for the difference.&lt;br /&gt;
&lt;br /&gt;
Problems in class P are generally considered “tractable” by computer scientists.  By this we mean that a computer can probably solve such a problem efficiently and relatively quickly.  Recall that the complexity classes relate the ‘number of pieces’ to the difficulty.  If you can solve a particular problem in P, then a similiar problem with a ‘larger number of pieces’ is likely within your grasp (and if not, it is usually a question of upgrading to a better computer).  Problems in class P are the ‘meat and potatoes’ of computer programs.&lt;br /&gt;
&lt;br /&gt;
Before I discuss NP, let me introduce the complexity class EXPTIME.  EXPTIME is where you find some really hard problems, like computer chess or Go.  It is true that there are computers that can play chess really well, but if we were to modify the rules of chess to add a couple of new pieces and make the board 9x9 instead of 8x8, it would greatly increase the difficulty of the game.  Problems in EXPTIME are generally considered “intractable”.  By this we mean that a computer will have a hard time solving such a problem efficiently and quickly.  And if you are able to solve a particular problem in EXPTIME, then a similar problem with just ‘a few more pieces’ is likely beyond your grasp, no matter how fancy a computer you might buy.  Problems in class EXPTIME take a lot of time and money to solve.&lt;br /&gt;
&lt;br /&gt;
So what about NP?  Problems in NP are quite curious.  They seem to be very difficult to solve, much like EXPTIME problems, but they have the unusual property that it is very easy to &lt;em&gt;check&lt;/em&gt; if a solution is correct.  Let me illustrate:  if I showed you a chess position and claimed that it was a good position for white, you'd have to do a lot of work to verify whether my claim was true.  In fact, it would have to be about the same amount of work it took me to come up with the position in the first place.  On the other hand, if I were to show you a jigsaw puzzle and claim that I had finished it, you could tell at a glance whether my claim were true.  Problems in NP seem to be much harder to solve than problems in P, but as easy to verify as problems in P.  That is a little weird.&lt;br /&gt;
&lt;br /&gt;
Problems in NP are often encountered in computer programs, and many of these kind of problems, although very difficult to solve, have &lt;em&gt;approximations&lt;/em&gt; that are relatively easy.  In some cases, when a perfect solution is not needed, one that is ‘good enough’ will be a lot easier to compute.  Another weird thing is that a lot of problems in NP don't sound at all like they'd be hard to solve.  Here are some examples:
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Take a group of people and divide them into two subgroups such that both subgroups have exactly the same amount of change in their pockets. (No, you aren't allowed to move the change around.)&lt;/li&gt;
&lt;li&gt;Find the shortest path that visits all the major landmarks in a city.&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="background-color: yellow;"&gt;Check if two computer programs always produce the same output.&lt;/span&gt;&lt;span class="Apple-style-span" style="background-color: white;"&gt;&lt;i&gt;&amp;nbsp;&amp;nbsp;Whoops! &amp;nbsp;I blew this one. &amp;nbsp;Check the next posting.&lt;/i&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
There is one final bit of weirdness.  It is easy to prove that EXPTIME problems are much harder to solve that P problems, but no one has proven that NP problems are harder than P problems. (or that they &lt;em&gt;aren't&lt;/em&gt; harder than P problems!)  This isn't for lack of trying.  Many smart people have worked on a proof for some time.  There's a million dollar prize for the first person to prove this one way or the other.  Recently, Vinay Deolalikar of HP Labs claimed that he has a proof.  Unfortunately, other experts in the field have pointed out flaws in the proof that may invalidate it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-9100799382785398819?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/9100799382785398819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=9100799382785398819' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/9100799382785398819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/9100799382785398819'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/p-np-part-2.html' title='P ≠ NP (part 2)'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6035048394878102773</id><published>2010-08-13T14:22:00.000-07:00</published><updated>2010-08-13T14:22:32.630-07:00</updated><title type='text'>P ≠ NP  (part 1)</title><content type='html'>I'm sure most people who read this blog know a bit about what this means, but I want to try to explain it in a way my mom could understand.  I won't go into excruciating detail, and I'll probably gloss over interesting points.&lt;br /&gt;&lt;br /&gt;
Let's start with an analogy.  Suppose you go to the store to buy a present for your nephew.  He likes jigsaw puzzles, so you want to get him one.  He's going to be twelve years old, so you need to find one that has the appropriate challenge.  A simple one with four pieces might be great for a two year-old, but your nephew would find that boring.  A big one with ten thousand pieces is probably too much for him.  You know he just finished one with five hundred pieces, so you pick one with six hundred pieces because it won't be too easy, but not too frustrating.  What you are doing is estimating the complexity of the puzzle.&lt;br /&gt;&lt;br /&gt;
When you get to the store you find that they are sold out of jigsaw puzzles.  They have a variety of other puzzles, though.  They have a Rubik's cube, a Sudoku book, some cryptograms, a Tower of Hanoi, etc.  They have models you can put together as well.  But these things aren't jigsaw puzzles.  You can't estimate the complexity the same way.  A model with five hundred pieces would be quite a bit more difficult to assemble than a jigsaw puzzle with the same number of pieces.&lt;br /&gt;&lt;br /&gt;
Perhaps you look at the age ratings for the various puzzles.  The eight-piece Tower of Hanoi puzzle is rated for ages ten and up, so maybe a twelve piece?  The standard 3x3x3 Rubik's cube is rated for ages eight and up, but would the 4x4x4 be too hard or too easy?  What about the 5x5x5?&lt;br /&gt;&lt;br /&gt;
The kind of rating system you use to describe the difficulty of a puzzle is analogous to the “complexity class” of a problem.  The complexity class roughly describes how hard a problem will be to solve, and more importantly, how much harder ‘big’ problems are compared to the ‘small’ ones.  Here's what I mean:  if I take a jigsaw puzzle, any jigsaw puzzle, and double the number of pieces in it, I'll make it roughly twice as hard (more or less).  If I take a cryptogram and double the number of words in it, I'll actually make it a lot easier.  If I take the Tower of Hanoi and double the number of discs, I'll make it incredibly harder, maybe even impossible.  These puzzles are in different complexity classes.&lt;br /&gt;&lt;br /&gt;
As it turns out, a lot of puzzles are in the same complexity class as the jigsaw puzzle:  the difficulty is reasonably proportional to the number of pieces.  Adding a piece or two doesn't change things that much, and it is easy to figure out how long it will take to solve if you've done a few of them.  A lot of puzzles are more like the Tower of Hanoi.  Adding a single piece will double the amount of time it takes to solve them.&lt;br /&gt;&lt;br /&gt;
P and NP are complexity classes for problems you might want to solve on a computer.  There are all sorts of rating systems, but everyone is familiar with the MPAA movie ratings.  There are all sorts of complexity classes, but most computer scientists are familiar with P and NP.&lt;br /&gt;&lt;br /&gt;
I'll pause here because the analogy is wearing thin.  The main point is that “P ≠ NP” is a statement about complexity classes.  In particular, it talks about two of the most popular complexity classes and that is part of the reason it is interesting.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6035048394878102773?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6035048394878102773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6035048394878102773' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6035048394878102773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6035048394878102773'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/p-np-part-1.html' title='P ≠ NP  (part 1)'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7714444971558937903</id><published>2010-08-12T10:00:00.000-07:00</published><updated>2010-08-12T10:00:22.343-07:00</updated><title type='text'>Rambling</title><content type='html'>Writing a blog is hard.  I need practice so I'm going to ramble a bit.&lt;br /&gt;&lt;br /&gt;

First, I'm very pleased that Blogger has improved their comment spam detection.  Every time I made a post I'd have to come back a day or two later and remove a bunch of pointless comment spam.&lt;br /&gt;&lt;br /&gt;

Second, I told my daughter that someone claims to have a proof that P ≠ NP.  She replied “Well, now we know that N doesn't equal 1.”&lt;br /&gt;&lt;br /&gt;

I read through the proof and I confess that I don't get it.  On the other hand, I think I want to get it, so I'll have to learn some interesting things.&lt;br /&gt;&lt;br /&gt;

Here's another thing I don't get.&lt;blockquote&gt;`` E8 is any of several closely related exceptional simple Lie groups and Lie algebras of dimension 248'' &lt;br /&gt;&lt;br /&gt;
``a simple Lie group is a connected non-abelian Lie group G which does not have nontrivial connected normal subgroups.'' &lt;br /&gt;&lt;br /&gt;
``a Lie group is a group which is also a differentiable manifold, with the property that the group operations are compatible with the smooth structure.'' &lt;br /&gt;&lt;br /&gt;
``a non-abelian group is a group (G, * ) in which there are at least two elements a and b of G such that a * b ≠ b * a.'' &lt;br /&gt;&lt;br /&gt;
``a connected space is a topological space which cannot be represented as the union of two or more disjoint nonempty open subsets'' &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7714444971558937903?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7714444971558937903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7714444971558937903' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7714444971558937903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7714444971558937903'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/rambling.html' title='Rambling'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3491710595537167509</id><published>2010-08-05T10:07:00.000-07:00</published><updated>2010-08-05T10:07:28.415-07:00</updated><title type='text'>Happy 80th Birthday to Neil Armstrong</title><content type='html'>Neil Armstrong turns 80 years old today!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3491710595537167509?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3491710595537167509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3491710595537167509' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3491710595537167509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3491710595537167509'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/happy-80th-birthday-to-neil-armstrong.html' title='Happy 80th Birthday to Neil Armstrong'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1356189903376739026</id><published>2010-08-03T11:10:00.000-07:00</published><updated>2010-08-03T11:10:18.454-07:00</updated><title type='text'>My definition</title><content type='html'>Here's my definition:&lt;blockquote&gt;A computer program is a description of a process which is formal enough to be carried out by a machine.&lt;/blockquote&gt;
Most of the other definitions describe a program as a ‘set of instructions’.  Some of the definitions suggest that these instructions should be organized in some way, perhaps as a (linear) list.  These instructions ‘make the computer do things’, ‘bring about a certain result’, ‘cause the computer to behave in a predetermined manner’, or ‘alter the contents of memory’.  But these definitions have an explicit or implicit assumption:  a sequential, imperative mode of thought.&lt;br /&gt;&lt;br /&gt;
Look at this Prolog code:
&lt;pre&gt;append(c(H,T), B, c(H,TB)) &lt;= append(T, B, TB).
append(nil, B, B).&lt;/pre&gt;
This code describes relationship of appending lists, but it doesn't specify &lt;em&gt;how&lt;/em&gt; to accomplish the appending.  Is the first clause an ‘instruction’ to build a list, or to take one apart?  Are the clauses to be run in any particular order?  Is there a deterministic ‘answer’?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1356189903376739026?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1356189903376739026/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1356189903376739026' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1356189903376739026'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1356189903376739026'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/my-definition.html' title='My definition'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2838236412311346761</id><published>2010-08-02T15:53:00.000-07:00</published><updated>2010-08-02T15:53:06.845-07:00</updated><title type='text'>What is a ‘computer program’?</title><content type='html'>This seems like a simple enough question.&lt;br /&gt;&lt;br /&gt;Here's what the web says.
A computer program is&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;a set of statements or instructions to be used directly or indirectly in a computer in order to bring about a certain result&lt;/li&gt;
&lt;li&gt;what makes the computer do things&lt;/li&gt;
&lt;li&gt;a set of instructions written in a programming language&lt;/li&gt;
&lt;li&gt;an algorithm written in a language that a computer can understand&lt;/li&gt;
&lt;li&gt;simply a long list of code written in another language&lt;/li&gt;
&lt;li&gt;a set of instructions for altering the contents of various words in the computer's memory&lt;/li&gt;
&lt;li&gt;a carefully thought out, step-by-step, set of instructions prepared by a programmer&lt;/li&gt;
&lt;li&gt;an organized list of instructions that, when executed, causes the computer to behave in a predetermined manner&lt;/li&gt;
&lt;li&gt;is a procedure (or algorithm) for performing some computation&lt;/li&gt;
&lt;li&gt;a bunch of instructions run by a computer, just like a storybook is just a whole bunch of sentences read by the reader&lt;/li&gt;&lt;/ol&gt;
&lt;br /&gt;
Does anyone have any better definitions?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2838236412311346761?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2838236412311346761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2838236412311346761' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2838236412311346761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2838236412311346761'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/08/what-is-computer-program.html' title='What is a ‘computer program’?'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-459217794320073817</id><published>2010-07-13T12:18:00.000-07:00</published><updated>2010-07-13T12:18:11.300-07:00</updated><title type='text'>Crazy person thinks ``Lisp sucks''</title><content type='html'>In &lt;a href="http://www.crazyontap.com/topic.php?TopicId=77343"&gt;this post&lt;/a&gt;, a person going by the initials CC declares:
&lt;blockquote&gt;There's a good reason almost no software has been written in lisp. Lisp sucks. Not just lisp, but the whole way the logic is arranged as nested things. The simplest problem becomes a mind-bending puzzle. &lt;/blockquote&gt;
&lt;blockquote&gt;
Instead of easy to understand: 
&lt;pre&gt;
if (a equals b) { 
  c = not d; 
} else { 
  c = d + b; 
}&lt;/pre&gt; 

You have this nested inner to outer logic where if is a function. 
&lt;pre&gt;
c = if(equals(a,b), not(d), plus(d,b)) 
&lt;/pre&gt;
The first is definitely more readible [&lt;i&gt;sic&lt;/i&gt;] and it reads like we think of the logic. No one thinks of if as a function that takes three arguments, and forcing you to work that way just makes you crazy.&lt;/blockquote&gt;
I suppose it is futile to argue with an admittedly crazy person, but perhaps being forced to work with conditionals has made me crazy as well.  A closer translation of the original code would be this:
&lt;pre&gt;
(if (equals a b)
    (setq c (not d))
    (setq c (+ d b)))
&lt;/pre&gt;
If these sorts of differences are a ``mind-bending puzzle'', perhaps the author should consider a career in the housekeeping or food-service industries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-459217794320073817?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/459217794320073817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=459217794320073817' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/459217794320073817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/459217794320073817'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/07/crazy-person-thinks-lisp-sucks.html' title='Crazy person thinks ``Lisp sucks&apos;&apos;'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2402707637203555250</id><published>2010-06-24T12:31:00.000-07:00</published><updated>2010-06-24T12:31:37.646-07:00</updated><title type='text'>Dr Scheme name change</title><content type='html'>I put together &lt;a href="http://sites.google.com/site/evalapply/name-change"&gt;a page&lt;/a&gt; that compares the various names of Dr. Scheme by how often people search for them in Google.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2402707637203555250?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2402707637203555250/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2402707637203555250' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2402707637203555250'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2402707637203555250'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/dr-scheme-name-change.html' title='Dr Scheme name change'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2946134160418440090</id><published>2010-06-11T08:45:00.000-07:00</published><updated>2010-06-11T09:36:49.860-07:00</updated><title type='text'>Buoyancy</title><content type='html'>&lt;a href="http://www.blogger.com/profile/13039816196174495030"&gt;Steve&lt;/a&gt; suggested:  &lt;em&gt;For this to work like you want, Java style, you'd have to add a Class member to the Box class, to represent the type of Box at runtime.&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Like this:
&lt;br /&gt;
&lt;pre&gt;public final class Box&amp;lt;E&amp;gt; {

  private final Class&amp;lt;E&amp;gt; type;
  private final E value;

  public Box (Class&amp;lt;E&amp;gt; type, E value) {
    this.type = checkNotNull(type, "type");
    this.value = value;
  }

  public E getValue() {
    return value;
  }

  public boolean isType (Class&amp;lt;?&amp;gt; specific) {
    return specific == this.type;
  }

  @SuppressWarnings("unchecked")
  public &amp;lt;X&amp;gt; Box&amp;lt;X&amp;gt; asType (Class&amp;lt;X&amp;gt; specific) {
    if (isType(specific)) {
      return (Box) this;
    } else {
      throw new ClassCastException();
    }
  }
}&lt;/pre&gt;
&lt;em&gt;You could then write a static generic filter taking an Iterable of generic Boxes and a Class object to filter by, and returning an Iterable of the correct type fairly simply.&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Sort of like this (assuming appropriate definitions of &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt;):
&lt;br /&gt;
&lt;pre&gt;// The essential code is in a &lt;b&gt;&lt;span class="Apple-style-span" style="color: #38761d;"&gt;bold green face&lt;/span&gt;&lt;/b&gt;.

public &amp;lt;X&amp;gt; Iterable&amp;lt;Box&amp;lt;X&amp;gt;&amp;gt; boxesOfType (final Class&amp;lt;X&amp;gt; type,
                                         Iterable&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt; boxes) {
  return
      &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;map&lt;/b&gt;&lt;/span&gt; (
          &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;filter&lt;/b&gt;&lt;/span&gt; (
              &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;boxes&lt;/b&gt;&lt;/span&gt;,
              new Predicate&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt; () {
                @Override
                public boolean apply (Box&amp;lt;?&amp;gt; box) {
                  &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;return box.isType(type);&lt;/b&gt;&lt;/span&gt;
                }
              }),
          new Function&amp;lt;Box&amp;lt;?&amp;gt;, Box&amp;lt;X&amp;gt;&amp;gt; () {
            @Override
            public Box&amp;lt;X&amp;gt; apply (Box&amp;lt;?&amp;gt; box) {
              &lt;span class="Apple-style-span" style="color: #38761d;"&gt;&lt;b&gt;return box.asType(type);&lt;/b&gt;&lt;/span&gt;
            }
          });
}&lt;/pre&gt;
&lt;em&gt;Dunno if that floats your boat, tho.&lt;/em&gt;
&lt;br /&gt;
&lt;br /&gt;
It definitely floats my boat (thanks, Steve) in that I can now, in a &lt;em&gt;typesafe&lt;/em&gt; manner, take a bunch of heterogeneous boxes and select and downcast them to a subset of homogeneous boxes.&lt;br /&gt;&lt;br /&gt;
I'll discuss the leaks in the boat in the next post.&lt;br /&gt;&lt;hr /&gt;
&lt;em&gt;Addendum&lt;/em&gt;&lt;br/&gt;&lt;br/&gt;
&lt;a href="http://www.blogger.com/profile/04628649386002008189"&gt;mquander&lt;/a&gt; offered a C# solution to the same problem:
&lt;pre&gt;internal interface IBox { }
 
public class Box&amp;lt;T&amp;gt; : IBox
{
    public T Value;
}
 
public static class BoxManipulators
{
    public static int MinimumIntegerInBox(IEnumerable&amp;lt;IBox&amp;gt; boxes)
    {
        return boxes.OfType&amp;lt;Box&amp;lt;int&amp;gt;&amp;gt;().Min(x =&amp;gt; x.Value);
    }
}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2946134160418440090?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2946134160418440090/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2946134160418440090' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2946134160418440090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2946134160418440090'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/buoyancy.html' title='Buoyancy'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1873302762885427248</id><published>2010-06-10T10:43:00.000-07:00</published><updated>2010-06-10T10:43:15.922-07:00</updated><title type='text'>An Illustrative Problem (Part II) correction</title><content type='html'>Blogger really munged Mike's code, so here is the relevant part correctly formatted:
&lt;pre&gt;public static int minimumIntegerInBox(Collection&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt; boxes) {
  Iterable&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt; intBoxes = filter(boxes,
      new Function&amp;lt;Box&amp;lt;?&amp;gt;, Boolean&amp;gt;() {
        @Override
        public Boolean of(Box&amp;lt;?&amp;gt; domainItem) {
          return domainItem.get() instanceof Integer;
        }
      });
  Iterable&amp;lt;Integer&amp;gt; ints = map(
      intBoxes,
      new Function&amp;lt;Box&amp;lt;?&amp;gt;, Integer&amp;gt;() {
        @Override
        public Integer of(Box&amp;lt;?&amp;gt; domainItem) {
          return Integer.class.cast(domainItem.get());
        }
      });
  return minimumElement(ints);
}

public static int minimumElement(Iterable&amp;lt;Integer&amp;gt; items) {
  return best(
      new Function&amp;lt;Pair&amp;lt;Integer, Integer&amp;gt;, Boolean&amp;gt;() {
        @Override
        public Boolean of(Pair&amp;lt;Integer, Integer&amp;gt; domainItem) {
          return domainItem.second() &amp;lt; domainItem.first();
        }
      },
      items);
}&lt;/pre&gt;
This is similar to what I started with, but I didn't like this solution for two reasons.
&lt;ol&gt;&lt;li&gt;The test for whether the &lt;code&gt;Box&amp;lt;?&amp;gt;&lt;/code&gt; is a &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt; relies on extracting the contents of the &lt;code&gt;Box&lt;/code&gt; and testing to see if it is an integer.  In other words, rather than relying on the type of the container, we explicitly look at the contents of the container.  This is an important distinction, but it might be hard to see it in this context.  Just because the box &lt;em&gt;happens&lt;/em&gt; to contain an integer at this point doesn't mean that it is a &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt;.  It could be a &lt;code&gt;Box&amp;lt;Number&amp;gt;&lt;/code&gt; or a &lt;code&gt;Box&amp;lt;Object&amp;gt;&lt;/code&gt; that &lt;em&gt;currently&lt;/em&gt; has an integer in it, but could just as well have some non-integer in it.  Conversely, it could be a &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt; that happens to have a &lt;code&gt;null&lt;/code&gt; in it.  For the purposes of finding the minimum element, a &lt;code&gt;null&lt;/code&gt; would be an issue, but if the task were to &amp;ldquo;fill all the &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt; with zero,&amp;rdquo; then this method of testing the box type would miss the &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt; with &lt;code&gt;null&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The type of &lt;code&gt;intBoxes&lt;/code&gt; is wrong.  It really ought to be &lt;code&gt;Iterable&amp;lt;Box&amp;lt;Integer&amp;gt;&amp;gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;
Anyone care to offer a fix?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1873302762885427248?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1873302762885427248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1873302762885427248' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1873302762885427248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1873302762885427248'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/illustrative-problem-part-ii-correction.html' title='An Illustrative Problem (Part II) correction'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-481432992731945016</id><published>2010-06-09T10:39:00.000-07:00</published><updated>2010-06-09T10:39:51.281-07:00</updated><title type='text'>An illustrative problem (part II)</title><content type='html'>&lt;a href="http://www.blogger.com/profile/15798013338569092950"&gt;Mike Coffin&lt;/a&gt; took the bait. (Thanks, Mike!)  Unfortunately, pasting code into the blog comments is a very poorly supported feature.  Blogs about Python must be interesting.  I'll recopy some of Mike's code here.&lt;br /&gt;&lt;br /&gt;
Mike said: &lt;em&gt;While I prefer this:&lt;/em&gt;
&lt;pre&gt;int minimumIntegerInBox (Collection&amp;lt;Box&amp;gt; boxes) {
    int result = Integer.MAX_VALUE;
    for (Box box : boxes) {
        if (box.get() instanceof Integer) {
            result = Math.min (result, Integer.class.cast (box.get()));
        }
    }
    return result;
}&lt;/pre&gt;
&lt;em&gt;that would be cheating.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;
It isn't cheating, but it isn't answering the question I posed, either.  It's more or less the obvious thing to do in Java or Lisp.  But conceptually it is pretty primitive.  I don't care about the machinery involved in traversing a list (the looping construct).  I want to take a binary operation like &lt;code&gt;Math.min&lt;/code&gt; and make it n-ary.&lt;br /&gt;&lt;br /&gt;
Mike gave a very complete solution, but I'm only going to reformat the relevant part:
&lt;pre&gt;public static int minimumIntegerInBox(Collection&amp;lt;Box&amp;gt; boxes) {
    Iterable&amp;lt;Box&amp;gt; intBoxes = 
        filter (boxes,
                new Function&amp;lt;Box, Boolean&amp;gt;() {
                    @Override
                    public Boolean of(Box domainItem) {
                        return domainItem.get() instanceof Integer;
                    }
                });

    Iterable ints = 
        map (intBoxes,
             new Function&amp;lt;Box, Integer&amp;gt;() {
                 @Override
                 public Integer of(Box domainItem) {
                     return Integer.class.cast(domainItem.get());
                 }
             });

    return minimumElement(ints);
}

public static int minimumElement(Iterable items) {
    return best(
        new Function&amp;lt;Pair, Boolean&amp;gt;() {
            @Override
            public Boolean of(Pair domainItem) {
                return domainItem.second() &amp;lt; domainItem.first();
            }
        },
        items);
}&lt;/pre&gt;
That's a lot closer to what I had in mind, but these are untyped &lt;code&gt;Box&lt;/code&gt;es.  I want to use parameterized &lt;code&gt;Box&lt;/code&gt;es.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-481432992731945016?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/481432992731945016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=481432992731945016' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/481432992731945016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/481432992731945016'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/illustrative-problem-part-ii.html' title='An illustrative problem (part II)'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5730709839566089734</id><published>2010-06-08T13:01:00.000-07:00</published><updated>2010-06-08T13:01:39.169-07:00</updated><title type='text'>An illustrative problem.</title><content type='html'>I'm working on a fairly simple problem and I think it illustrates something interesting.  Here is the problem statement:&lt;br /&gt;&lt;br /&gt;
A `box' is an object that has a name and can hold another object of a particular type (that is, there are boxes for integers, boxes for strings, boxes for floats, etc.)  You are given an unordered collection of various boxes and must find the smallest integer among the subset of boxes that contain integers.&lt;br /&gt;&lt;br /&gt;
To make it a tiny bit more challenging, we won't just write an ad-hoc loop.  We'll use &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;fold-left&lt;/code&gt;.  Since &lt;code&gt;fold-left&lt;/code&gt; is a bit scary, I'll write that part:
&lt;pre&gt;
(define (best better? list)
  (fold-left (lambda (best-so-far candidate)
               (if (or (null? best-so-far)
                       (better? candidate best-so-far))
                   candidate
                 best-so-far))
             '()
             list))

(define (minimum-element list)
  (best &amp;lt; list))
&lt;/pre&gt;
So assuming that &lt;code&gt;*box-list*&lt;/code&gt; is a variable containing our list of boxes, Exercise 1 is to write a program in Scheme or Lisp using &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;filter&lt;/code&gt;, and &lt;code&gt;minimum-element&lt;/code&gt; that finds the smallest integer (fixnum) in the boxes.&lt;br /&gt;&lt;hr /&gt;
Too easy?  Let's make it a bit trickier:  Code up the identical solution in Java.&lt;br /&gt;&lt;br /&gt;
Assume that &lt;code&gt;Box&lt;/code&gt; is a &lt;em&gt;generic&lt;/em&gt; (that is, parameterized) type, so &lt;code&gt;Box&amp;lt;Integer&amp;gt;&lt;/code&gt; would contain an &lt;code&gt;Integer&lt;/code&gt; and &lt;code&gt;Box&amp;lt;String&amp;gt;&lt;/code&gt; contains a &lt;code&gt;String&lt;/code&gt;, etc.  The variable &lt;code&gt;BoxList&lt;/code&gt; would be declared as &lt;code&gt;Collection&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt;&lt;/code&gt;, so we want a method with this signature:  &lt;code&gt;int minimumIntegerInBox (Collection&amp;lt;Box&amp;lt;?&amp;gt;&amp;gt; boxes)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;
I don't think it can be done without getting at least one &lt;code&gt;Unchecked conversion&lt;/code&gt; warning, but a cleverly placed &lt;code&gt;@SuppressWarnings("unchecked")&lt;/code&gt; will permit you to downcast a &lt;code&gt;Box&amp;lt;?&amp;gt;&lt;/code&gt; to a specific type, and then everything else should type check.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5730709839566089734?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5730709839566089734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5730709839566089734' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5730709839566089734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5730709839566089734'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/illustrative-problem.html' title='An illustrative problem.'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7438558845991619967</id><published>2010-06-07T15:52:00.000-07:00</published><updated>2010-06-07T15:52:48.951-07:00</updated><title type='text'>International Lisp Conference 2010 - Call for Papers</title><content type='html'>&lt;pre&gt;
***********************************************************************
*                                                                     *
*                  International Lisp Conference 2010                 *
*                         October 19-21, 2010                         *
*                    John Ascuaga's Nugget (Casino)                   *
*              Reno/Sparks, Nevada, USA (near Lake Tahoe)             *
*                                                                     *
*           Collocated with SPLASH 2010 (OOPSLA &amp; DLS &amp; more)         *
*               see also http://splashcon.org as well as              *
*          http://www.dynamic-languages-symposium.org/dls-10/         *
*                                                                     *
*              In association with ACM SIGPLAN (PENDING)              *
*                                                                     *
*********************************************************************** 


The Association of Lisp Users is pleased to announce that the 2010
International Lisp Conference will be held in Reno, Nevada, in
collocation with SPLASH 2010.  The scope includes all areas related to
the Lisp family of programming languages.

Accepted papers will be published in the ACM Digital Library (PENDING).

Extended Abstracts and Papers must be written in English and submitted
electronically at http://www.easychair.org/conferences?conf=ilc2010 in
PDF or WORD format. If an Extended Abstract is submitted, it must be 
between 2 and 4 pages, with full paper to follow before final deadline.

Final submissions must not exceed 15 pages and need to use the ACM 
format, for which templates which can be found at:
    http://www.acm.org/sigs/pubs/proceed/template.html.


Important Dates:
****************

* Deadline for Abstract Submission      August      1, 2010
* Deadline for Paper Submission         September   6, 2010
* Author notification                   September  20, 2010
* Final paper due (in electronic form)  October     5, 2010
* Conference                            October 19-21, 2010


Scope:
******

Lisp is one of the greatest ideas from computer science and a major
influence for almost all programming languages and for all
sufficiently complex software applications.

The International Lisp Conference is a forum for the discussion of
Lisp and, in particular, the design, implementation and application of
any of the Lisp dialects.  We encourage everyone interested in Lisp to
participate.

We invite high quality submissions in all areas involving Lisp
dialects and any other languages in the Lisp family, including, but
not limited to, ACL2, AutoLisp, Clojure, Common Lisp, ECMAScript,
Dylan, Emacs Lisp, ISLISP, Racket, Scheme, etc.

Topics may include any and all combinations of Lisp and:

* Language design and implementation
* Language critique
* Language integration, inter-operation and deployment
* Applications (especially commercial)
* 'Pearls' (of wisdom)
* Experience reports and case studies
* Reflection, meta-object protocols, meta-programming
* Domain-specific languages
* Programming paradigms and environments
* Parallel and distributed computing
* Software evolution
* Theorem proving
* Scientific computing
* Data mining
* Semantic web

We also encourage submissions about known ideas as long as they are
presented in a new setting and/or in a highly elegant way.

Authors concerned about the appropriateness of a topic may communicate
by electronic mail with the program chair prior to submission.

Each paper should explain its contributions in both general and
technical terms, identifying what has been accomplished, explaining
why it is significant, and comparing it with previous work. Authors
should strive to make their papers understandable to a broad audience.
Each paper will be judged according to its significance, novelty,
correctness, clarity, and elegance.

The official language of the conference is English.  Some further
information is available at the conference web site, with more details
added later.  See: http://www.international-lisp-conference.org

Technical Program:
******************

Original submissions in all areas related to the conference themes are
invited for the following categories.

* Papers: Technical papers of up to 15 pages that describe original
   results or explain known ideas in new and elegant ways, or extended
   abstracts of 4 pages soon followed by the corresponding full paper.

* Demonstrations: Abstracts of up to 4 pages for demonstrations of
   tools, libraries, and applications.

* Tutorials: Abstracts of up to 4 pages for in-depth presentations
   about topics of special interest for at least 90 minutes and up to
   180 minutes. 

* Workshops: Abstracts of up to 4 pages for groups of people who
   intend to work on a focused topic for half a day.

* Panel discussions: Abstracts of up to 4 pages for discussions about
   current themes. Panel discussion proposals must mention panel
   members who are willing to partake in a discussion.

* Lightning talks: Abstracts of up to one page for talks to last for
   no more than 5 minutes.

Depending on the technical content, each submitted paper will be
classified by the program committee as either a technical paper or as
an experience paper; and authors will be informed about this
classification.  Note that all interesting submissions are considered
valuable contributions to the success of the ILC series of
conferences.  As in past ILC's since 2007, accepted papers in both
categories will be presented at the conference, included in the
proceedings, and submitted to the ACM digital library.


Organizing Committee:
*********************

* General Chair:
   JonL White          The Ginger IceCream Factory of Palo Alto, ALU

* Program Chair:
   Antonio Leitao      Instituto Superior Tecnico/INESC-ID

* Conference Treasurer:
   Duane Rettig        Franz, Inc., ALU Director

* Publicity Chair:
   Daniel Herring      ALU Director

* ALU Treasurer:
   Rusty Johnson       TASC, Inc., ALU Director


Program Committee:
******************

* Antonio Leitao      Instituto Superior Tecnico/INESC-ID, Portugal
* Alex Fukunaga       University of Tokyo, Japan
* Charlotte Herzeel   Vrije Universiteit Brussel, Belgium
* Christophe Rhodes   Goldsmiths College, University of London, UK
* Didier Verna        EPITA Research and Development Laboratory, France
* Duane Rettig        Franz, Inc., USA
* Giuseppe Attardi    University of Pisa, Italy
* Jeff Shrager        Symbolic Systems Program, Stanford University, USA
* Joe Marshall        Google, Inc., USA
* Julian Padget       University of Bath, UK
* Keith Corbet        Clozure Associates, USA
* Kent Pitman         PTC, USA
* Manuel Serrano      INRIA Sophia Antipolis, France
* Marc Feeley         University of  Montreal, Canada
* Marie Beurton-Aimar University of Bordeaux 1, France
* Mark Stickel        SRI International, USA
* Matthias Felleisen  Northeastern University, USA
* Scott McKay         ITA Software, USA


Contacts:
*********

* Questions:         ilc10-organizing-committee at alu.org

* Program Chair:     ilc2010 at easychair.org

For more information, see http://www.international-lisp-conference.org
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7438558845991619967?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7438558845991619967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7438558845991619967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7438558845991619967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7438558845991619967'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/international-lisp-conference-2010-call.html' title='International Lisp Conference 2010 - Call for Papers'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1890980135488273147</id><published>2010-06-04T09:52:00.000-07:00</published><updated>2010-06-04T09:52:10.579-07:00</updated><title type='text'>It was quiet..... too quiet.....</title><content type='html'>Things seemed a bit quiet here until I looked at some older posts and discovered comments I hadn't seen before.  It seems that gmail had gotten into its head that forwarded posts were spam.  Wonderful.  My apologies for not responding to people.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1890980135488273147?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1890980135488273147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1890980135488273147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1890980135488273147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1890980135488273147'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/it-was-quiet-too-quiet.html' title='It was quiet..... too quiet.....'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5289546869208273154</id><published>2010-06-04T09:37:00.000-07:00</published><updated>2010-06-04T09:37:15.335-07:00</updated><title type='text'>Choose and perish</title><content type='html'>&lt;a href="http://picasaweb.google.com/lh/photo/sQ4CYShpoaqSOCfkk9_I6AsEI5ukD_XfHtNQUd6q-YI?feat=blogger" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh5.ggpht.com/_0hfeSxONUSM/TAkpaPEPibI/AAAAAAAABXQ/nP01UQDiYfg/s512/IMG_20100604_091240.jpg" /&gt;&lt;/a&gt;I chose ok...&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;(I had to retouch the buttons because the camera overexposed them.)&lt;/span&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5289546869208273154?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5289546869208273154/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5289546869208273154' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5289546869208273154'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5289546869208273154'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/06/choose-and-perish.html' title='Choose and perish'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_0hfeSxONUSM/TAkpaPEPibI/AAAAAAAABXQ/nP01UQDiYfg/s72-c/IMG_20100604_091240.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6397300566192890740</id><published>2010-05-26T09:53:00.000-07:00</published><updated>2010-05-26T09:53:51.193-07:00</updated><title type='text'></title><content type='html'>I have two collections and I need to see if one of them is a representation of the other.  Since each kind of object has an Id, the two sets of Ids should match, but since collections are unordered, you can't just do a pairwise match.&lt;br /&gt;&lt;br /&gt;

The solution is to use the &lt;code&gt;containsAll&lt;/code&gt; method to see if each collection contains all the elements of the other one.  In Scheme this is trivial:
&lt;pre&gt;
(let ((foo-ids (map foo-id (get-foos)))
      (bar-ids (map bar-id (get-bars))))
  (and (contains-all foo-ids bar-ids)
       (contains-all bar-ids foo-ids)))
&lt;/pre&gt;
in Java, not so easy:
&lt;pre&gt;
Collection&amp;lt;Id&amp;gt; fooIds =
    Collections2.transform(getFoos(),
                           new Function&amp;lt;Foo, Id&amp;gt; () {
                             @Override
                             public Id apply (Foo foo) {
                               return foo.getId();
                             }
                           });
Collection&amp;lt;Id&amp;gt; barIds =
    Collections2.transform(getBars(),
                           new Function&amp;lt;Bar, Id&amp;gt; () {
                             @Override
                             public Id apply (Bar bar) {
                               return bar.getId();
                             }
                           });
return fooIds.containsAll(barIds) &amp;amp;&amp;amp;
       barIds.containsAll(fooIds);
&lt;/pre&gt;
I know that this is not Java's forte, but this isn't some obscure stratified monadic combinator, it's just &lt;code&gt;map&lt;/code&gt; for heaven's sake!  If future maintainers of this code can't handle &lt;code&gt;map&lt;/code&gt;, maybe they should consider a career in the fast food industry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6397300566192890740?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6397300566192890740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6397300566192890740' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6397300566192890740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6397300566192890740'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/i-have-two-collections-and-i-need-to.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4334245273028554912</id><published>2010-05-25T16:26:00.000-07:00</published><updated>2010-05-25T16:26:53.311-07:00</updated><title type='text'>Pathetic</title><content type='html'>&lt;pre&gt;Collection&lt;Id&gt; expectedIds =
    Collections2.transform(fooCollection,
                           new Function&lt;Foo, Id&gt; () {
                             @Override
                             public Id apply (Foo foo) {
                               return foo.getId();
                             }
                          });

&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4334245273028554912?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4334245273028554912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4334245273028554912' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4334245273028554912'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4334245273028554912'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/pathetic.html' title='Pathetic'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4079751281648779500</id><published>2010-05-25T09:12:00.000-07:00</published><updated>2010-05-25T09:12:01.501-07:00</updated><title type='text'>Looking forward to ILC 2010</title><content type='html'>&lt;p&gt;Daniel Herring sends this announcement:
 
&lt;blockquote&gt; 
&lt;p&gt;The &lt;a href="http://alu.org/"&gt;ALU&lt;/a&gt; is pleased to announce that the International Lisp Conference
  2010 (ILC-2010) will be held mid October in Reno, Nevada.
 
&lt;p&gt;ILC-2010 will be colocated with &lt;a href="http://splashcon.org/"&gt;OOPSLA/SPLASH&lt;/a&gt;.
 
&lt;p&gt;Colocated conferences allow people to explore other sessions; but the
  ILC itself will be the same independent, lisp-intensive event you've
  grown to love.
 
&lt;p&gt;More announcements, including the ILC conference website and call for
  papers, will appear in the coming weeks.
 
&lt;p&gt;Sincerely,&lt;br&gt; 
p.p. Daniel Herring&lt;br&gt; 
ALU Board of Directors
&lt;/blockquote&gt; 
&lt;br /&gt;&lt;br /&gt;
I'm planning on being there.  Anybody want to write a paper?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4079751281648779500?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4079751281648779500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4079751281648779500' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4079751281648779500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4079751281648779500'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/looking-forward-to-ilc-2010.html' title='Looking forward to ILC 2010'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2522868031451773929</id><published>2010-05-11T12:17:00.000-07:00</published><updated>2010-05-11T12:17:56.133-07:00</updated><title type='text'>Doing it wrong</title><content type='html'>I'm hacking some Java code and I'm going to do a query and return some objects.  Since I have no need to mutate the collection, I decide to use an immutable list.  To make a long story short, I did this:
&lt;pre&gt;import com.foo.bar.ImmutableList;

final ImmutableList.Builder&amp;lt;Object&amp;gt; intermediateCollection = ImmutableList.builder();
    ...
    if (fromObjectClass.isInstance(object))
       intermediateCollection.add(object);
    ...
    query (intermediateCollection.build())
&lt;/pre&gt;
This is bad enough, but we'll let it slide.&lt;br /&gt;&lt;br /&gt;


It turns out that the query method &lt;em&gt;wants&lt;/em&gt; to mutate the collection.  (This is obnoxious.  When I borrow something I try to leave it in the same condition as when I got it.  I don't go mutating it and I expect my libraries to extend the same courtesy.)  I guess I don't care all that much &amp;mdash; I can simply make the collection mutable.&lt;br /&gt;&lt;br /&gt;


&lt;em&gt;So why can't I just delete the `Immutable' prefix?&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;

&lt;pre&gt;// &lt;em&gt;Now it is named `Lists' with an `s'&lt;/em&gt;
import com.foo.bar.Lists;

// &lt;em&gt;Now I have to specify the implementation technique.&lt;/em&gt;
// &lt;em&gt;Why isn't it a List.builder?&lt;/em&gt;
  final List&amp;lt;Object&amp;gt; intermediateCollection = Lists.newArrayList();

// &lt;em&gt;Why isn't there build that is a no-op?&lt;/em&gt;
   query (intermediateCollection)
&lt;/pre&gt;
This is simply wrong.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2522868031451773929?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2522868031451773929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2522868031451773929' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2522868031451773929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2522868031451773929'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/doing-it-wrong.html' title='Doing it wrong'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4537092382279576045</id><published>2010-05-06T12:26:00.000-07:00</published><updated>2010-05-06T12:26:50.357-07:00</updated><title type='text'></title><content type='html'>Not too many takers on that batch of questions.  Oh well.&lt;br /&gt;&lt;br /&gt;
Anyone care to take a stab at how these notions of equality relate to procedural abstraction?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4537092382279576045?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4537092382279576045/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4537092382279576045' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4537092382279576045'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4537092382279576045'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/not-too-many-takers-on-that-batch-of.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-6539773843102464182</id><published>2010-05-05T09:18:00.000-07:00</published><updated>2010-05-05T09:18:58.104-07:00</updated><title type='text'>Pondering</title><content type='html'>What does it mean to say that two programs are &amp;lsquo;the same&amp;rsquo;?&lt;br /&gt;&lt;br /&gt;
What does it mean to say that two programs are &amp;lsquo;equivalent&amp;rsquo;?&lt;br /&gt;&lt;br /&gt;
What is the difference between &lt;em&gt;intensional&lt;/em&gt; and &lt;em&gt;extensional&lt;/em&gt; equivalence?&lt;br /&gt;&lt;br /&gt;
What is &amp;lsquo;observational equivalence&amp;rsquo;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-6539773843102464182?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/6539773843102464182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=6539773843102464182' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6539773843102464182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/6539773843102464182'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/pondering.html' title='Pondering'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2303891122629455768</id><published>2010-05-04T08:36:00.000-07:00</published><updated>2010-05-04T11:09:26.839-07:00</updated><title type='text'>C++ vs. Lisp</title><content type='html'>Yes, a provocative title.&lt;br /&gt;&lt;br /&gt;
In &lt;a href="http://www.ebhakt.info/blog/?p=2291"&gt;this blog post&lt;/a&gt;, Mr. Ebhakt decides to compare C++ and Lisp.  (Go ahead and read it, I'll wait...)&lt;br /&gt;&lt;br /&gt;

Wow!  It seems the original article was written by Brandon Corfman.  My apologies to Mr. Corfman.  Shame on you, Ebhakt.&lt;br /&gt;&lt;br /&gt;

I had to laugh.  First he is disappointed that it took him eight hours to find a solution (Norvig did it in two), and his initial attempt took 220 lines of code (Norvig did it in 45).  One source of conciseness was because Lisp function calls return useful values while C++ function calls typically cause side effects.  Thus the Lisp expression
&lt;pre&gt;(format t "~a:~ {  ~a}~%" num (reverse words))&lt;/pre&gt;
could make use of the return value from &lt;code&gt;reverse&lt;/code&gt; whereas the C++ version
&lt;pre&gt;words.reverse(); 
cout &lt;&lt; num &lt;&lt; ":"; 
for (list&lt;string&gt;::const_iterator i = words.begin(); i != words.end(); ++i) 
    cout &lt;&lt; *i; 
cout &lt;&lt; "\n";&lt;/pre&gt;
could not.&lt;br /&gt;&lt;br /&gt;
Mr. Ebhakt also noted that &amp;lsquo;most of the complexity of the STL arises from its explicit use of iterators.&amp;rsquo;  &lt;a href="http://home.pipeline.com/~hbaker1/home.html"&gt;Henry Baker&lt;/a&gt; pointed out in 1992 that iterators are &lt;a href="http://home.pipeline.com/~hbaker1/Iterator.html"&gt;&amp;ldquo;Signs of Weakness in Object-Oriented Languages&amp;rdquo;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;
Armed with this knowledge, Mr. Corfman &amp;ldquo;decided to rewrite all of the STL’s algorithms to accept containers instead of iterators&amp;rdquo; and &amp;ldquo;also make the algorithms (where possible) return copies of containers instead of iterators&amp;rdquo;.  Furthermore, he decided &amp;ldquo;to build another layer of utility functions on top of the STL to perform common tasks such as tokenizing strings, looking up values in containers, reading from files&amp;rdquo; etc.
The end result?  &amp;ldquo;The new line count is 79 lines.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
I wont bother quoting &lt;a href="http://philip.greenspun.com/"&gt;Philip Greenspun&lt;/a&gt; at this point.&lt;br /&gt;&lt;br /&gt;
Mr. Corfman sums it all up: &amp;lsquo;C++ isn’t all that bad.&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
Of course it doesn't have garbage collection, macros, and closures, but it has &amp;lsquo;extensive library support&amp;rsquo; (which he just spent hours throwing away and re-implementing) &amp;lsquo;and of course, its premier status&amp;rsquo; which, with an additional two dollars will buy you a large coffee.&lt;br /&gt;&lt;br /&gt;
Mr. Corfman came so close to the mark and just missed it.  Lisp isn't magic, it's at a sweet spot in the design space.  Lisp doesn't do anything the other languages &lt;em&gt;cannot&lt;/em&gt;, but it does what the other ones &lt;em&gt;do not&lt;/em&gt;.  It works that much harder for the programmer so the programmer can do other things (like program).  Sure, a &lt;a href="http://en.wikipedia.org/wiki/Ford_Model_A_(1927%E2%80%931931)"&gt;Ford Model-A&lt;/a&gt; isn't all that bad.  It can get you where you're going and it is unsurpassed in popularity, but if you spend most of your waking hours behind the wheel, wouldn't you rather drive a &lt;a href="http://en.wikipedia.org/wiki/Duesenberg"&gt;Dusenberg&lt;/a&gt;?&lt;br /&gt;&lt;hr /&gt;
After finding out that this was written by Brandon Corfman, I decided to see if his opinion had changed at all.  On his &lt;a href="http://www.cliki.net/Brandon%20Corfman"&gt;Road to Lisp&lt;/a&gt; page, he says &amp;ldquo;Lisp still has the definite edge on the power curve. I think the clue for me is that I still find myself saying, &amp;lsquo;Why didn't they do this like Lisp?&amp;rsquo;&amp;rdquo;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2303891122629455768?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2303891122629455768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2303891122629455768' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2303891122629455768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2303891122629455768'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/c-vs-lisp.html' title='C++ vs. Lisp'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-7083119981811170046</id><published>2010-05-03T17:55:00.000-07:00</published><updated>2010-05-03T17:55:18.050-07:00</updated><title type='text'>Quasi-cranks</title><content type='html'>Every now and then I run into &amp;lsquo;quasi-cranks&amp;rsquo; in the computer industry.  These people
don't fit the mold of the standard &lt;a ref="http://en.wikipedia.org/wiki/Crank_(person)"&gt;crank&lt;/a&gt;.  For instance, they often appear reasonably normal (although in this field, there is more than the usual amount of latitude for &amp;lsquo;normal&amp;rsquo;), they generally don't rant unless you specifically mention certain trigger words, and they seem to have successful computer careers.  But when you start talking about technical details, you realize that these people are profoundly confused.&lt;br /&gt;&lt;br /&gt;
I often help people debug their code.  Most of the time I can follow what they're thinking and how the code is structured.  Every now and then, though, I'll come across someone that has some insane hairball of code.  They'll point out the location where the error is raised and explain what the intended behavior is. (I don't know why they insist on telling me this.  If the code behaved the way it was intended, there wouldn't be an error.)  I listen patiently and then ask them what the code &lt;em&gt;actually&lt;/em&gt; did, and then try to understand where the reasoning went wrong.  It's at this point I get the first inklings of weirdness.  I'll find out that what they want to do is fairly simple, but that the error is bizarre.  For example, they'll say they want to look something up in a table, but the error message is something like &lt;code&gt;Error: Variable reference to syntactic keyword&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;
Now this can go one of three ways.  The best is when I ask them if they're doing something weird and they sheepishly admit &amp;ldquo;Yeah, I thought I could model this with a first-class environment... I guess I should use a hash table.&amp;rdquo;  These people have a future in computers.  They're exploring.&lt;br /&gt;&lt;br /&gt;
Second best is when they say &amp;ldquo;I'm using a first-class environment to hold my lookup table.&amp;rdquo; and when I suggest some more conventional mechanism they assert &amp;ldquo;No, I need to be able to call &lt;code&gt;eval&lt;/code&gt;.&amp;rdquo; and it turns out they have some hair-brained idea that kinda sounds plausible, but won't work in practice.  These people can make a living in computers, but they need a structured environment.&lt;br /&gt;&lt;br /&gt;
Then there are the third type of people.  When you look at the hairball of code you see a bunch of things that make no sense at all:  continuations that are captured, but not bound to a variable, spurious data structure copying, strange and unexpected variable names, checks for errors that cannot logically occur, etc.  If you ask them what they are doing, they'll say something like &amp;ldquo;I have to &lt;code&gt;eval&lt;/code&gt; the current continuation on the stack.&amp;rdquo;  or &amp;ldquo;That forces the oldspace to swap.&amp;rdquo;  If you try to encourage them to try a standard approach they explain &amp;ldquo;Look, this code pushes a binding on the continuation and I need to find a way to remove it.  The error message is because the garbage collector is evaluating the wrong binding.  If I could remove the binding here, then the collector will see the correct binding here.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
The first couple of times I ran into people like this I tried to nudge them in the right direction.  It doesn't work.  People like this are &lt;em&gt;profoundly&lt;/em&gt; confused.  I'm not sure what they are doing.  &lt;em&gt;They&lt;/em&gt; think they are programming, but the logic is unrelated to any model of programming &lt;em&gt;I&lt;/em&gt; am familiar with.  I'll usually feign ignorance and suggest some debugging tool or something.  (Sometimes they'll come back with a &amp;lsquo;solution&amp;rsquo; to their bug:  &amp;ldquo;Oh yeah, it was easy, I just pushed a second null on the continuation.&amp;rdquo;)&lt;br /&gt;&lt;br /&gt;
You can tell these quasi-cranks from the way they use computer jargon and terminology.  They &amp;ldquo;misunderstand or fail to use standard notation and terminology,&amp;rdquo; and &amp;ldquo;ignore fine distinctions which are essential to correctly understand mainstream belief.&amp;rdquo; (as per the Wikipedia article).  But it astounds me that some of these people seem to have careers as programmers despite their confusion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-7083119981811170046?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/7083119981811170046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=7083119981811170046' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7083119981811170046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/7083119981811170046'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/05/quasi-cranks.html' title='Quasi-cranks'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3327471262773422861</id><published>2010-04-30T09:14:00.000-07:00</published><updated>2010-04-30T09:14:57.891-07:00</updated><title type='text'>Importance of terminology</title><content type='html'>An upcoming study of first-year computer science students has an interesting observation about terminology.  It seems that their understanding of the computer science vocabulary is much worse than one would expect.  You cannot blame the teachers because I'm sure they were unaware of the problem.  You cannot blame the students for being `dumb' because nearly all of them could identify a `function body'.  Yet fewer than one in three could tell you what is meant by a `defined name' or a `predicate'.  Really!  The results surprised me, but in thinking about it, I have a couple of personal anecdotes that highlight the problem.&lt;br /&gt;&lt;br /&gt;
Every year or so there used to be a heated debate on one or more usenet groups (remember usenet?) between the static and dynamic type factions.  (I won't argue either side.) One year, however, I encountered someone who challenged me about my viewpoint.  He said that he knew many people who held a similar viewpoint to mine, and he had a lot of respect for them.  They weren't idiots.  But he could not understand their rationale.  His viewpoint made perfect logical sense to him, so how could another intelligent person disagree so violently?  He didn't want to argue, he wanted to understand how anyone could find the alternative viewpoint to be as logical.  (He assumed it must be so, or there wouldn't be so many respectable adherents to it.)&lt;br /&gt;&lt;br /&gt;
We discussed it back and forth for a while in a non-heated way and it dawned on me that the fundamental problem is simply one of terminology.  `Static typers' and `dynamic typers' have completely different understandings of the word `type'.  They cannot agree on the simplest things because they each think the other knows what he means by `type'.&lt;br /&gt;&lt;br /&gt;
For the sake of clarity, I'll lay out the definitions:&lt;ul&gt;
&lt;li&gt;Type&lt;sub&gt;1&lt;/sub&gt; &amp;mdash; an equivalence class for data.  Two objects are of the &amp;lsquo;same type&amp;rsquo; if operations on one could be (or could have been) performed on the other with analagous results.  For example, &amp;lsquo;integer&amp;rsquo; is a type because objects like &amp;lsquo;3&amp;rsquo; and &amp;lsquo;42&amp;rsquo; can both be added, subtracted, multiplied, and divided. &lt;/li&gt;
&lt;li&gt;Type&lt;sub&gt;2&lt;/sub&gt; &amp;mdash; a purely syntactic label that can be assigned to a code fragment.  There are rules for assigning such labels to primitive fragments and rules for composing types as the code fragments are composed.  Certain compositions are disallowed.  A well-typed program has no disallowed compositions, and a type-checking program can verify this.  By clever construction of the rules, certain useful runtime properties can be proven.
&lt;/li&gt;&lt;/ul&gt;
I think you can see that these two definitions have almost nothing to do with each other.&lt;br /&gt;&lt;br /&gt;
Once I understood this, I stopped using the word &amp;lsquo;type&amp;rsquo; and started talking about &amp;lsquo;tags&amp;rsquo; &amp;mdash; manifest metadata attached to &lt;em&gt;all&lt;/em&gt; objects in memory that describe what each object is.  &amp;lsquo;Static typers&amp;rsquo; understand the utility and benefit such things, they don't understand why anyone would want to forego compile-time &amp;lsquo;type checks&amp;rsquo;.  They &lt;em&gt;don't&lt;/em&gt; mean the annoying task of decorating every variable and procedure in the system with a &amp;lsquo;type specifier&amp;rsquo;, but rather having the compiler notice that your code said to &lt;code&gt;vector-ref&lt;/code&gt; the result of a floating point divide and that most likely is &lt;em&gt;not&lt;/em&gt; what you intended.  Notwithstanding the contrarians who complain that maybe they &lt;em&gt;did&lt;/em&gt; want to vector-ref a float, every Lisp hacker &lt;em&gt;I&lt;/em&gt; know of appreciates getting early notification of these kind of errors (provided that false positives are very rare and it remains unnecessary to kowtow to the compiler).&lt;br /&gt;&lt;br /&gt;
Next anecdote later...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3327471262773422861?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3327471262773422861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3327471262773422861' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3327471262773422861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3327471262773422861'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/importance-of-terminology.html' title='Importance of terminology'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4197712083459382687</id><published>2010-04-29T08:22:00.001-07:00</published><updated>2010-04-29T08:22:16.386-07:00</updated><title type='text'>Persistent store:  a new record type</title><content type='html'>The object map allows us to abstract away the physical addresses where
our objects are stored, but only if we can remember where we put it!
We need another record type and things will get much more
interesting.&lt;br /&gt;&lt;br /&gt;

A &lt;code&gt;commit-record&lt;/code&gt; is a special record that we will write to
the durable storage.  The &lt;code&gt;commit-record&lt;/code&gt; will contain
(among other things) the physical address of the root of the object
map.  We'll require a little more functionality from the durable
storage layer.  When we first use a previously existing persistent
store, we need to ask the durable storage layer to find the most
recent &lt;em&gt;valid&lt;/em&gt; and &lt;em&gt;complete&lt;/em&gt; commit record.  It can do
this by starting at the newest record and reading backwards through
earlier records until it finds one.&lt;br /&gt;&lt;br /&gt;

Since computers are unreliable, we have to take into account the
possibility that the computer could crash in the middle of writing a
commit record.  When looking for the commit record on restart, we
ignore any partially written commit records.  When we're writing
a commit record to the durable storage, we don't return control until
we're &lt;em&gt;sure&lt;/em&gt; that the record is durably saved and complete.  If
the computer crashes at any time before that last byte is written, we
will recover using the previous valid commit record, and if it crashes
at any time &lt;em&gt;after&lt;/em&gt; that last byte is written we'll use this
one.&lt;br /&gt;&lt;br /&gt;

There is an extra burder on the durable store to be able to find the
most recent commit record, but we can take a different burden off the
store.  Instead of insisting that every record be durably written at
the time we send it to the store, we can allow most of the records to
be buffered until it is more convenient to write.  We only insist that
the buffers be flushed prior to writing the commit record.  This makes
a huge difference in the performance of the store.&lt;br /&gt;&lt;br /&gt;

There is a design decision to be made at this point.  When we save
durable objects, we can either send the object and the object-map
records to the durable store immediattely, or we can defer sending
them until we want to write the commit record.  The eager strategy is
more responsive when we are doing a lot of writes because we can start
writing records while we're computing.  The lazy strategy will reduce
the total amount of traffic (every time we modify the object-map, we
need to write new object-map records, if newer entries supersede
records that haven't even been written, we can elide the write), but
when we eventually &lt;em&gt;do&lt;/em&gt; write the commit record, there will be
a flurry of activity as we force the pending writes.  This will cause
a noticable pause at commit time.&lt;br /&gt;&lt;br /&gt;

There is another interesting design decision.  In many cases, it is ok
to lose a few seconds of work if the computer crashes.  You wouldn't
want to lose anything if you were logging financial transactions, but
if you were checkpointing a text file, you might consider it ok if two
or three of the most recently typed letters didn't get saved.  When
the computer restarted, you'd re-open the text file and find that what
you were typing wasn't completely there, but was mostly there.  You
can re-enter the last couple of keystrokes.  If this is acceptable
&amp;mdash; and it is for some applications and not for others &amp;mdash;
then it is not necessary for commit records to be immediately written
to durable storage so long as they are written in a reasonably timely
manner (within a second or two).  The freedom to defer writing commit
records like this will also improve performance quite a bit.&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
Exercise:  Add commit records to your durable store and the ability to
recover the most recent commit record when opening an existing store.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-4197712083459382687?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4197712083459382687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4197712083459382687' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4197712083459382687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4197712083459382687'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/persistent-store-new-record-type.html' title='Persistent store:  a new record type'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-4116833580204822008</id><published>2010-04-27T13:46:00.000-07:00</published><updated>2010-04-27T13:47:52.482-07:00</updated><title type='text'>Open letter to the SEC</title><content type='html'>&lt;br /&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
To Whom it may concern:&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
In the document entitled&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;span style="font-family: 'Times New Roman'; font-size: medium;"&gt;&lt;pre class="foobar" style="white-space: pre-wrap; word-wrap: break-word;"&gt;    SECURITIES AND EXCHANGE COMMISSION
    17 CFR Parts 200, 229, 230, 232, 239, 240, 243 and 249
    Release Nos. 33-9117; 34-61858; File No. S7-08-10
    RIN 3235-AK37 
    ASSET-BACKED SECURITIES
&lt;/pre&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse; font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;span style="font-family: 'Times New Roman'; font-size: medium;"&gt;a number of changes to Item 601 of Regulation S-K, Rules 101, 201, 202 and 305 of Regulation S-T, a new Rule 314 of Regulation S-T and changes to Form 8-K are proposed. These changes are proposed to accommodate the filing of the ‘waterfall’ computer program. The document requests comments on this proposal.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;span style="font-family: 'Times New Roman'; font-size: medium;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="border-collapse: collapse;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;em&gt;Is it appropriate for us to require most ABS issuers to file the waterfall computer program?&lt;/em&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
As mentioned in the proposal, ABS issuers are currently required to submit an informal, ‘English language’ description of the waterfall. A computer program would be far more formal and less likely to be ambiguous or misinterpreted.&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;em&gt;Is it appropriate to require issuers to submit the waterfall computer program in a single programming language, such as Python, to give investors the benefit of a standardized process? If so, is Python the best choice or are there other open source programming language alternatives (such as PERL) that would be better suited for these purposes?&lt;/em&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
The proposal goes to great lengths to justify the choice of Python as the language in which the waterfall program should be expressed. Unfortunately, every one of the justifications is either incorrect or irrelevant.&lt;/div&gt;
&lt;ul style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;li style="margin-left: 15px;"&gt;&lt;em&gt;Python is an open source interpreted programming language.&lt;/em&gt;&amp;nbsp;— Python is more accurately described as a family of programming languages with several implementations. The Python Software Foundation supports one particular implementation, but both Microsoft and Nokia offer alternative implementations. The Python Software Foundation provides an interpreter, but there are versions of Python that are fully compiled, byte-code compiled, or JIT compiled.&lt;/li&gt;
&lt;li style="margin-left: 15px;"&gt;&lt;em&gt;Open source means that the source code is available to all users.&lt;/em&gt;— This is true, but irrelevant. INTERCAL is an open source language, yet it is completely unsuitable for the purposes of writing a waterfall program. On the other hand, the Microsoft implementation of ECMAScript is proprietary, yet ECMAScript is certainly a language to consider for waterfall programs.&lt;/li&gt;
&lt;li style="margin-left: 15px;"&gt;&lt;em&gt;An interpreted language is a programming language that requires an interpreter in the target computer for program execution.&lt;/em&gt;&amp;nbsp;— Interpretation is a technique for implementing a language. Few languages&amp;nbsp;&lt;em&gt;require&lt;/em&gt;&amp;nbsp;an interpreter, and as noted above, compilers for Python exist.&lt;/li&gt;
&lt;li style="margin-left: 15px;"&gt;&lt;em&gt;Since Python is an interpreted language that does not need to be compiled prior to running it, executable code would not need to be published on EDGAR. We define executable code in Rule 11 of Regulation S-T [17 CFR 239.11] as instructions to a computer to carry out operations that use features beyond the viewer's, reader's, or Internet browser's native ability to interpret and display HTML, PDF, and static graphic files. Such code may be in binary (machine language) or in script form. Executable code includes disruptive code.&lt;/em&gt;— A Python program is most certainly ‘executable’ by the definition supplied.&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
The proposal appears to be suggesting that&amp;nbsp;&lt;em&gt;safety&lt;/em&gt;&amp;nbsp;is an important desideratum. This includes the safety of the EDGAR system as well as the safety of the investors that would presumably use the waterfall program. The proposal concludes that a language that is executed by an interpreter would be inherently safer than a compiled language. This is false. There has been a considerable amount of research into computer safety, and it is clear that safety is very hard to achieve even if it is the highest priority in the design. Provable safety is not, and never has been, a goal of Python.&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
To conclude, I believe that a formal description of the waterfall algorithms written as a computer program may be quite beneficial to investors. The proposal, however, fails to enumerate the desiderata for the language such a program would be written in. The proposal makes a few erroneous assertions and then puts forward Python as a suggested language. While Python is a popular language, it was never intended to be used as a critical component of such an important part of the U.S. economy.&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
I suggest that Securities and Exchange Commission, if they intend to pursue the path of requiring a formal waterfall program to be provided, follow a formal process for finding or developing a suitable language. First, the requirements for such a language need to be specified. Second, these requirements should be compared against existing and proposed languages. Finally, one or more of the languages should be adopted and implemented.&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="border-collapse: collapse; font-family: 'Times New Roman'; font-size: medium;"&gt;
Sincerely,&lt;br /&gt;Joe Marshall&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/8288194986820249216-4116833580204822008?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/4116833580204822008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=4116833580204822008' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4116833580204822008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/4116833580204822008'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/open-letter-to-sec.html' title='Open letter to the SEC'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-675228709605730794</id><published>2010-04-27T11:32:00.000-07:00</published><updated>2010-04-27T11:32:39.237-07:00</updated><title type='text'>More on persistence</title><content type='html'>I haven't forgotten about persistence, I've just been busy.&lt;br /&gt;&lt;br /&gt;
When I last blogged about it, I discussed the need for an object-map.  The object-map maps logical object ids to the physical location that the durable store placed the object.  We'll be putting a couple more kinds of things in the durable store, so at this point it is a good idea to add a record abstraction on top of the durable store.  It is easier to show this than to describe it.  Here are the actual contents of a test durable store:
&lt;pre&gt;
;;; A persistent store.  Do not edit.
(object 1 929 &amp;lt;string&amp;gt; 1 "zip")
(leaf 1 38)
(object 1 269 &amp;lt;string&amp;gt; 1 "zero?")
(leaf 1 82)
(branch 1 116 0 38)
(object 1 387 &amp;lt;string&amp;gt; 1 "yield-current-thread")
(leaf 1 148)
(branch 1 0 197 82)
(leaf 1 38)
(leaf 1 82)
(branch 1 242 230 148)
(object 1 535 &amp;lt;string&amp;gt; 1 "xsubstring-move!")
(leaf 1 277)
(branch 1 322 0 38)
(branch 1 242 335 148)
(object 1 295 &amp;lt;string&amp;gt; 1 "xsubstring-find-previous-char-in-set")
&lt;/pre&gt;
A &amp;lsquo;record&amp;rsquo; is simply a list.  The first element is one of &lt;code&gt;object&lt;/code&gt;, &lt;code&gt;leaf&lt;/code&gt;, or &lt;code&gt;branch&lt;/code&gt;.  The second element is the version number of the record layout in case I decide to change how the record is represented.  The remaining elements are the contents of the record.  For a leaf, it is simply the address of the object that this leaf represents.  For a branch, it is the addresses of the left and right child and the address of the object the branch represents.  (This is using a functional binary tree as detailed in the code.)  An object record has four additional components.  First is the object-id.  Second is the  data tag of the object.  Third is a version number of the serialization method for the object and finally the serialized representation of the object itself.&lt;br /&gt;&lt;br /&gt;
This is clearly not the most parsimonious representation, and it could be made much more robust by including record length information, checksums or CRCs, and by ensuring that user data (such as those strings) cannot spoof a record boundary, but this is demonstration code, not production code.&lt;br /&gt;&lt;br /&gt;
In the next installment, we add another record type.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-675228709605730794?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/675228709605730794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=675228709605730794' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/675228709605730794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/675228709605730794'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/more-on-persistence.html' title='More on persistence'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5163981740572003357</id><published>2010-04-23T10:01:00.000-07:00</published><updated>2010-04-23T10:01:49.124-07:00</updated><title type='text'>The Education of JRM</title><content type='html'>I learn so much from the Internet.  Yesterday, someone posted a link to my &lt;a href="http://funcall.blogspot.com/2010/04/whenever-i-write-code-in-java.html"&gt;post&lt;/a&gt; about Java.  I got close to 3 orders of magnitude increase in traffic.  Many people commiserated with me, and I thank them.  Some, however, went the extra mile:
&lt;blockquote&gt;An ellipsis has three dots.&lt;/blockquote&gt;
&lt;em&gt;Mea culpa&lt;/em&gt;.  I was sloppy.  Fortunately, another reader defended me:
&lt;blockquote&gt;An ellipsis at the end of a sentence is three dots, followed by a period. He/she did it right.&lt;/blockquote&gt;
Alas, if I did it right it was only by accident.
&lt;blockquote&gt; There should be a space between the ellipsis and the period. Putting four dots ala George Lucas is incorrect....&lt;/blockquote&gt;
I'm flattered to be placed in such good company!&lt;br /&gt;&lt;br /&gt;
One reader pointed out that the problem might not lie in Java, but within me:
&lt;blockquote&gt;This is what reflection is for. If you can't solve this problem with reflection, then you don't really have reflection.&lt;/blockquote&gt;
while others offered concrete advice:
&lt;blockquote&gt;Maybe you just need to learn to type faster.&lt;/blockquote&gt;
and still others tactfully suggested I broaden my horizons:
&lt;blockquote&gt;ever code in C++? this isn't unique to Java, noob.&lt;/blockquote&gt;
I thank you all for the advice and the spirit in which you offered it.  I believe I'll reflect upon it this weekend &amp;mdash; assuming I really have reflection.  I will continue posting in the hope that I can be further edified.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-5163981740572003357?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/5163981740572003357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=5163981740572003357' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5163981740572003357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/5163981740572003357'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/education-of-jrm.html' title='The Education of JRM'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3657428340450693746</id><published>2010-04-21T16:18:00.000-07:00</published><updated>2010-04-21T16:18:10.074-07:00</updated><title type='text'>Whenever I write code in Java....</title><content type='html'>Whenever I write code in Java I feel like I'm filling out endless forms in triplicate.&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;Ok, sir, I'll just need your type signature here, here, and ... here.  Now will this be everything, or...&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;Well, I might need to raise an exception.&amp;lsquo;&lt;br /&gt;&lt;br /&gt;
&lt;em&gt;The compiler purses its lips.&lt;/em&gt;&amp;ldquo;An exception?  Hmmm... let's see.... Yes, I think we can do that... I have the form over here...  Yes, here it is.  Now I need you to list all the exceptions you expect to raise here.  Oh, wait, you have other classes?  We'll have to file an amendment to them.  Just put the type signature here, here, ... yes, copy that list of exceptions....&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3657428340450693746?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3657428340450693746/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3657428340450693746' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3657428340450693746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3657428340450693746'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/whenever-i-write-code-in-java.html' title='Whenever I write code in Java....'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>28</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-8061991830827369392</id><published>2010-04-21T09:12:00.000-07:00</published><updated>2010-04-21T09:12:40.205-07:00</updated><title type='text'></title><content type='html'>Student M overhears the argument between Students A and T.
&amp;ldquo;What seems to be the problem?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T explains, &amp;lsquo;We're at an impasse.  I want to be able to
change the semantics of the language...&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student A says &amp;ldquo;... and I want the semantics to be
stable.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T says &amp;lsquo;It seems to me that if the program is a tool for
solving a problem, then the language itself is just another tool.  I
should be able to make changes to the language if it helps solve the
problem.&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student A replies &amp;ldquo;And I have no problem with that &lt;em&gt;in
principle&lt;/em&gt;, but when I'm writing a program, I need to know what
the language semantics are so I can have some idea about whether my
program will work.  If the semantics change after I write the program,
I won't even know whether I &lt;em&gt;have&lt;/em&gt; a program.  Mangle the
semantics all you want, but then tell me what they are and don't
change them!&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T says &amp;lsquo;I'm not going to &amp;ldquo;mangle&amp;rdquo; the
semantics.  But I don't want to lock myself out of a solution for
&lt;em&gt;your&lt;/em&gt; convenience.  I want to be able to take whatever
baseline semantics we have and tweak them as appropriate,  but I can't
change the semantics &lt;em&gt;before&lt;/em&gt; I write the program the changes
them!&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student A says &amp;ldquo;This is just impossible.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student M interrupts &amp;ldquo;Time out, everyone.  Ok, now let me get
this straight.  You...&amp;rdquo; and he points to student A, &amp;ldquo;want the
meaning of your code to be stable, and &lt;em&gt;you&lt;/em&gt;...&amp;rdquo; (he points
to student T) &amp;ldquo; want to be able to tailor the semantics to suit
you.  That's simple!  Why are you arguing?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Students A and T look confused.  &amp;lsquo;Simple?!&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student M says, &amp;ldquo;Of course.  You both agree that changing the
language will change the semantics, and conversely changing the
semantics changes the language...&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Students A and T nod.&lt;br /&gt;&lt;br /&gt;

Student M turns to student A &amp;ldquo;So you write your code in your
language (let's call it L), and we'll be sure that L has stable,
static semantics that never change.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student A says &amp;ldquo;That's what I'm talking about.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T objects &amp;lsquo;Hold on!  You're just completely ignoring me!
 What if I don't like the semantics?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student M turns to student T &amp;ldquo;I'm not done, yet.  &lt;em&gt;You&lt;/em&gt;
want the freedom to morph language L into language L', which is very
much like L, but with maybe a few changes...&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T interrupts &amp;lsquo;.. or a lot of changes.  And not just L',
I want L, L', L'', L''', whatever changes I think are necessary
and &lt;em&gt;whenever&lt;/em&gt; I think they are necessary.&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student M continues &amp;ldquo;... or a lot of changes.  I get you.  Now
here's the question:  If I have a program in language L, but I have a
machine that runs a &lt;em&gt;different&lt;/em&gt; language &amp;mdash; call it C
&amp;mdash; what do I do?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T replies &amp;lsquo;Write an interpreter...&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student A answers &amp;ldquo; ... or a compiler.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student M says &amp;ldquo;Bingo!  Problem solved.  Simply use language L
as the base language for an interpreter or compiler for programs in L'
(or L'' or L''', etc.)&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student A thinks for a moment then says &amp;ldquo;Works for me.  If I
need to understand code written in L', I can just compile it down to L.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T looks dubious.  &amp;lsquo;Wait a second.  You're suggesting I
write a compiler?  What if I want several different language features
to mix and match?  I'm supposed to write compilers for each of
them?!&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student M shrugs &amp;ldquo;Well, &lt;em&gt;you're&lt;/em&gt; the one that wants to
change the language, you can't expect student A to write them.
Besides, it isn't that much work.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;

Student T protests &amp;lsquo;Not that much work?  It's a compiler!  Flow
control, analysis, register allocation, code generation!  I just want
to tweak the language, not invent a whole new one from scratch!&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

Student M counters &amp;ldquo;Who said you need to do all that?  A
compiler is simply a program that translates code from one language to
another, right?  If you can express the constructs of language L' (or
L'' etc.) in terms of language L, then that's all you need to do.  If
you're really just tweaking the language, then your
&amp;lsquo;compiler&amp;rsquo; is mostly the identity function.&amp;ldquo;&lt;br /&gt;&lt;br /&gt;

&amp;lsquo;And the parts that aren't?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;

&amp;ldquo;Macros.&amp;rdquo;&lt;br /&gt;
&lt;hr /&gt;&lt;br /&gt;
&lt;em&gt;Is student M's solution reasonable?&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-8061991830827369392?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/8061991830827369392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=8061991830827369392' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8061991830827369392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/8061991830827369392'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/student-m-overhears-argument-between.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-1638957445766099744</id><published>2010-04-15T09:12:00.000-07:00</published><updated>2010-04-15T09:12:37.573-07:00</updated><title type='text'>Another wacky idea</title><content type='html'>Student T exclaims &amp;ldquo;I have a great idea!&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;Sometimes I want to make a computer language that is very similar to an existing language with just a couple of exceptions.  Wouldn't it be cool if we could just tweak the semantics of the existing language?&amp;rdquo;&lt;br &gt;&lt;br /&gt;
Student A asks &amp;lsquo;What do you mean?  What part of the semantics?&amp;lsquo;&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;Oh, I don't know...  Anything!&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;Anything?  Anything at all?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;Sure.  Why limit ourselves?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;Like, say, adding or removing special forms?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;Of course.  Anything!&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;How about changing from call-by-value to call-by-name?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;That would be harder, but why not?  Imagine you're running a program and you realize you need lazy evaluation for some part of it.  Well, you just turn on lazy evaluation for that segment of code and turn it off again when it returns!  Voila!&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;What?  While the code is running?&amp;rsquo;
Student A thinks for a moment and says, &amp;lsquo;So in essence you want the language semantics to be a function of time.&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
Student T replies &amp;ldquo;No no no.  I just want to be able to change them on the fly if I want.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
Student A says &amp;rsquo;Yes, that's what I mean.  At different times you could have different semantics.&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
Student T says &amp;ldquo;Yes, but only if you change them.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;And how do I change them?&amp;rsquo;&lt;br /&gt;&lt;br /&gt;
&amp;ldquo;You just call a special primitive or something from your program.&amp;ldquo;&lt;br /&gt;&lt;br /&gt;
&amp;lsquo;So if the language semantics can change over time, doesn't that imply that the meaning of a program can change over time as well?&amp;rsquo;&lt;br /&gt;&lt;hr /&gt;
Is Student A right?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-1638957445766099744?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/1638957445766099744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=1638957445766099744' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1638957445766099744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/1638957445766099744'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/another-wacky-idea.html' title='Another wacky idea'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3476896318157080018</id><published>2010-04-14T08:11:00.000-07:00</published><updated>2010-04-14T08:11:07.556-07:00</updated><title type='text'></title><content type='html'>Let me propose these thoughts:  a &amp;ldquo;semantics&amp;rdquo; is a way of associating meaning with programs.  A &amp;ldquo;formal semantics&amp;rdquo; uses well-known mathematical models in an attempt to be thorough, precise, and consistent.  An &amp;ldquo;informal semantics&amp;rdquo; uses human language, analogies, and examples in an attempt to be more concise and easier to understand.&lt;br /&gt;&lt;br /&gt;
As a programmer, you need to have &lt;em&gt;some&lt;/em&gt; idea of semantics in order to get anything done.  Even something as simple as the expression &lt;code&gt;x + 1&lt;/code&gt; presupposes that the symbol &lt;code&gt;+&lt;/code&gt; has something to do with addition, the symbol &lt;code&gt;1&lt;/code&gt; names a literal number, and the symbol &lt;code&gt;x&lt;/code&gt; names &lt;em&gt;something&lt;/em&gt; that can be understood numerically.  Your understanding doesn't have to be complete (how does that supposed addition handle overflow?), and it doesn't have to be correct (maybe &lt;code&gt;x&lt;/code&gt; is a string and &lt;code&gt;+&lt;/code&gt; performs concatenation), or even consistent, but you can't work with no understanding whatsoever.&lt;br /&gt;&lt;br /&gt;
Does that seem like a reasonable point of view?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3476896318157080018?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3476896318157080018/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3476896318157080018' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3476896318157080018'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3476896318157080018'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/let-me-propose-these-thoughts-is-way-of.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-3683304826687466779</id><published>2010-04-13T18:59:00.000-07:00</published><updated>2010-04-13T18:59:19.515-07:00</updated><title type='text'></title><content type='html'>It's clear that you don't need to fully understand the formal semantics of a language in order to program in it. (There are a lot of languages for which the formal semantics haven't been specified.)  How far could you get without knowing the &lt;em&gt;informal&lt;/em&gt; semantics?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-3683304826687466779?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/3683304826687466779/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=3683304826687466779' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3683304826687466779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/3683304826687466779'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/its-clear-that-you-dont-need-to-fully.html' title=''/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2414031244545167679</id><published>2010-04-12T17:51:00.000-07:00</published><updated>2010-04-12T17:51:42.473-07:00</updated><title type='text'>Student Z has another complaint</title><content type='html'>Student Z raises his hand in class.  He says &amp;ldquo;Ok, so I guess I see a reason to do something with code other than run it.  But I still think there's too much academic wankery in this field.  Look at all these discussions of &lt;em&gt;meaning&lt;/em&gt; and &lt;em&gt;semantics&lt;/em&gt;.  Who cares?  Your average hacker doesn't bother with semantics, he just wants to get the job done.&amp;rdquo;&lt;br /&gt;&lt;br /&gt;Well, obviously I'm setting up Student Z as a straw man, but how important are the semantics of a language?  Are they simply a curiosity for &amp;lsquo;language lawyers&amp;rsquo; and mathematicians to worry about, or are they a tool that is used daily by programmers?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2414031244545167679?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2414031244545167679/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2414031244545167679' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2414031244545167679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2414031244545167679'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/student-z-has-another-complaint.html' title='Student Z has another complaint'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-2120043293188815610</id><published>2010-04-10T13:00:00.000-07:00</published><updated>2010-04-10T13:00:23.770-07:00</updated><title type='text'>Improvements</title><content type='html'>Of course the next day after you upload something you find bugs.  If you go to &lt;a href="http://code.google.com/p/jrm-code-project/source/browse/#svn/trunk/PStore"&gt;http://code.google.com/p/jrm-code-project/source/browse/#svn/trunk/PStore&lt;/a&gt; you will find not only updated versions of the object-map and persistent tree code, but also a very primitive serializer and deserializer (using John Cowan's suggesting of &lt;code&gt;read&lt;/code&gt; and &lt;code&gt;write&lt;/code&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8288194986820249216-2120043293188815610?l=funcall.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://funcall.blogspot.com/feeds/2120043293188815610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8288194986820249216&amp;postID=2120043293188815610' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2120043293188815610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8288194986820249216/posts/default/2120043293188815610'/><link rel='alternate' type='text/html' href='http://funcall.blogspot.com/2010/04/improvements.html' title='Improvements'/><author><name>Jrm</name><uri>http://www.blogger.com/profile/03233353484280456977</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://1.bp.blogspot.com/-6IWzfuxReDo/Tl1IckHPXdI/AAAAAAAABh0/1XrGpKHEHFU/s220/my_image.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8288194986820249216.post-5332487047711040336</id><published>2010-04-09T12:06:00.000-07:00</published><updated>2010-04-09T12:06:04.360-07:00</updated><title type='text'>Some code</title><content type='html'>If you're following along with the persistent storage thread, you may want to take a look at
&lt;a href="http://code.google.com/p/jrm-code-project/source/
