Cons-Air (a.k.a. Lispers On A Plane) January 22nd, 2015
Patrick Stein

Before bed last night, I was trying to sort out in my head the lineage and historical inter-relations between BKNR, TBNL, HTML-TEMPLATES, CL-WHO, and Hunchentoot. When my alarm went off this morning, I was having a dream about the Lisp community.

In my dream, there were about 50 Lispers on a prison plane. It was pretty much a commercial 737, but all of the passengers were wearing prison jumpsuits and the plane would never land. We were all just on the plane. We refueled in flight. (The dream had nothing to say about how we restocked with food or emptied the septic tanks. *shrug*)

There was a cage around/over the last three rows of the left side of the plane. The door to the cage was not locked, but everyone knew that you were only allowed to go into the cage if Edi let you. Edi Weitz was the top dog in this prison. The only reason the rest of us were still alive is because Edi hadn’t seen a reason to have us taken care of yet.

Didier Verna was the only person who was allowed to approach the cage if Edi were in it.

There wasn’t much turbulence, but we were flying through a thunderstorm. This had Nick Levine sitting at a window seat, looking out over the wing, nervously bobbing back and forth, and sipping whiskey with ice from a plastic cup.

The storm had Zach Beane pacing back and forth in the aisle.

Cyrus Harmon was sitting doing a crossword puzzle from the in-flight magazines, giggling to himself about FarΓ©.

FarΓ© was standing near the front of the plane throwing little packets of peanuts at everyone. He wasn’t trying to hurt people with them, but he was delighting in watching them bounce of the heads of people who weren’t expecting them (especially the back of Zach’s head when he was fifteen or twenty rows away).

Robert Goldman was trying to get some sleep, but was unable to do so because of the lack of leg-room, the bright cabin lights, and all of the packets of peanuts careening past.

There were a number of other Lisp-folk in this dream. For some of them, I don’t recall exactly what they were up to. For a few, it would probably be impolitic of me to say. πŸ™‚

Code That Tells You Why November 13th, 2014
Patrick Stein

A 2006 article by Jeff Atwood titled Code Tells You How, Comments Tell You Why showed up on reddit/r/programming today.

It makes a good point. However, it got me thinking that for cases like the binary-search example in the article, it might be nice to see all of the alternatives in the code and easily be able to switch between them.

One way to accomplish this in Lisp is to abuse the #+ and #- reader macros:

