<?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-18469865</id><updated>2011-04-21T19:32:06.390-07:00</updated><title type='text'>Scott's Blog</title><subtitle type='html'>Lisp, wine-making, knitting, writing, emacs, programming languages, politics, and rants.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18469865.post-116093959669033568</id><published>2006-10-15T12:10:00.000-07:00</published><updated>2006-10-15T12:13:16.700-07:00</updated><title type='text'>Dingbat</title><content type='html'>Chris is studying for the GRE today and we're testing each other's vocabulary. This definition for dingbat is by far my favorite today:
&lt;blockquote&gt;1. An eccentric or silly person; 2. An ornimental piece of type for borders, seperators, etc; 3. An object (as a brick) serving as a missile.&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-116093959669033568?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/116093959669033568/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=116093959669033568' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/116093959669033568'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/116093959669033568'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/10/dingbat.html' title='Dingbat'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-116076274607825314</id><published>2006-10-13T09:53:00.000-07:00</published><updated>2006-10-13T14:16:59.680-07:00</updated><title type='text'>Finding a job sucks. Or: on exposing your trackers to the world</title><content type='html'>Finding a job sucks. One thing that drives me crazy is when you go to a career fair for your university and you &lt;span style="font-style: italic;"&gt;physically hand a recruiter your resume&lt;/span&gt;. They look it over and say "Wow! You look really qualified, we'd love to interview you!" You nod in satisfaction, having spent days polishing your resume. "But," says the recruiter, "we'd like you to go online to your campus's Career Services website and submit your resume through them to us; and then, would you go ahead and visit our corporate website and use our lame-ass resume tracker too?" Honestly, what's the point of giving the recruiters your resume if they're just going to shred it and ask for two electronic copies?&lt;p&gt;

I wouldn't mind visiting corporate website X Y and Z to submit my resume if that's all their resume trackers wanted me to do. But that &lt;span style="font-style: italic;"&gt;isn't what a resume tracker is for&lt;/span&gt;. Resume trackers provide a company three things: a way to keep track of applicants, a bar to entry, and a way to avoid paying something with a brain to weed through the pile of resumes, discarding the obviously incompetent. What I truly resent is having to rewrite my resume for every single company I apply for. Every company has its own unique take on what a resume should be; every company just &lt;span style="font-style: italic;"&gt;knows&lt;/span&gt; the One True Resume Format. And it's your responsibility as an applicant to take the work of art that is your resume and compromise its integrity and eye-catching uniqueness in order to shoehorn it into the bland, uniform, generic Corporate Resume Form.&lt;/p&gt;&lt;p&gt;

Okay, I get it: you're a big company and you've got thousands of hungry developers scratching at your door and you'd like a little bar to entry. Well, here's a hint. Think about exactly who you're barring. You're not barring the desperate underqualified morons with Gud Tiping Skills. They have nothing else to do but rewrite their resumes over and over, targeting with mindnumbing persistence every company they can think of. You're definitely discouraging creative programmers who find repetitive tasks disgusting. Your Generic Corporate Resume form doesn't provide the creative programmer a way to express all the neat projects he's worked on. And if you think letting your own applicants tell you how experienced they are in the limited number of skill fields you allow them to enter will produce accurate profiles of characteristically hard to qualify skills, you're just fooling yourself. Yes, resume trackers are a bar to entry, but it's &lt;span style="font-style: italic;"&gt;the wrong bar to entry.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;

Okay, I get it: you're a big company and your HR department of 40 needs a way to track the state of 40,000 applications. I'm no stranger to that problem. My honors fraternity usually has two people in charge of handling all the requests for new membership. They aren't paid, they're in school, and they handle collectively about 150 new contacts each semester. These new contacts are the brightest crayons in the box, the top kids in their class, and by far the most discerning applicants. We don't want to drop the ball with them. I built our fraternity a recruiting tracker to keep track of who applied, when they applied, their statistics, which events they've attended, and any number of other things we would otherwise have to keep track of with paper. HR departments have these trackers as well.&lt;/p&gt;&lt;p&gt;

When my honors fraternity wants new members, we ask our campus's registrar to send a note to students with a certain GPA who have a certain number of credit hours. Companies do this too: they send messages through my university's career services website, through my department chair, and through advertisements on campus. The result of this kind of direct advertising is a landslide response. Our honors fraternity recruitment begins with an info session, followed by two weeks of events open to the public before Pinning, the official start of the initiation period---a six-week long introduction to the fraternity before Induction, when the initiates become members. Companies do this too: you attend an info session, you interview, and you get hired.&lt;/p&gt;&lt;p&gt;

The big difference is how we handle our recruitment trackers. When I wrote the recruitment tracker for my fraternity, I explicitly did NOT allow anyone besides the two officers who handle new applicants to use the tracker. Everyone else needs to ask them for information if they want it. Applicants never ever see the recruitment tracker. We don't want them to! The president and recruitment advisor, the two officers responsible for handling applicants, respond to every single application by email and make the changes to the recruitment tracker themselves.&lt;/p&gt;&lt;p&gt;

"Inefficient!" you say, "Why not have a link in your advertising and have your applicants do it themselves?" Two very good reasons: integrity and respect. We don't want our applicants interacting with the recruitment tracker because we want to make sure the tracker has high data integrity. This internal tool is a great time saver for us, but it's worthless if it contains crap for data. The tool is inherently limited in what it accepts for input and what functions it can perform. If an outstanding applicant doesn't fit the mould, I fix the tracker or we flag the applicant and make annotations to the tracker entry. If an applicant hasn't provided enough information, the president or the rush advisor personally gets in touch with the applicant to get the required information. "Inefficient!" you say, "Why not use form validation and get all the information in one fell swoop?" Because it's not &lt;span style="font-style: italic;"&gt;just&lt;/span&gt; about data integrity, it's also about respect for our applicants. We want them to know we care about them. Our fraternity isn't going to be just another name on their resume, it's going to be a big part of their life. Every interaction we have with them tells us more about them and tells them more about us.&lt;/p&gt;&lt;p&gt;

