Data as Procedures with No Data

Further to my post on data as procedures, I’ve translated to Common Lisp the implementation of cons, car and cdr as procedures with no data, not even numbers.

This comes from lecture 5b of the Structure and Interpretation of Computer Programs video series, with the necessary (funcall) adjustments for Common Lisp.

(defun my-cons (x y)
    (lambda (m) (funcall m x y)))

(defun my-car (x)
  (funcall x (lambda (a d) a)))

(defun my-cdr (x)
  (funcall x (lambda (a d) d)))

(print (my-car (my-cons 35 47)))
(print (my-cdr (my-cons 77 22)))

Output is:

35
22

Data as Procedures

I was watching lecture 2b of the SICP lectures and it shows an implementation of cons, car and cdr in Scheme as procedures. So I thought I’d write the equivalent in Common Lisp to test my understanding:

(defun my-cons (a b)
  #'(lambda (c)
      (cond ((= c 0) a)
            ((= c 1) b))))

(defun my-car (x) (funcall x 0))

(defun my-cdr (x) (funcall x 1))

(print (my-car (my-cons 'gold 'silver)))
(print (my-cdr (my-cons 'everything 'nothing)))

Output is:

$ clisp pairs.lisp

GOLD
NOTHING

Crazy. “Constructed out of thin air”, as Abelson says.

The scheme implementation is definitely nicer. See What Is Meant by Data? Scheme has only one namespace so there’s no need for the #' and funcall clutter.

Thresholding del.icio.us/popular

I really like delicious’ “popular” page and I particularly like that it is available as an RSS feed. But keeping up with it could really take over your life.

To get around this I’ve set up a “very popular” feed. To qualify an item has to be on the delicious popular page AND have 100+ recent votes. You can subscribe at:

http://bluebones.net/very-popular/rss/

If you want a different threshold just add ?threshold=n to the end of the URL where n is the number of votes a link has to have had to qualify.

High Level Data Structures

Design-heavy languages like Java try and convince us that what we want is an object model that represents every facet of the problem. But what we really want is to remain nimble and adaptable.

A lesson learned from both scripting and functional languages is that the best high level data structure is something lightweight. Perl’s hashes and arrays or Lisp’s lists. Even Python and Ruby’s objects are skinny.

This object or something like it replaces entire object models in seconds:

class Bag: pass

From PyAmazon.

or, with a bit more syntactic sugar:

class Storage:
    def __init__(self, initial=None):
        if initial:
            for k in initial.keys(): setattr(self, k, initial[k])
    
    def __getattr__(self, k): 
        if hasattr(self.__dict__, k) or (
          k.startswith('__') and k.endswith('__')): # special keyword
            return getattr(self.__dict__, k)
        raise AttributeError, repr(k)
    
    def __repr__(self): return ''

From web.py.

Better, you can create objects from your data store quickly and easily with no boilerplate required:

/**
 * Runs a SQL statement against the specified database and returns
 * the result.
 *
 * @param   $sql    SQL to run against database.
 * @param   $host   Host to attach to.
 * @param   $usr    Username for db.
 * @param   $pwd    Password for db.
 * @param   $db     MySQL database to attach to.
 * @return          true if insert/update succeeded, false on error,
 *                  array of associative arrays (rows) if select succeeded
 *                  (may have 0 entries if no rows to fetch).
 */
function db($sql, $db="bbdb", $host="localhost", $usr="root", 
        $pwd="rootpass") {
    mysql_connect($host, $usr, $pwd);
    @mysql_select_db($db) or die("Unable to select database: " . $db);
    $res = parse_result(mysql_query($sql));
    mysql_close();
    return $res;
}

/**
 * Parses the result of a SQL query and returns an appropriate var.
 *
 * @res             Result to parse.
 * @return          true if insert/update succeeded, false on error,
 *                  array of associative arrays (rows) if select succeeded
 *                  (may have 0 entries if no rows to fetch).
 */
function parse_result($res) {
    if (is_bool($res)) {
        return $res;
    }
    $arr = array();
    $i = 0;
    while ($row = mysql_fetch_array($res)) {
        $arr[$i++] = $row;
    }
    return $arr;
}