(defun sum-i^2 (n)
  #+i-wanted-to-do-this
  (loop :for i :to n :summing (* i i))

  #+my-first-attempt-was-something-like-this
  (do ((i 0 (1+ i))
       (sum 0 (+ sum (* i i))))
      ((> i n) sum))

  #+but-i-could-not-do-that-because
  "Some people find a do-loop to hard to read
    (and 'too' too hard to spell, apparently)."


  #-now-i-know-better-and-can-do-this
  (/ (* n (1+ n) (1+ (+ n n)) 6))

This is less than ideal for a number of reasons, including: one needs to make sure to pick “feature” names that won’t actually ever get turned on, the sense of + and - seem backwards here, and switching to a different alternative requires editing two places.

Another Lisp alternative is to abuse the case form:

(defun sum-i^2 (n)
  (case :now-i-know-better-and-can-do-this
    (:i-wanted-to-do-this
     (loop :for i :to n :summing (* i i)))

    (:my-first-attempt-was-something-like-this
     (do ((i 0 (1+ i))
          (sum 0 (+ sum (* i i))))
         ((> i n) sum)))

    (:but-i-could-not-do-that-because
     "Some people find a do-loop to hard to read
    (and 'too' too hard to spell, apparently)."
)

    (:now-i-know-better-and-can-do-this
     (/ (* n (1+ n) (1+ (+ n n)) 6)))))

This is better. No one can doubt which alternative is in use. It is only one edit to switch which alternative is used. It still feels pretty hackish to me though.

One can clean it up a bit with some macrology.

(defmacro alternatives (&body clauses)
  (flet ((symbol-is-***-p (sym)
           (and (symbolp sym)
                (string= (symbol-name sym) "***")))
         (final-clause-p (clause)
           (when (listp clause)
             (destructuring-bind (tag &body body) clause
               (when (and (symbolp tag)
                          (member (symbol-name tag)
                                  '("***" "FINAL" "BLESSED")
                                  :test #'string=))
                 body)))))
    (anaphora:acond
      ((member-if #'symbol-is-***-p clauses)
       (let ((clause (first (rest anaphora:it))))
         `(progn
            ,@(rest clause))))

      ((find-if #'final-clause-p clauses)
       `(progn
          ,@(rest anaphora:it)))

      ((last clauses)
       `(prog
          ,@(rest (first anaphora:it)))))))

With this macro, one can now rewrite the sum-i^2 function quite readably:

(defun sum-i^2 (n)
  (alternatives
    (i-wanted-to-do-this
     (loop :for i :to n :summing (* i i)))

    (my-first-attempt-was-something-like-this
     (do ((i 0 (1+ i))
          (sum 0 (+ sum (* i i))))
         ((> i n) sum)))

    (but-i-could-not-do-that-because
     "Some people find a do-loop to hard to read
    (and 'too' too hard to spell, apparently)."
)

    (now-i-know-better-and-can-do-this
     (/ (* n (1+ n) (1+ (+ n n)) 6)))))

If I wanted to try the my-first-attempt-was-something-like-this clause, I could stick a *** before that clause or change its name to *** or final or blessed, or I could move that clause into the last spot.

There is still an onus on the developer to chose useful alternative names. In most production code, one wants to clean out all of the dead code. On the other hand, during development or for more interactive code bodies, one might prefer to be able to see the exact “How” that goes with the “Why” and easily be able to swap between them.

(Above macro coming in well-documented library form, hopefully this weekend.)

Clozure Common Lisp on the Raspberry Pi April 8th, 2014
Patrick Stein

I finally ordered a Raspberry Pi last week. It arrived yesterday. Last night, I installed the Raspbian (Debian for Raspberry Pi) distro. Then, I followed Rainer Joswig’s excellent instructions on how to get Clozure Common Lisp running on the Raspberry Pi.

The only think that I would add to Rainer’s presentation is that Raspbian didn’t come with m4(1) out of the box, but it is needed when you make all to rebuild Clozure.

Hacks and glory await!

Also, Linux pro-tip: If you are thinking of renaming your only account on the machine, make sure you add the new name to a group with sudo privileges and make sure you get both /etc/passwd and /etc/shadow in the same sudo.

Edit: Rainer correctly points out that his article does say you will need to install m4 if you haven’t already. I just missed it.

Ranked Choice Voting Visualization November 9th, 2013
Patrick Stein

There were 35 candidates registered for the Minneapolis mayoral race this year. Minneapolis approved ranked-choice voting in 2006. I have great respect and deep sympathy for those who had to tabulate all of those votes. And, because there is no FEC-certified software for counting this type of vote, it was a huge human effort.

The Minnesota Secretary of State’s website has information about which candidates where eliminated in which of the 33 elimination rounds in the tabulation. I scraped the data from their Excel spreadsheet, added some Vecto, and put together some worm-trail charts. I couldn’t quite use Zach’s wormtrails library because I wanted to show how an eliminated candidates votes were redistributed (to other candidates who were lower-ranked choices or to the exhausted bucket). Also, note: the tabulated data on the Minnesota Secretary of State’s website is insufficient to form an accurate proportioning in rounds when multiple candidates are eliminated. In those cases, I just assumed that all candidates whose votes were redistributed were redistributed in the same proportions to the candidates who gained votes because of the eliminations in that round.

About 450 lines of Lisp code later, I came up with images like the one below (click to see it at full-size):
Minneapolis Mayoral 2013 RCV rounds 22 through 33

The white worm-trail through the center is the exhausted pile. Unfortunately, the eliminated candidates in the first 25 or so rounds had so few votes that I’d have to render these images wall-sized for you to get any idea what proportion of their votes went where. In the final few rounds, you can see some detail even with a semi-reasonable file size. I suppose I should see if I can wrangle the data from the St. Paul race which only had six candidates (and thus fewer than six rounds of counting).

Here is the chart broken up into three sections to make it a bit more manageable:
Minneapolis Mayoral 2013 RCV rounds 1 through 11 Minneapolis Mayoral 2013 RCV rounds 11 through 22 Minneapolis Mayoral 2013 RCV rounds 22 through 33

Here is a link to all rounds in one big file. And, here is the source code: rcv.lisp.

Note for Lisp folks: I don’t like the above code. I like short functions, but I also like using flet or labels to make functions that are still within lexical scope of a whole mess of variables. Anyone else come to a good resolution between those two things? Is bundling data in structs and classes really the right thing or a sea of global specials?

Lisp-style Generic Functions in Javascript October 28th, 2013
Patrick Stein

I have been spending some time over at codewars.com. It is an interactive platform where you can train on Javascript, Coffeescript, or Ruby exercises. The other participants in the site add their own exercises.

I just added an exercise to implement Lisp-style Generic Functions (including the standard method combinations) in Javascript. I’m pretty happy with the way my code came out.

var append = defgeneric('append');
append.defmethod('Array,Array', function (a,b) { return a.concat(b); });
append.defmethod('*,Array', function (a,b) { return [a].concat(b); });
append.defmethod('Array,*', function (a,b) { return a.concat([b]); });

append([1,2],[3,4]); // => [1,2,3,4]
append(1,[2,3,4]);   // => [1,2,3,4]
append([1,2,3],4);   // => [1,2,3,4]
append(1,2,3,4);     // => throws "No method found for append with args: number,number,number,number

Here’s a link directly to the exercise, but if you register for the site with this link, I get bonus points.

l