Companies that don't interact with their applicants are missing worlds of information about their prospective employees! Not only do they avoid personal contact with these applicants, who may eventually become their co-workers, supervisors, or underlings; not only do they risk polluting their precious tracking databases with crappy data; but they also turn off the creative people they want to reach in the first place. Your HR people are extremely intelligent and quite adept at discerning the bullshit from the real. Much more so than any computerized filter could ever be.
&lt;/p&gt;&lt;h4&gt;The best of the best, the worst of the worst&lt;/h4&gt;All ranting aside, I wanted to share my application experience for the hopeful benefit of humankind.
&lt;ul&gt;&lt;li&gt;Google. You don't even need to wonder. I've never seen Google's recruitment tracker, but I have no doubt it's brilliant. Every interaction I've had with them has been through email with their extremely competent and respectful recruiters. These guys are the best of the best.&lt;/li&gt;&lt;li&gt;Sun. Sure, I had to deal with their tracker, but it let me upload my own resume in PDF format. It didn't ask me to enter my experience as a form field. They didn't ask a bunch of questions that a non-moron would answer with their resume. If you're going to have a tracker, do it like Sun.&lt;/li&gt;&lt;li&gt;Micron. Aside from having a nice looking website anyway, their tracker uses AJAX for a much smoother experience. Kudos to &lt;a href="http://www.taleo.com"&gt;Taleo&lt;/a&gt;. If you're going to use an off-the-shelf product, use these guys. The first page on the tracker asks you to upload your resume, transcript, any other helpful documentation. That's the way to do it. They ask you some form questions about your name, your institute of higher education (a pretty safe field to add to a form---there's pretty much only one way to report this, unlike your employment history and your skillset). They ask broad questions about where you'd like to work. That's it---end of story. Very much one of the best trackers I've seen.&lt;/li&gt;&lt;li&gt;Agilent. This may be one of the poorest trackers I've seen. You can't upload your resume, but you CAN paste a text copy of it. For those of us who don't use word processors but prefer to generate our resumes from XML or LaTeX, this is a big pain in the ass. Oh, but you &lt;span style="font-style: italic;"&gt;can&lt;/span&gt; use the resume generator, which asks you a bunch of questions and produces a generic resume in text format for you. At least they don't force you to enter your work history in a series of forms. It's not really Agilent's fault, they just chose &lt;a href="http://www.apply2jobs.com/corporate/index.cfm"&gt;crappy tracking software&lt;/a&gt;. Agilent, go get Taleo.&lt;/li&gt;&lt;/ul&gt;These are just a few of the many places I'm applying to. Many are worse, some are better. None are better than Google, though.
&lt;h4&gt;Common Resume Interchange&lt;/h4&gt;In a world constantly spouting mumbo-jumbo about service connectivity and integration, you'd think the hiring process would be seeing some of this. But it hasn't. Most employers ask the same basic questions: who are you, where can we reach you, and why should we care. I call on the leaders of HR companies to produce an XML specification for resumes. If you don't want to excite your applying developers' gag reflex even further, your product had better allow for the following:
&lt;ul&gt;&lt;li&gt;Be open and not restrictive about the format and content of employment history and skills. There's no objective way to quantify your skills, and your employment history (especially for the self-employed or you built your own company) is going to be very difficult to fit into someone else's idea of what your employment history should be.&lt;/li&gt;&lt;li&gt;Understand that the CRI is about metadata, not a &lt;span style="font-style: italic;"&gt;replacement&lt;/span&gt; for a resume. It's fine if you want me to extract important metadata from my resume so you can get to it faster. I really don't mind. But the CRI will never replace a resume.&lt;/li&gt;&lt;li&gt;Build a plugin for Word. I don't use Word and I'd prefer never to have to. But if you want CRI to be useful, you should give away a Word plugin that can annotate your word documents with CRI data.&lt;/li&gt;&lt;li&gt;For God's sake, don't overengineer it! Don't build another XSL spec, don't build another GEDCOM spec. It doesn't need to be that complicated. And make sure you document the spec well enough.&lt;/li&gt;&lt;li&gt;If your client company can't be bothered to look at resumes individually, then your product should use natural language processing techniques to attempt to extract useful information from freeform resumes translated into text format. Yeah, it's a hard problem; your clients would be better off just paying a brain to look through the resumes. But don't succumb to the urge to put this problem in your applicant's lap, or you'll find that your tracker product reduces the quality of your clients' new hires. Talk about solving the wrong problem.
&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/18469865-116076274607825314?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/116076274607825314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=116076274607825314' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/116076274607825314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/116076274607825314'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/10/finding-job-sucks-or-on-exposing-your.html' title='Finding a job sucks. Or: on exposing your trackers to the world'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115976988444749540</id><published>2006-10-01T23:05:00.000-07:00</published><updated>2006-10-01T23:18:04.463-07:00</updated><title type='text'>Carbonleaf and Matt Nathanson at the Aggie</title><content type='html'>I discovered I love Carbonleaf! Perhaps despite the Aggie Theatre, which seems to be completely incapable of decent sound balance. Matt Nathanson's band sounded muddy; the accoustic guitar and the vocals were barely audible over the bass! The Fox Theater did a much job when I saw Steven Kellog and the 6ers last Thursday, and when I last saw Matt Nathanson two years ago. Carbonleaf must be really awesome when the sound technician is decent.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115976988444749540?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115976988444749540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115976988444749540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115976988444749540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115976988444749540'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/10/carbonleaf-and-matt-nathanson-at-aggie.html' title='Carbonleaf and Matt Nathanson at the Aggie'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115812813688331956</id><published>2006-09-12T23:06:00.000-07:00</published><updated>2006-09-12T23:15:55.316-07:00</updated><title type='text'>Busy Beaver hunter up and running!</title><content type='html'>A hastily-written python program hums quietly away on four different machines, patiently guessing solutions to the 5-node busy beaver problem. Hooray!! If I'd been thinking properly, I'd have written it in scheme and used gambit to compile it... the algorithm I'm using uses constant memory, but is quite greedy in terms of computation time, so every little bit of speed counts.&lt;p&gt;After about half an hour of running, one of the processes has found a machine that produces 12 marks after 61 cycles!&lt;p&gt;It would help prune down the search space enormously if I could prove there were equivalent turing machines out there that had non-isomorphic state graphs; especially if the result allowed us to prune down the possible labels for the edges of the state graph! That's where the really terrible performance comes from...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115812813688331956?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115812813688331956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115812813688331956' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115812813688331956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115812813688331956'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/09/busy-beaver-hunter-up-and-running.html' title='Busy Beaver hunter up and running!'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115804840748858883</id><published>2006-09-12T00:55:00.000-07:00</published><updated>2006-09-12T01:06:47.500-07:00</updated><title type='text'>The potency of configurations</title><content type='html'>As a fun question to try to answer related to Turing machines... let &lt;i&gt;C&lt;sub&gt;n&lt;/sub&gt;&lt;/i&gt; represent the set of all Turing templates of &lt;i&gt;n&lt;/i&gt; states, as defined in the last post. Let &lt;i&gt;P(c)&lt;/i&gt; represent the &lt;i&gt;potency&lt;/i&gt; of configuration &lt;i&gt;c&amp;isin;C&lt;sub&gt;n&lt;/sub&gt;&lt;/i&gt;, defined to be the mean productivity of all the Turing machines &lt;i&gt;t&amp;isin;c&lt;/i&gt;.&lt;br&gt;&lt;b&gt;The question:&lt;/b&gt; What's the distribution of &lt;i&gt;P(c)&lt;/i&gt;?
&lt;h3&gt;Why it matters...&lt;/h3&gt;If &lt;i&gt;P(c)&lt;/i&gt; has a Gaussian distribution with a fairly tight standard deviation, then the potency function is a useful heuristic that could be used to drive an A* search through C&lt;sub&gt;n&lt;/sub&gt;. A few samples of &lt;i&gt;t&amp;isin;c&lt;/i&gt; could establish whether &lt;i&gt;c&lt;/i&gt; is worth examining.&lt;p&gt;It's not likely to be the case though, given that two machines in &lt;i&gt;c&lt;/i&gt; could behave completely differently. This suggests looking for a different similarity metric between machines.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115804840748858883?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115804840748858883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115804840748858883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115804840748858883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115804840748858883'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/09/potency-of-configurations.html' title='The potency of configurations'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115804756665306454</id><published>2006-09-11T21:28:00.000-07:00</published><updated>2006-09-12T00:52:46.750-07:00</updated><title type='text'>Hunting beavers: exhaustive generation without isomorphism</title><content type='html'>In the previous post, I decided to narrow my brute-force search for the 5-node Busy Beaver down to a smaller number of 5-node machines that at least stood a fair chance of halting and used all 5 states. I haven't proved this simplification doesn't exclude the Busy Beaver machine, but I have a strong intuition it doesn't.

&lt;h3&gt;The graph-theoretic reformulation&lt;/h3&gt;To make the search tractable, we're going to represent the busy beaver Turing machine with a graph. There are two symbols in the alphabet of the Turing machine, so each node in the graph representing a Turing machine "state" should have two outgoing edges. To guarantee that the machine at least contains a HALT instruction, add another node "E" representing the HALT instruction, and stipulate that there must be a path between the start node "S" and the HALT state "E".

&lt;b&gt;The situation:&lt;/b&gt; Suppose we have a directed graph of &lt;i&gt;n&lt;/i&gt; nodes that allows loops and self-loops. Two nodes are distinguished: S and E. There must be a path from every node but E to E. All the nodes but E have two outgoing edges; E must have none.

&lt;b&gt;The question:&lt;/b&gt; How many non-isomorphic graphs of this form are there?

&lt;b&gt;The answer:&lt;/b&gt; 6&lt;sup&gt;5&lt;/sup&gt; = 7,776 graphs. Few enough to be tractable!

&lt;h4&gt;Ugly details&lt;/h4&gt;Where did the magic 6&lt;sup&gt;5&lt;/sup&gt; come from? A chain from S to E must exist, so start there. We can additionally ensure that every node has a path to E by having the chain from S to E run through every node:&lt;table style="float: right;"&gt;
 &lt;caption&gt;The "backbone" of the isomorphism guarantees at least one HALT instruction and gives the machine a chance at reaching it&lt;/caption&gt;
   &lt;tbody&gt;&lt;tr&gt;
       &lt;td&gt;S&lt;/td&gt;&lt;td&gt;→&lt;/td&gt;
       &lt;td&gt;2&lt;/td&gt;&lt;td&gt;→&lt;/td&gt;
       &lt;td&gt;3&lt;/td&gt;&lt;td&gt;→&lt;/td&gt;
       &lt;td&gt;…&lt;/td&gt;&lt;td&gt;→&lt;/td&gt;
       &lt;td&gt;&lt;i&gt;n&lt;/i&gt;&lt;/td&gt;&lt;td&gt;→&lt;/td&gt;
       &lt;td&gt;E&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td&gt;↓&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;↓&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;↓&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;
&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;↓&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;↓&lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
       &lt;td&gt;?&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;?&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;?&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;
&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;?&lt;/td&gt;&lt;td&gt;
&lt;/td&gt;
       &lt;td&gt;?&lt;/td&gt;
   &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
That takes care of half the edges. The other &lt;i&gt;n&lt;/i&gt; edges each choose one of the &lt;i&gt;n+1&lt;/i&gt; nodes independently, for a total of &lt;i&gt;(n+1)&lt;sup&gt;n&lt;/sup&gt;&lt;/i&gt; possibilities.

&lt;h3&gt;Applying the results&lt;/h3&gt;For each distinct graph found above, a number of machines can be generated by annotating the edges. For example, an annotation "1:1L" means "if I read a one, write a one, move the head left, and transition the Turing machine to the state at the end of this line." There are 2×4×4 = 32 possible annotation sets for each node, putting the solution space at 32&lt;sup&gt;&lt;i&gt;n&lt;/i&gt;&lt;/sup&gt;(n+1)&lt;sup&gt;n&lt;/sup&gt;; a whopping 6&lt;sup&gt;5&lt;/sup&gt;32&lt;sup&gt;5&lt;/sup&gt; (that's a 26-digit number in decimal!). Still too big to brute force, but still much smaller than the unrestricted solution space of (2n)&lt;sup&gt;8n&lt;/sup&gt; (10&lt;sup&gt;40&lt;/sup&gt;). The restrictions tighten the solution space by roughly 14 orders of magnitude for the n=5 case.

Given that the constraints enforce the presence of at least one HALT, and the use of the entire 5 states of the machine, it's easy to see why the stochastic method over the unrestricted state space fails to find answers. The chances of hitting on one of the machines that fits the constraints is roughly 1 to 10&lt;sup&gt;14&lt;/sup&gt; against; given that the constraint machines aren't guaranteed to halt makes this statistic even more abysmal.

Note that this approach &lt;i&gt;still&lt;/i&gt; overgenerates. It's easy to see if both outgoing edges of a node lead to the same node that there are only 16 possible labels for the node's edges.

The graph approach looks promising. Possibly there are further sensible constraints that would reduce the number of potential non-isomorphic graphs&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115804756665306454?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115804756665306454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115804756665306454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115804756665306454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115804756665306454'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/09/hunting-beavers-exhaustive-generation.html' title='Hunting beavers: exhaustive generation without isomorphism'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115760290642482372</id><published>2006-09-06T20:02:00.000-07:00</published><updated>2006-09-06T22:00:36.656-07:00</updated><title type='text'>Busy Beaver</title><content type='html'>&lt;i&gt;Note: This article is in progress. The assignment is due Wednesday the 13th, so you can count on it being done sometime around then!&lt;/i&gt;
&lt;p&gt;This problem comes to us by way of Tibor Radó's 1962 paper on the Busy Beaver function. A brief formulation goes like this: Suppose you define the &lt;i&gt;productivity&lt;/i&gt; of a Turing machine with &lt;i&gt;n&lt;/i&gt; states as the number of 1's written to the Turing machine's tape after it successfully halts. Represent the productivity as a function &lt;i&gt;p(n)&lt;/i&gt;. Call the machine with &lt;i&gt;n&lt;/i&gt; states that maximizes &lt;i&gt;p(n)&lt;/i&gt; the &lt;i&gt;Busy Beaver Machine&lt;/i&gt;. Radó proved that no Turing machine can compute the value of &lt;i&gt;p(n)&lt;/i&gt;&lt;sup&gt;&lt;a href="#foot1"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;&lt;p&gt;Our primary interest in the problem is to find the Busy Beaver Machine for &lt;i&gt;n=5&lt;/i&gt; in order to win a contest for class: who can write the 5-state Turing machine that halts and writes the most ones to an initially blank tape?&lt;/p&gt;

For an intuition about the magnitudes involved in this problem, previous research turns up the current leader in the &lt;i&gt;n=5&lt;/i&gt; case at &lt;a href="http://www.logique.jussieu.fr/~michel/ha.html#tm52"&gt;Pascal Michel's page&lt;/a&gt;. This particular machine (found in 1989 by  Heiner Marxen and Jürgen Buntrock) produces 4,098 marks before halting after 47,176,870 steps.

&lt;h3&gt;Formalizing the problem a bit&lt;/h3&gt;&lt;p&gt;The Busy Beaver problem, being a subset of Turing literature, requires a bit further definition. Our Turing machine has the following form:
&lt;table border="1"&gt;
 &lt;tbody&gt;&lt;tr&gt;
   &lt;td&gt;
&lt;/td&gt;
   &lt;td&gt;0&lt;/td&gt;
   &lt;td&gt;1&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
   &lt;td&gt;1&lt;/td&gt;
   &lt;td&gt;S&lt;sub&gt;new&lt;/sub&gt; D I&lt;sub&gt;new&lt;/sub&gt;&lt;/td&gt;
   &lt;td&gt;…&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;&amp;hellip;&lt;/td&gt;&lt;/tr&gt;
 &lt;tr&gt;&lt;td&gt;&lt;i&gt;n&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

The instructions arranged into rows corresponding to the states of the Turing machine, and into columns based on the contents of the cell at the tape's current location. The instruction cell consists of three components: what to write at the current location, which way to move the tape, and what state to transition to next.

&lt;/p&gt;&lt;h3&gt;First approach: the stochastic method&lt;/h3&gt;
The stochastic method builds random Turing machines and tests them. Because the &lt;i&gt;Halting Problem&lt;/i&gt; is also not solvable, we run the Turing machine for an arbitrary amount of time and stop the machine if it hasn't stopped itself by then.

The stochastic method is a rather naive method. Since it's not an exhaustive search of the state space, it's not possible to determine whether &lt;i&gt;p(5)&lt;/i&gt; has been maximized or not. The best we can do is run the stochastic machine builder, keeping track of the most performant candidates, until we run out of time for the contest.

It's important to understand the size of the search space. Suppose we examine each cell in the 2×&lt;i&gt;n&lt;/i&gt; table individually and assign it an instruction. We choose S&lt;sub&gt;new&lt;/sub&gt;, D, and G independently for each instruction, giving 2×2×5 = 20 different operating instructions. Add to that the halt instruction and the total is 21 instructions, for a total of 10&lt;sup&gt;21&lt;/sup&gt; combinations!

If the stochastic method finds any solution at all, it's by sheer luck. My python process has been running several hours, and the best it's come up with is 5-state Turing machine that produces 1 mark on the tape and halts. Obviously, even a human can do better than this!

&lt;h3&gt;Intuitions about behavior may improve our chances&lt;/h3&gt;

&lt;h4&gt;Intuition 1: Avoiding Isomorphisms&lt;/h4&gt;

The intuition here is that much of the state space is populated by clones—that is, equivalent Turing machines. Any machine &lt;i&gt;M'&lt;/i&gt; which is equivalent to the halting machine &lt;i&gt;M&lt;/i&gt; also halts and additionally produces the same number of marks on the tape. If a brute-force method could avoid generating all the isomorphisms of a halting machine, the state space to be searched might be significantly reduced.

This approach, done without care, may produce a crippling effect on memory usage as each halting machine is stored so the algorithm can avoid producing its isomorphisms. Additionally, if the generator randomly generates new machines and then attempts to prove to itself whether it's an isomorphism of a known machine is likely to be more costly than simply running the machines themselves.

What's needed is an algorithm for enumerating the non-isomorphic machines with &lt;i&gt;n&lt;/i&gt; states that doesn't involve storing history.

&lt;h4&gt;Intuition 2: Graph Theory&lt;/h4&gt;
Enter graph theory. By reformulating the question in terms of graph theory, we can take advantage of the powerful methods and proofs already developed in this domain. To simplify the machine representation, let's only examine the potential instruction sequences instead of the entire machine. Let's build a directed graph of the states. We'll represent the special HALT instruction as an extra node, giving n + 1 nodes to the state graph. We'll represent state transitions with colored edges to indicate that the state transitions are not fungible.

First, some obvious observations on the necessary nature of this graph. The state graph should be connected, with no islands. By this I mean from any node it should be possible to reach the halt node. Otherwise the machine has effectively fewer than &lt;i&gt;n&lt;/i&gt; states, and it's been proven that &lt;i&gt;p(n) &gt; p(n')&lt;/i&gt; where &lt;i&gt;n &gt; n'&lt;/i&gt;. This constraint guarantees that it is at least plausible that the machine will eventually reach the special halt node. Additionally, this helps the machine avoid some obvious infinite loops—for example, a state where both outgoing edges lead back to itself. The graph may be cyclic without necessarily causing the machine to run forever—the state graph doesn't encompass enough information to determine this (and in fact this is a good thing---we're hoping by simplifying the problem we can make it tractable. We already know the problem is not directly soluble, we're just trying to find a practical approximation).

Fixing the state graph is a big win. For a given n-state graph, there are now only O(n&lt;sup&gt;2&lt;/sup&gt;) machines (in reality, this number is slightly smaller—at least one of the instructions is the halt instruction, which has no second component). The next question in combinatorial analysis is: how many non-isomorphic, connected graphs of n+1 nodes, where n of the nodes have two distinct outgoing edges, and the special halt node has no outgoing edges?

Finally, the last question is: how do we generate these graphs?

&lt;h4&gt;Intuition &lt;i&gt;n&lt;/i&gt;: The optimal number of HALTs&lt;/h4&gt;
The question of how many HALT instructions to include in the machine is intuitively related to the bridge-crossing question. Look at it this way: we must start at state 0, and to get the best of the machine we should try to use every state possible.

In some cases, this is an even number of crossings, in some cases, an odd number. This affects the number of HALT instructions that need to be available (or does it? After all, we're not restricted to crossing a bridge only once—we're restricted to only crossing bridges that exist. That is, we can't modify the machine after it starts running).

This most likely will turn out to be a false intuition.

&lt;hr /&gt;
&lt;a name="foot1"&gt;&lt;/a&gt;1. &lt;a href="http://plato.stanford.edu/entries/turing-machine/"&gt;http://plato.stanford.edu/entries/turing-machine/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115760290642482372?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115760290642482372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115760290642482372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115760290642482372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115760290642482372'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/09/busy-beaver.html' title='Busy Beaver'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115708679247930800</id><published>2006-08-31T21:24:00.000-07:00</published><updated>2006-08-31T21:59:52.533-07:00</updated><title type='text'>My Christine</title><content type='html'>ὠ ἡ χρίστη, χριστίν, ἡ καρδίᾱς ἐμῆς φύλαξ· ἐμή φιλίᾱ σοί.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115708679247930800?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115708679247930800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115708679247930800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115708679247930800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115708679247930800'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/my-christine.html' title='My Christine'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115657533733009753</id><published>2006-08-25T23:51:00.000-07:00</published><updated>2006-08-25T23:55:37.343-07:00</updated><title type='text'>Moved In-ness!</title><content type='html'>I'm &lt;i&gt;finally&lt;/i&gt; moved in! Well most of the way. Got a TV and DVD player from Elizabeth for &amp;lt;intonation type="salesman"&amp;gt;cheap cheap cheap&amp;lt;/intonation&amp;gt; but nowhere really to hook it up. Not that I particularly watch TV anyway, but it might be nice to catch the odd episode of SNL, or tune into those important emergency system tests!

With the last of the peaches going bad, it's time for a food-drying experiment. We'll see how dried peaches turn out. Hopefully they'll make a delightful addition to the bread pudding I'm making tomorrow from all the crusty French bread around here. Which it turns out is something I actually like&amp;hellip; between the two of us, Chris and I can almost consume an entire loaf in one sitting, leaving just about a quarter left. Perfect for bread pudding.

Now if I could only manage to find time to clean up this mess...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115657533733009753?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115657533733009753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115657533733009753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115657533733009753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115657533733009753'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/moved-in-ness.html' title='Moved In-ness!'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115614121394214252</id><published>2006-08-20T23:19:00.000-07:00</published><updated>2006-08-20T23:20:13.953-07:00</updated><title type='text'>Jumping cow amber ale (++)</title><content type='html'>Yum yum! Light, wih just enough body...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115614121394214252?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115614121394214252/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115614121394214252' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115614121394214252'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115614121394214252'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/jumping-cow-amber-ale.html' title='Jumping cow amber ale (++)'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115613972861542743</id><published>2006-08-20T22:53:00.000-07:00</published><updated>2006-08-20T22:55:28.616-07:00</updated><title type='text'>One thing I'd change about python</title><content type='html'>I think python is a nice enough language, but the lack of proper lexical scoping drives me nuts! Also, the generator concept &lt;i&gt;almost&lt;/i&gt; works, but when you want to do a non-local yield, it's just not possible. For example, if your generator has a helper function that wants to yield, control flows back to your generator instead of to the code calling your generator!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115613972861542743?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115613972861542743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115613972861542743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613972861542743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613972861542743'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/one-thing-id-change-about-python.html' title='One thing I&apos;d change about python'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115613949545704539</id><published>2006-08-20T22:46:00.000-07:00</published><updated>2006-08-20T22:51:35.460-07:00</updated><title type='text'>Almost moved into my new apartment!</title><content type='html'>It's taking for freaking ever, but I'm almost moved in to my apartment! Serious amounts of material were omitted from this blog because I didn't have an internet connection or I was out of the state (maybe more on that later :o). Actually the biggest reason is I'm exceedingly lazy.

I picked up a cheap modem at CompUSA which amazingly enough worked in Linux. I tweaked my old server box a bit by installing dnsmasq for DHCP and DNS service and used it as a router, since the modem on my laptop isn't as linux-friendly. Works very well! Go gentoo again for having useful HOWTO material readily available (google gentoo home router).

My newest addition to my growing library is "The Scheme Language." It looks quite informative and hopefully will be helpful when I'm implementing my .net scheme compiler! Yeah that's right, even though they already exist, I really want the experience of implementing scheme and since I want to learn about .net, this is a natural combination. Let's hope I can get someone on the CU faculty to advise this project so I can substitute it for some boring core class.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115613949545704539?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115613949545704539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115613949545704539' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613949545704539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613949545704539'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/almost-moved-into-my-new-apartment.html' title='Almost moved into my new apartment!'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-115613919051448238</id><published>2006-08-20T22:43:00.000-07:00</published><updated>2006-09-06T08:48:55.056-07:00</updated><title type='text'>Autohighlight moves to a permanent home</title><content type='html'>After a lengthy stay in no-man's land, &lt;a href="http://trac.artesiancode.com/trac/autohighlight"&gt;Autohighlight&lt;/a&gt; finally has a home! As described on the home page, autohighlight is a project I worked on with another student in Spring 2006 whose purpose it was to automatically generate syntax description files for VIM and EMACS when given an input grammar in BNF form.

The project was a mixed success, when taken in light of the fact it was implemented in 2 months, and the problem of reducing a context-free language to regular expressions is inherently intractable!

Anyway, I hope someone gets use out of the code; it looks promising.

&lt;b&gt;Update:&lt;/b&gt; The url is really &lt;a href="http://trac.artesiancode.com/trac/autohighlight"&gt;http://trac.artesiancode.com/trac/autohighlight&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-115613919051448238?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/115613919051448238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=115613919051448238' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613919051448238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/115613919051448238'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/08/autohighlight-moves-to-permanent-home.html' title='Autohighlight moves to a permanent home'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114819545859001805</id><published>2006-05-20T23:58:00.000-07:00</published><updated>2006-05-23T08:51:43.526-07:00</updated><title type='text'>Blogger stuff, and pictures and poems</title><content type='html'>&lt;p&gt;I apparently just now figured out how to get post titles to appear in the RSS feeds... apparently you have to add &lt;code&gt;class="post-title"&lt;/code&gt; to your title header…. Sucks to that! Apparently some people's post editors have a little place for TITLE, but not mine. Maybe its broken.&lt;/p&gt;&lt;p&gt;Today someone showed me how to upload pictures, so some of the more interesting ones should be forthcoming, perhaps with some meditative text about them.&lt;/p&gt;&lt;p&gt;In other news, another project is born: a photo essay of abandoned and decaying spaces in Boulder; I'm thinking I'll call it &lt;em&gt;Something there is that doesn't love a wall&lt;/em&gt;, in homage to Robert Frost's poem &lt;a href="http://www.writing.upenn.edu/%7Eafilreis/88/frost-mending.html"&gt;The Mending Wall&lt;/a&gt;:&lt;/p&gt;&lt;blockquote&gt;Something there is that doesn't love a wall,&lt;br&gt;
That sends the frozen-ground-swell under it,&lt;br&gt;
And spills the upper boulders in the sun,&lt;br&gt;
And makes gaps even two can pass abreast.&lt;br&gt;
…&lt;br&gt;
Something there is that doesn't love a wall,&lt;br&gt;
That wants it down.' I could say 'Elves' to him,&lt;br&gt;
But it's not elves exactly, and I'd rather&lt;br&gt;
He said it for himself. I see him there&lt;br&gt;
Bringing a stone grasped firmly by the top&lt;br&gt;
In each hand, like an old-stone savage armed.&lt;br&gt;
He moves in darkness as it seems to me—&lt;br&gt;
Not of woods only and the shade of trees.&lt;br&gt;
He will not go behind his father's saying,&lt;br&gt;
And he likes having thought of it so well&lt;br&gt;
He says again, "Good fences make good neighbors."&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114819545859001805?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114819545859001805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114819545859001805' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114819545859001805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114819545859001805'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/05/blogger-stuff-and-pictures-and-poems.html' title='Blogger stuff, and pictures and poems'/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114805755560083945</id><published>2006-05-19T09:49:00.000-07:00</published><updated>2006-05-21T00:12:02.663-07:00</updated><title type='text'></title><content type='html'>&lt;h3 class="post-title"&gt;Surviving Identity Theft&lt;/h3&gt;&lt;p&gt;God forbid it should ever happen to one of us, but if it did, here's a post on &lt;a href="http://www.theconsumerist.com/"&gt;the consumerist&lt;/a&gt; that gives you a &lt;a href="http://www.consumerist.com/consumer/top/how-to-get-through-having-your-identity-stolen-171194.php"&gt;Step -by-step HOWTO for dealing with a stolen identity&lt;/a&gt;. Very useful stuff brought to you by the security guru &lt;a href="http://www.schneier.com/blog/archives/2006/05/how_to_get_thro.html"&gt;Bruce Schneier&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114805755560083945?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114805755560083945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114805755560083945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114805755560083945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114805755560083945'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/05/surviving-identity-theftgod-forbid-it.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114791076198052834</id><published>2006-05-17T17:03:00.000-07:00</published><updated>2006-05-21T00:12:34.403-07:00</updated><title type='text'></title><content type='html'>&lt;h3 class="post-title"&gt;Reason and the facts beat Intelligent Design &lt;i&gt;again&lt;/i&gt;&lt;/h3&gt;&lt;p&gt;Check out &lt;a href="http://www.pamd.uscourts.gov/kitzmiller/kitzmiller_342.pdf"&gt;this ruling&lt;/a&gt; handed down in the Middle District court of Pennsylvania! Of course, with all the money behind the ID machine, it'll probably be appealed for a long time. In the mean time, rejoice in the truth! ID is a doggle, to quote the old man in Life of Brian.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114791076198052834?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114791076198052834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114791076198052834' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114791076198052834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114791076198052834'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/05/reason-and-facts-beat-intelligent.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114791028137209907</id><published>2006-05-17T16:56:00.000-07:00</published><updated>2006-05-21T00:13:05.676-07:00</updated><title type='text'></title><content type='html'>&lt;h3 class="post-title"&gt;Chris gets a blog!&lt;/h3&gt;&lt;p&gt;Well not quite a blog, but a &lt;a href="http://starpow971.livejournal.com/"&gt;livejournal&lt;/a&gt;... and hey, it offers RSS syndication, awesome!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114791028137209907?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114791028137209907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114791028137209907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114791028137209907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114791028137209907'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/05/chris-gets-blogwell-not-quite-blog-but.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114782236658011932</id><published>2006-05-16T16:30:00.000-07:00</published><updated>2006-05-21T00:13:33.840-07:00</updated><title type='text'></title><content type='html'>&lt;h3 class="post-title"&gt;A Sonnet&lt;/h3&gt;&lt;p&gt;Terror of the birdbath, she&lt;br /&gt;In stalking quiet solitude&lt;br /&gt;Approacheth near the feather-swarm&lt;br /&gt;As birds erupt in hectic flurry&lt;br /&gt;from branch and feeder where they stood.&lt;br /&gt;Kitten smiles amid the storm.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114782236658011932?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114782236658011932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114782236658011932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114782236658011932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114782236658011932'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/05/sonnetterror-of-birdbath-shein.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114520356763075273</id><published>2006-04-16T09:04:00.000-07:00</published><updated>2006-05-21T00:14:06.703-07:00</updated><title type='text'></title><content type='html'>&lt;h3 class="post-title"&gt;Mervyns to become shopper heaven&lt;/h3&gt;&lt;p&gt;KINGDOM OF HEAVEN - In a press conference Tuesday, God declared, "Only the elect shall get into Mervyns." Mervyns, until recently a retail fixture of malls the country over, will be repurposed as a heaven for good consumers. An angel discussing the decision on condition of anonymity noted, "Since Mervyns, God rest its soul, has departed the earth forever and ever, really the only way to get into Mervins is to be among one of the elect," which are 13,000 in number and pre-chosen before birth by the Lord God Himself. "No amount of righteousness can cause Him to send to Mervins someone who was not elected at birth; but a single failure by one of the elect to heed His holy command could result in an instant loss of the promise of everlasting peace in Mervyns."&lt;/p&gt;&lt;p&gt;Experts in holy affairs speculate that the move may be intended as a test to the children of God. "Will they be good consumers?" Asks the Reverend Al Jameston, "Or will God's command to buy, buy, buy go unheeded?" He added, "the fate of the shopper's soul hangs in the balance by a perilous thread, suspended between unending damnation in the fiery pits of Hell and the paradise of Mervyns."&lt;/p&gt;&lt;p&gt;Rev. Jameston was unwilling to reveal his sources, but claimed to have it on good authority that there would be a second coming of Mervyns. "It is written by the hand of God Himself that when the final hour be reached, the celestial Mervyns will descend again to earth to bring shopping bargains and high-quality clothing to all," he said. The time of the second coming would be marked with plagues of frothy mochas and consumer savings cards, a strange disappearance of funds in bank accounts, and hip designer fashions returning mysteriously to Earth.&lt;/p&gt;&lt;p&gt;God, King of Kings and Lord of hosts, ruler of heaven and earth, in infinite wisdom abiding, could not be reached for further comment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114520356763075273?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114520356763075273/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114520356763075273' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114520356763075273'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114520356763075273'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/04/mervyns-to-become-shopper.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114339159500824312</id><published>2006-03-26T08:33:00.000-08:00</published><updated>2006-03-26T08:47:14.900-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;More unfinished musings&lt;/h1&gt;

So if a dispatch function/closure represents an object, then around-advice on the dispatch function is extending an object. Can a closure be cloned using primitives in Scheme? If so, then closures + aspect-oriented programming == prototype-based object system.

The downside to the closure object system is that code is not shared. For cases where the clone &lt;abbr title="directed acyclic graph"&gt;dag&lt;/abbr&gt; is deep (large with a small branching factor), not sharing code is a good thing. For cases where the clone dag is wide (large with a large branching factor), sharing code is a good thing.

How does one decide which slots will behave like class slots and which slots will behave like instance slots in the clone? Does the closure object necessarily &lt;i&gt;need&lt;/i&gt; the concept of a slot at all? It could all be defined in terms of reactions to messages, some of which appear to cause state changes in the object. How does &lt;a href="http://www.forcix.cx/software/prometheus.html"&gt;Prometheus&lt;/a&gt; handle this?

Speaking of, a &lt;i&gt;type&lt;/i&gt; could be defined either in terms of the clone dag, where children of a node are types; or type could be defined purely in terms of the interface supported by an object (if it looks like a duck, walks like a duck, quacks like a duck...).

What kind of type safety optimizations can be made in a prototype-based language? Is it reasonable to be able to freeze changes to the clone dag in order to optimize method dispatch and slot mutation? Can freezing easily be undone, allowing the developer to resume modifying the objects in the dag interactively?

Hmm...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114339159500824312?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114339159500824312/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114339159500824312' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114339159500824312'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114339159500824312'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/03/more-unfinished-musings-so-if-dispatch.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-114332004085568597</id><published>2006-03-25T12:35:00.000-08:00</published><updated>2006-03-25T12:54:00.986-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;Unfinished thoughts on object systems&lt;/h1&gt;
Prototype-based object systems, plus aspect-oriented programming, plus multiple dispatch generic functions... hmm...

The naive way to implement method dispatch and slot access in prototype-based object systems is to chain-up to the original object when a clone doesn't understand a message. This means potentially several indirections if the clone-chain is deep. Some language I saw recently claimed to be able to do single-dispatch method invocations using a maximum of three indirections.

Hygenic mix-ins require lexical closures. If you have a mix-in that modifies the behaviour of an object and requires keeping additional state, you need to be positive that your state-keeping slot doesn't clash with an existing slot.

It seems like method invocation could be called "resume environment", where the object represents an environment, that is, a set of bindings.

In the multiple-dispatch generic function case, method specializers are real, actual objects, specifying a node in the clone tree. All the progeny (objects created by cloning) of the specializer object are considered subclasses of the progeny.

Some support should be built programmatically for moving methods and slots around in the tree. This implies that methods are first-class objects. This is also necessary because adding advice to a function requires having access to the function object. This implies that behaviour is somehow external to objects, which seems to contradict the prototype-based system; unless some provision for "cloning" methods exists, and this sounds a lot like aspect-orientation: orthogonal extensions to behavior. What if they're not orthogonal, but more like behavioral mixins? You'd like to be able to replace, not just augment behavior.

It would be really nice to do this in scheme in 10 lines using closures.

What does a MOP look like for prototype-based object system?

Unfinishedness...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-114332004085568597?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/114332004085568597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=114332004085568597' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114332004085568597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/114332004085568597'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/03/unfinished-thoughts-on-object-systems.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113933637154337907</id><published>2006-02-07T10:17:00.000-08:00</published><updated>2006-02-07T19:26:58.126-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;Capturing a debugger backtrace&lt;/h1&gt;
In my web application, I want to capture backtraces automatically and continue with the top-level request-handler-response loop. Here's how I did it:
&lt;pre&gt;(with-output-to-string (s)
 (block nil
    (handler-bind ((t #'(lambda (condition)
                                (sys::print-backtrace :out s)
                                (fresh-line s)
                                (sys::pretty-print-condition condition s)
                                (return))))
       (error "foo"))))
=&gt; ".....[giant backtrace omitted]....."&lt;/pre&gt;
Pretty ugly. I need to do some work to get clisp to print only the relevant frames (ie none of the driver, and none of the frames before the handler-bind, which I don't really care about).

Pascal Bourguignon suggests a more elegant abstraction, which I have adopted for my own purposes (having the condition object responsible for the mess seemed useful).
&lt;pre&gt;(defmacro collecting-backtrace (&amp;body body)
  (let ((s (gensym)) (b (gensym)))
    `(block ,b
       (handler-bind
           ((t (lambda (condition)
                 (return-from ,b 
                   (values nil condition
                           #+clisp (with-output-to-string (,s)
                                     (sys::print-backtrace :out ,s)
                                     (fresh-line ,s)
                                     (sys::pretty-print-condition condition ,s))
                           #-clisp
                           (format nil
                             "I don't know how to generate a backtrace on ~A"
                             (lisp-implementation-type)))))))
         (values (multiple-value-list (progn ,@body)) nil)))))&lt;/pre&gt;
Much cleaner. I wonder whether the &lt;code&gt;t&lt;/code&gt; in the handler-bind should be customizable... Anyways, still haven't looked into limiting the verbosity and depth of the stack trace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113933637154337907?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113933637154337907/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113933637154337907' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113933637154337907'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113933637154337907'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/02/capturing-debugger-backtrace-in-my-web.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113917259928541589</id><published>2006-02-05T12:46:00.000-08:00</published><updated>2006-02-05T15:47:35.713-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;Finding nested ASDF components easily&lt;/h1&gt;
The problem that prompted this excursion is that I wanted to get at a specific file in another ASDF package, and I didn't particularly care to know where the package is installed. Here's how the code started
&lt;pre&gt;(asdf:find-component 
  (asdf:find-component 
    (asdf:find-component nil :cl-catalyst)
    "templates") 
  "error")&lt;/pre&gt;
There's a much easier way to do this kind of canonical component finding:
&lt;pre&gt;(reduce #'asdf:find-component 
        '(nil :cl-catalyst "templates" "error"))&lt;/pre&gt;
Neat!!! It almost reminds me of logical pathnames...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113917259928541589?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113917259928541589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113917259928541589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113917259928541589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113917259928541589'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/02/finding-nested-asdf-components-easily.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113883089269414067</id><published>2006-02-01T13:32:00.000-08:00</published><updated>2006-02-01T14:10:19.933-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;Using mod_rewrite to avoid seeing script names&lt;/h1&gt;
&lt;p&gt; It seemed like a pretty innocuous job... getting rid of the script name in the request &lt;code&gt;http://localhost/~scottw/puma3/&lt;b&gt;puma3.lisp&lt;/b&gt;/extra/path&lt;/code&gt;. But you wouldn't believe the pain it caused me! I record here the eventual solution (the inspiration is from &lt;a href="http://forum.textdrive.com/viewtopic.php?pid=75072"&gt;this&lt;/a&gt; post related to removing the &lt;code&gt;index.php&lt;/code&gt; from wiki urls). &lt;/p&gt;
&lt;p&gt;Suppose you have a script &lt;code&gt;~/web/script.cgi&lt;/code&gt;, which is ordinarily accessible from the web as &lt;code&gt;~user/script.cgi&lt;/code&gt;. You want to rewrite requests like &lt;code&gt;~user/&lt;i&gt;path&lt;/i&gt;&lt;/code&gt; into requests like &lt;code&gt;/~user/script.cgi/&lt;i&gt;path&lt;/i&gt;&lt;/code&gt;. The important piece being that the script sits in the same directory as your "virtual" &lt;i&gt;path&lt;/i&gt; filename. Because of this important fact, the following &lt;code&gt;~/web/.htaccess&lt;/code&gt; &lt;b&gt;will not work&lt;/b&gt;:
&lt;/p&gt;&lt;pre&gt;RewriteEngine On
RewriteBase /~user/
RewriteRule ^(.*)$ script.cgi/$1 [L]&lt;/pre&gt;
Even though you added &lt;code&gt;[L]&lt;/code&gt; to your rule, requesting &lt;code&gt;~user/anything&lt;/code&gt; will result in a 500 error. Looking at the apache logs, you'll see mod_rewrite complaining of too many internal rewrites. This is because your request is being rewritten over and over again like this:
&lt;pre&gt;anything -&gt; script.cgi/anything -&gt; script.cgi/script.cgi/anything&lt;/pre&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;This is where the magic happens. You only want the rewrite rule to run when the virtual path doesn't exist. Here's the correct and working solution:
&lt;/p&gt;&lt;pre&gt;RewriteEngine On
RewriteBase /~user/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ script.cgi/$1&lt;/pre&gt;
Now after the first rewrite, the request filename begins with script.cgi, so the condition isn't true and the rewrite isn't triggered.&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113883089269414067?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113883089269414067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113883089269414067' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113883089269414067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113883089269414067'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/02/using-modrewrite-to-avoid-seeing.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113834486130519647</id><published>2006-01-26T22:46:00.000-08:00</published><updated>2006-01-26T22:54:21.306-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;McCLIM and CLISP&lt;/h1&gt;
After several hours of trying, I successfully managed to load mcclim into a recent clisp. However, none of the demos are "working." By working, i mean, no errors are generated, but no output is really displayed. I'm trying to figure out how to debug the damned thing without really knowing much CLIM, but the more I learn, the more impressed I am with CLIM. I was especially impressed with the command object idea, having recently emerged from a software engineering class where we discussed the command pattern. It seems so natural in this context!

I'm eager to try my hand at CLIM development, I'd like especially to build a gdk/gtk+-2.0 backend. Even cooler, potentially, when gobject introspection turns from vapourware into software, would be to have the backend mapping happen dynamically! Lots left to learn about CLIM and gdk first... I have a feeling the first thing to do is to make a gdk backend that mirrors the CLX backend, and hook the GTK widgets in place higher in CLIM abstraction model once I know the gdk drawing stuff is going to produce correct if not beautiful output for CLIM applications that use the low-level drawing toolkit stuff. It's quite exciting! If one could get CLIM running atop gdk and gtk, it wouldn't be hard to deliver clisp applications for windows (especially with clisp's recently-acquired ability to build executable files for windows!).

I guess I'll start by tracing the crap out of the CLIM protocols to find out what's wrong with the CLX backend. I suspect it's a method combination or class precedence problem somewhere... I saw quite a few suspicious looking compilation errors on those topics. More later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113834486130519647?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113834486130519647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113834486130519647' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113834486130519647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113834486130519647'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/01/mcclim-and-clisp-after-several-hours.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113834434703984088</id><published>2006-01-26T22:44:00.000-08:00</published><updated>2006-01-26T22:45:47.053-08:00</updated><title type='text'></title><content type='html'>&lt;h1&gt;An update on clisp-sqlite&lt;/h1&gt;I packaged clisp-sqlite as an ASDF-installable package!! Go check it out &lt;a href="http://www.cliki.net/clisp-sqlite"&gt;here&lt;/a&gt;. More documentation and some examples should follow soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113834434703984088?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113834434703984088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113834434703984088' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113834434703984088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113834434703984088'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2006/01/update-on-clisp-sqlitei-packaged-clisp.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113400464099486170</id><published>2005-12-07T17:12:00.000-08:00</published><updated>2005-12-07T17:45:48.656-08:00</updated><title type='text'></title><content type='html'>I've been programming some mind-bending algorithms in Python lately, and was truly irritated to be unable to find a Python analogue for Common Lisp's TRACE macro. Specifically, TRACE like clisp's &lt;a href="http://clisp.cons.org/impnotes/environment-dict.html#trace"&gt;TRACE&lt;/a&gt;. So, I built my own.

This TRACE notifies you function invocations and returns, which makes it a lot more useful than the line-based TRACE &lt;a href="http://www.advogato.org/person/jamesh/diary.html?start=189"&gt;offered by Python&lt;/a&gt; itself. My trace implementation only works on methods, not functions, so it's a little limited. When you call funtrace on a method name, it replaces the method with a wrapper that prints the name of the method, its arguments, and then calls the method itself. When the method returns, it prints which method finished and the return values. Sometimes you don't want to print all the arguments (because one is a gigantic dict and fills the entire screen when printed), which is what the second argument of funtrace is for. If you set this argument to False, all arguments are suppressed. If you set it to a numerical value &lt;i&gt;n&lt;/i&gt;, only the first &lt;i&gt;n&lt;/i&gt; arguments to the function will be printed (useful if you pass the dict in last).

Each time a traced function is called, a global indent variable is incremented, and each time a traced function exits, the indent variable is decremented. If you print debugging statements using trprint, your output will be indented appropriately as well.

If you want things that look like function invocations, for example at the beginning and end of a block, you can use trenter and trleave, just remember to balance them or you'll get very strange results. Both of these simply print their argument and do the indent bookkeeping.

trace.py
&lt;pre&gt;
indent = 0

from sys import stdout
import sys

def trprint(*args):
    global indent
    sys.stdout.write(indent * "   ")
    sys.stdout.write(*args)
    sys.stdout.write("\n")

def trenter(name):
    global indent
    trprint("ENTERING %s:" % name)
    indent += 1

def trleave(name):
    global indent
    indent -= 1
    trprint("LEAVING %s." % name)

def trace(func, printArgs):
    def inner(*args):
        global indent
        if printArgs:
            trenter("%s%s" % (func.__name__, args[:printArgs]))
        else:
            trenter("%s(...)" % (func.__name__))
        rt = func(*args)
        if printArgs:
            trleave("%s%s = %s" % (func.__name__, args[:printArgs], rt))
        else:
            trleave("%s(...) = %s" % (func.__name__, rt))
        return rt
    return inner

def funtrace(func, printArgs):
    func.im_class.__dict__[func.__name__] = trace(func, printArgs)
    return func
&lt;/pre&gt;

example.py
&lt;pre&gt;
from trace import funtrace
from trace import trprint
class foo:
   def __str__(self): return "&lt;foo&gt;"
   def __repr__(self): return str(self)
   def bar(self, x):
     trprint("X = %s" % x)
     if x != 0:
        self.bar(x - 1)
     return x

funtrace(foo.bar, 3)
foo().bar(1)
&lt;/pre&gt;

This produces
&lt;pre&gt;
ENTERING bar(&lt;foo&gt;, 3)
   X = 3
   ENTERING bar(&lt;foo&gt;, 2)
     X = 2
     ENTERING bar(&lt;foo&gt;, 1)
       X = 1
       ENTERING bar(&lt;foo&gt;, 0)
         X = 0
       LEAVING bar(&lt;foo&gt;, 0) = 0
     LEAVING bar(&lt;foo&gt;, 1) = 1
   LEAVING bar(&lt;foo&gt;, 2) = 2
LEAVING bar(&lt;foo&gt;, 3) = 3
&lt;/pre&gt;

Quite useful!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113400464099486170?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113400464099486170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113400464099486170' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113400464099486170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113400464099486170'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/12/ive-been-programming-some-mind-bending.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113108818756824636</id><published>2005-11-03T23:00:00.000-08:00</published><updated>2005-11-03T23:09:47.570-08:00</updated><title type='text'></title><content type='html'>I've just started &lt;i&gt;The Mystery of Capital&lt;/i&gt;, by Hernando de Soto, and so far I don't think it's a bad read. I confess that I don't know much about economics, so it's sometimes disorienting. The premise is that formal property systems in developing nations exclude the poor, who hold the vast majority of assets in those nations. The poor have no access to the formal property systems, because the assets they own are owned illegally or because the legal system is too cumbersome to use. Lacking an entry into the formal property system, there is no way to use these assets for collateral. The statistics de Soto and his team use to illustrate the massive impediment to property ownership in developing nations is enlightening. My biggest question so far is whether the "formal property" argument can explain conditions in inner-city slums, and I suspect the answer is that inner-city slums in developed nations are caused by fundamentally different forces than shanty towns on the outskirts of a sprawling third-world metropolis. The author notes that land value in shanty towns is sometimes as high or higher than land in the legally-owned areas of town and going up, whereas land value in inner-city slums is wretched and deteriorating quickly. Hopefully more reading will clear up some of my economic confusion.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113108818756824636?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113108818756824636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113108818756824636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113108818756824636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113108818756824636'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/11/ive-just-started-mystery-of-capital-by.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113108663861969481</id><published>2005-11-03T22:22:00.000-08:00</published><updated>2005-11-03T22:58:56.000-08:00</updated><title type='text'></title><content type='html'>I'm releasing version 1.0 of my clisp SQLite bindings for SQLite 2.8. If you've never used SQLite before, it's an embeddable SQL (duh) database. Check out &lt;a href="http://www.sqlite.org"&gt;SQLite&lt;/a&gt;. You can download my clisp binding at &lt;a href="http://ucsub.colorado.edu/~williasr/sqlite-2.8-1.0.lisp"&gt;http://ucsub.colorado.edu/~williasr/sqlite-2.8-1.0.lisp&lt;/a&gt;. An ASDF/ASDF-Install-able version is Real Soon Now (tm).

The bindings offer two levels of support: a low-level binding which is directly tied to the FFI (package SQLITE.RAW) and a more friendly, lisp-like interface built atop it (package SQLITE). Here's a glimpse of how it works:

&lt;pre&gt;
[1]&gt; (use-package :sqlite)
=&gt; T
[2]&gt; (setf my-db (sqlite-open #"~/tmp/test.db"))
=&gt; #&amp;lt;SQLITE::DATABASE #P"/home/scottw/tmp/test.db" :OPEN&gt;
[3]&gt; (sql my-database "malformed sql")
*** - sql error 1: "near \"malformed\": syntax error. Offending query:
        "malformed sql"
Break 1 [4]&gt; :r1
[5]&gt; (sql my-database "create table bar (a, b)")
=&gt; NIL
[6]&gt; (sql my-database "insert into bar values (1, 2)")
=&gt; NIL
[7]&gt; (sql my-database "insert into bar values ('a', 'x')")
=&gt; NIL
[8]&gt; (sql my-database "select * from bar")
=&gt; (("1" "2") ("a" "x"))
[9]&gt; (sqlite-close my-database)
=&gt; #&amp;lt;SQLITE::DATABASE #P"/home/scottw/tmp/test.db" :CLOSED&gt;
[10]&gt; (with-open-db (db #"~/tmp/test.db")
        (with-query (db (a b) "select a, b from bar")
          (format nil "Processing a row with a=~s, b=~s.~%" a b)))
Processing a row with a="1", b="2".
Processing a row with a="a", b="x".
=&gt; T
&lt;/pre&gt;

So far as I've used it, I find &lt;code&gt;with-query&lt;/code&gt; to be one of the most efficient and useful of the sql forms supplied with the binding. I optimized it for relatively high throughput (though for some reason, clisp creates 3 strings for every column in the row, odd), so it's fast in tight loops where your lisp must process a lot of data (it can handle a million 3-column rows in less than a second on my machine). Since the body of with-query is executed once for each row as the row is returned, it avoids building up potentially large lists, the way the plain SQL call is likely to. I find this form so particularly useful because it binds the columns from each result row to the specified variables, making them much more accessible.

There are a few outstanding issues. The first is the lack of a with-transaction. Inserts into the database are much more efficient when wrapped in a transaction, but I haven't yet worked out how to wrap the body of with-transaction so that "rollback" is called if the body is left abnormally, and "commit" is called otherwise. I suspect some trickery with unwind-protect and catch is going to be necessary, though it's not obvious to me how to do it, so I'm delaying a while.

Next, I plan to explore the MOP by building a Class::DBI-style object mapper. CLSQL already does this, but a) it doesn't compile out of the box with clisp, and b) I want to make my own.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113108663861969481?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113108663861969481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113108663861969481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113108663861969481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113108663861969481'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/11/im-releasing-version-1.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113090848508084116</id><published>2005-11-01T21:06:00.000-08:00</published><updated>2005-11-01T21:15:00.980-08:00</updated><title type='text'></title><content type='html'>I got my copy of the Art of the Meta-Object Protocol in the mail today! Already it's more well-written and accessible than I could possibly have imagined, and is so far answering several questions in fields I hadn't related to the MOP (like how classical object models can be integrated with the generic object models used in CLOS, and how the MOP relates to the "essential difficulty" of software production).

Thinking over the essential difficulty of programming today and the most promising (though non-silver) bullets, I was trying to decide how Generators, Patterns, and metaprogramming are related to one another in the attack on the essence of difficulty in programming. I've been thinking a lot, especially about Paul Graham's assertion that "When I see patterns in my programs, I consider it a sign of trouble. The shape of a program should reflect only the problem it needs to solve. Any other regularity in the code is a sign, to me at least, that I'm using abstractions that aren't powerful enough-- often that I'm generating by hand the expansions of some macro that I need to write." Perhaps more stewing on this idea is necessary before coming to a conclusion, but I'm tempted to agree, and also to point out Graham's use of Generators (in the form of macros) to help him accomplish some metaprogramming (someone who deserves an attribution but whose name I can't remember once said that metaprogramming is the art of engineering the language upward to meet it's intended use).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113090848508084116?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113090848508084116/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113090848508084116' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113090848508084116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113090848508084116'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/11/i-got-my-copy-of-art-of-meta-object.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113090799245740800</id><published>2005-11-01T20:54:00.000-08:00</published><updated>2005-11-01T21:06:32.466-08:00</updated><title type='text'></title><content type='html'>Perl and Python, Lisp and TeX: Fundamental differences in user communities. I have a bias against Lisp and Tex documentation because I have always found it difficult to come by; hence I have always regarded these languages as poorly documented, even though I'm a fairly active and excited user of both. On the difference of availability of documentation, I think the origins of the languages are extremely important. Both Lisp and TeX have a rather more academic user group (not that they are any more capable than the Perl and Python crowd, but when you think practical programming, you think Perl, not TeX), whereas Perl and Python are grassroots efforts, so to speak. The very definition and elaboration of the languages themselves reflect this. If you want good documentation of TeX, buy the TeXbook, which I've heard is quite a rigorous bible of TeX. Consequently, anybody who owns the TeXbook is unlikely to be constantly publishing the little tidbits of information and procedure that float around. When I first began using LaTeX, I had a hell of a time finding any documentation for it, and now that I know exactly what to search for, I have a slightly less hard time, but by no means is it as easy as CPAN. The same is true with Lisp. The official common lisp spec has to be purchased from ANSI, and if you want to delve under the hood with the MOP, you're pretty much out of luck unless you buy the AMOP. Contrast this with the Python and Perl world: if you've been to CPAN, if you've read the perldocs, or browsed doc.python.org, you already know what I'm talking about. The TeX group has CTAN, which is similar to CPAN, and common lisp has cliki, which is also similar, but these two repositories are fundamentally different than CPAN—it's the documentation! The CTAN and cliki are &lt;span style="font-style: italic;"&gt;only&lt;/span&gt; (or at least mostly) code repositories. They allow for quick and easy downloading of code, but provide no support for the user.

I posit that it is exactly &lt;span style="font-style: italic;"&gt;because&lt;/span&gt; the languages Perl and Python grew up in the bright sun of public scruitiny that they are so well documented on the Internet. As single individuals attempt to document a language, they must surely fail to document all of it. The Internet responds by producing stacks of How-To articles that guide the novice user. In the more academic world, the novice is guided to a book. The book may be perfectly instructive, but the community dialog, that searchable collective experience, is not available. I think this accounts for a significant difference between the Perl and Python, Lisp and TeX crowds.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113090799245740800?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113090799245740800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113090799245740800' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113090799245740800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113090799245740800'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/11/perl-and-python-lisp-and-tex.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113082466963708024</id><published>2005-10-31T21:34:00.000-08:00</published><updated>2005-11-01T07:00:18.090-08:00</updated><title type='text'></title><content type='html'>An automatic syntax highlighter for EMACS and VI. I'm taking a compiler construction course at CU this semester and a friend and I have chosen to write a compiler that produces syntax highlighters for two popular editors based on the abstract syntax specification of the language. We're using Eli (see &lt;a href="http://eli-project.sf.net"&gt;Eli homepage&lt;/a&gt;). We spent last night wrangling with the AST, communally editing the AST spec using vim on screen. Nothing earth-shattering here, but it's what I'm working on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113082466963708024?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113082466963708024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113082466963708024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113082466963708024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113082466963708024'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/10/automatic-syntax-highlighter-for-emacs.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18469865.post-113071561352775972</id><published>2005-10-30T13:42:00.000-08:00</published><updated>2005-10-30T15:45:37.213-08:00</updated><title type='text'></title><content type='html'>For those of us who have never heard of a MetaObject Protocol, the MOP for CLOS is a bit puzzling. What exactly is it? It's a standard that allows you to customize and extend the common lisp object system. For example, if you want to map objects onto databases like Class::DBI in Perl, or you want object persistance like Java's Prevayler, the MOP is the lisp machinery that will allow you to do it.

Before one can delve into the dank cave of MOP, it helps to orient oneself a bit, and see how the CLOS is really put together. I'm using clisp, so if you run these examples in a different lisp, you may see different results. First, let's see what classes are made of.

[1]&gt; (defclass myclass () ((a :accessor mc-a)))
#&amp;lt;standard-class&gt;
[2]&gt; (class-of (make-instance 'myclass))
#&amp;lt;standard-class&gt;

There's nothing surprising about this. The class of a myclass object is #&lt;standard-class&gt;, just like we suspected. But here's something novel, classes in common lisp are first-class objects. What's the class of MyClass?

[3]&gt; (class-of (find-class 'myclass))
#&amp;lt;standard-class&gt;

Interesting. What this should tell you is that the class MyClass is an instance of the class Standard Class. Do not make the mistake of thinking that MyClass is a SUBCLASS of Standard-Class! This is emphatically NOT the case!

[4]&gt; (subtypep (find-class 'myclass) (find-class 'standard-class))
NIL ;
T

Compare this to

[5]&gt; (subtypep '(integer 0 2) 'integer)
T;
T

Which tells us that yes, the integer range from 0 to 2 is indeed a subtype of integers. So what's going on here? Why isn't MyClass a subclass of Standard-Class? In MOP parliance, Standard-Class is the metaclass of MyClass. You can do all sorts of wonderful and strange things using metaclasses, but let's hold off on that for a bit.

The next interesting thing to find out is that the slots of a class are themselves objects. Not just ordinary places that can be SETFed, but real, full-fledged objects of their own right, with inheritance, subtyping, and metaclasses of their own. Let's explore.

[6]&gt; (class-direct-slots (find-class 'myclass))
(#&amp;lt;standard-direct-slot-definition&gt;)

One may wonder at the awkward verbosity of MOP, it certainly can cause hand cramps. Why class-direct-slots and not class-slots? It so happens that class-slots already exists.

[7]&gt; (class-slots (find-class 'myclass))
(#&amp;lt;standard-effective-slot-definition&gt;)

What gives? There's an important distinction in MOP between direct slots and effective slots. Direct slots are the objects that are created when the slot is first created. For example, A is a direct-slot in myclass. The difference comes into play when inheritance happens: instead of inheriting the slot objects themselves, copying them straight into the subclass, the MOP allows one to combine the slot definitions for the superclass and the subclass. This makes a lot of sense when you consider what happens when you have (defclass MyOtherClass (MyClass) ((a :accessor moc-a))). Remember that slot A was once accessible using mc-a. What accessor should fetch the slot value of A in MyOtherClass objects? Should it be mc-a or moc-a? Using an effective-slot-definition, you can allow both.

To make this more real, let's have an example. Everyone who's used CLOS is aware that CLOS doesn't support encapsulation directly. Even if you supply no accessors for a slot, someone can always read and write the slot using slot-value. Since slot-value is a function, there's no way to override the behavior of slot-value using defmethod. But there is another way, using the MOP. Conceptually, slot-value is defined to call slot-value-using-class, which is a generic method. In many lisps, slot-value is optimized when slot-value is called on an object whose class has a metaclass of standard-class. So we'll need to make a metaclass in order to define a method that can intercept calls to slot-value-using-class.

[8]&gt; (defclass my-metaclass (standard-class) ((class-var :accessor mc-class-var :initarg :class-var)))
#&amp;lt;standard-class&gt;

We next need a class of metaclass My-Metaclass so we can make objects to call slot-value on.

[9]&gt; (defclass my-other-class () ((instance-var :accessor moc-instance-var :initarg :instance-var)) (:metaclass my-metaclass))
#&amp;lt;my-metaclass&gt;

Then we can specialize slot-value-using-class.
[10]&gt; (defmethod slot-value-using-class :before ((class my-metaclass) instance slot) (print 'fetching-slot-value))

Now, make an instance and get the slot's value.
[11]&gt; (setf inst (make-instance 'my-other-class :instance-var 'hello))
[12]&gt; (slot-value inst 'instance-var)
FETCHING-SLOT-VALUE
HELLO

This should instantly suggest several interesting things. For example, one could replace slot-value-using-class instead of wrapping it, and thereby get computed slots! This would be useful if your class represented a database table and the slots represented columns. Suppose you had a BLOB column that you didn't want to transfer unless it was requested. By wrapping slot-value-using-class, you could fetch the BLOB if it wasn't already present.

There are lots more interesting things you can do with the MOP. I'll get around to giving some more concrete and followable examples. Mostly, I wanted something to be online for googlers who had as much trouble learning about MOP as I did.&lt;/my-metaclass&gt;&lt;/standard-class&gt;&lt;/standard-effective-slot-definition&gt;&lt;/standard-direct-slot-definition&gt;&lt;/standard-class&gt;&lt;/standard-class&gt;&lt;/standard-class&gt;&lt;/standard-class&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18469865-113071561352775972?l=ortmage.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ortmage.blogspot.com/feeds/113071561352775972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18469865&amp;postID=113071561352775972' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113071561352775972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18469865/posts/default/113071561352775972'/><link rel='alternate' type='text/html' href='http://ortmage.blogspot.com/2005/10/for-those-of-us-who-have-never-heard.html' title=''/><author><name>Scott Williams</name><uri>http://www.blogger.com/profile/12056503582882971241</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