# Usage:
#
# $myobj = db("SELECT name, company FROM employee WHERE id = 12");
# print $myobj['name'] . " works for " . $myobj['company'];

You could argue that this couples the database and the program’s representation of data too closely. But for the spring in your step you get when coding, I think it’s a worthwhile trade off. This is approximately how Rails does things, but with a layer in between for exceptions where you can override the database.

Web Design Fashion

~1991

Tim Berners-Lee
“Tim Berners-Lee”: The first page on the web, academics putting up papers in default styles.

~1994

Under Construction
“My Home Page”: Clip Art, Animated GIFs, HTML, “Under Construction”, Guest Book.

~1997

Hotwired
“Webmonkey”: Inspired by Wired.

~2000

Google
“Google”: White is the new black, minimal.

~2003

404 Not Found
“Out of work”: Fallout from the dot.com collapse.

~2006

Odeo
“Web 2.0”: new optimism, new hype, please God just one more bubble (make your own)

To Do List

Remember the Milk is todo list software, much better than tadalist and all the other products I’ve looked at.

Some of the great features: free (as in beer), amazing usability, unlimited lists/reminders/entries, email/SMS/instant messenger reminders, atom feeds, keyboard shortcuts for everything, submit tasks via email, support for recurring tasks and tasks with a specific time (appointments) and many other features besides.

Tomcat 4.1 and Apache 2 on Ubuntu Linux

Short Version.

  • Install java (JDK not JRE). (Download binary from java.sun.com, add executable permission, run, move resulting directory to /usr/local or similar.)
  • Install apache2.
  • Get Tomcat binary from tomcat.apache.org and extract to /usr/local/
  • Set an environment variable CATALINA_HOME to the path of the directory into which you have installed Tomcat 4.0. And another JAVA_HOME to the path of the directory into which you have installed Java.
  • Execute the shell command: $CATALINA_HOME/bin/startup.sh
  • Check Tomcat works on port 8080
  • Install jk2 connector (sudo apt-get libapache2-mod-jk2)
  • Copy /usr/share/doc/libapache2-mod-jk2/examples/workers2.properties.minimal to /etc/apache2/workers2.properties adding in your own config
  • Uncomment line in /etc/apache2/mods-available/jk2.conf
  • Place your Tomcat-related code in CATALINA_HOME/webapps/ROOT or other appropriate directory. Restart everything.

Internet Commandline

yubnub.org is a commandline for the web. Better than that, it’s collaborative. This means you don’t need to create the command to subscribe to a feed at bloglines, it’s already been done (it’s called blub).

It’s like one shell shared by thousands so that every contribution can build on all the others. Like so much on the web it’s messy and somewhat fragile but it’s brilliant nonetheless. Check it out.

Accessing X Clipboard with Vim

You can access the X clipboard in Vim by using the ‘+’ buffer.

So to paste from your system clipboard into Vim use:

"+p

And to copy the current line to system clipboard use:

"+Y

On Ubuntu 5.10 (“Breezy Badger”) this only works (in both vim and gvim) once you have installed gvim:

sudo apt-get install gnome-vim

169.254.0.0 Address Causes Confusion

I got a very intriguing email yesterday. It read:

Mr Baker,

I wonder if you can throw any light on the fact that my virus killer has warned me that there is a new internet connection on my router.

The IP address is 169.254.0.0

As you are a computer programmer I would like you to explain to me how you came to get a web address through my router when it is securely firewalled and why you would wish to do so?.

On selecting the address I was sent to the Bluebones.net website.

Your IP address should not be anywher near my computer system and I wish to know from you why it is before making any further judgements or decisions on what to do about it. I should be glad if you would proffer an explanation as urgent.

For a moment I thought I must have some horrible virus that was using my machine to go out and infect others. Then I thought about it for a minute and I realised what must have happened.

169.254.0.0 is not a valid IP address. It is part of a block reserved by IANA for showing errors in getting DHCP addresses.

So the browser of my “victim” must have tried to visit 169.254.0.0, failed to find a machine on that address and automatically taken him to the top search result for “169.254.0.0” which must have just happened to be my post, ‘Network Client Assigned 169.154 Address

Mystery solved. Probably.