Fizzbuzz in SNOBOL4

Posted by Daniel Lyons Mon, 31 Dec 2007 18:06:00 GMT


**  FizzBuzz in SNOBOL4
**
**  Daniel Lyons <fusion@storytotell.org>
**
**  Yes, I am insane, before you ask.
**
**

        I = 1
LOOP    FIZZBUZZ = "" 
        EQ(REMDR(I, 3), 0)              :F(TRY_5)
        FIZZBUZZ = FIZZBUZZ "FIZZ" 
TRY_5   EQ(REMDR(I, 5), 0)              :F(DO_NUM)
        FIZZBUZZ = FIZZBUZZ "BUZZ"      
DO_NUM  IDENT(FIZZBUZZ, "")             :F(SHOW)
        FIZZBUZZ = I
SHOW    OUTPUT = FIZZBUZZ
        I = I + 1
        LE(I, 100)                      :S(LOOP)
END

Tags , ,  | 1 comment

Problem/Solution Space

Posted by Daniel Lyons Sat, 15 Dec 2007 11:09:00 GMT

Programming is different because you give people a problem and a solution at the same time.

Somehow, when someone comes to you with a programming task, you distill from that what exactly their problem is. Then you decide what the solution to the problem will be. Finally, you deliver to the customer two things: your conception of the problem they brought you and your concrete solution to that problem. (There’s usually a third product of this, which is either money or laughter depending on how badly you screw it up.)

There’s really two problems here. The customer is actually bringing you a universe with some flaws. They want a universe without these flaws. There are actually many universes without these flaws, so your first job as a programmer is to understand the customer’s reality.

Because programming begins and ends in concrete terms it’s easy to fall under the impression that it is concrete the whole time. Nothing could be further from the truth.

The set of perfect universes for this customer is quite large. Each one consists of a problem definition and a solution implementation. For example, someone may come to you with the problem that they have no money. They want to live in a universe in which they have money. One perfect universe is the one in which they panhandle for an hour and earn $3. Presto, they are no longer broke.

This definition of problem considers being broke to be a one-time state of being. There are other solutions to this problem with different attributes. For example, you could also go pick up aluminum cans for two weeks and take them to the recycling center to earn $50. $50 is more than $3, but two weeks is a lot longer than 1 hour. On the other hand, panhandling is degrading and picking up cans is just boring.

The solution isn’t the only thing that can vary. There are other ways of defining the problem. With a little common sense it’s easy to see that being broke is probably not a one-time event. Better solutions are probably found by designing the problem to account for this insight, but coming up with this insight isn’t something anyone has an algorithm for. The result of this insight, however, is a formal problem and a formal solution.

Additionally, the solution you hand over to the customer comes with another problem built-in. The customer imagines a world in which they have money, not a world in which they pick up aluminum cans or panhandle. However, the customer can’t come to you and just have wealth appear. They have to do some work to create new wealth.

As we imagine perfected universes, we are in the act of formalizing a problem and conceiving of a formal solution to that problem. This means dividing the problem into a metaphor, a formalized problem and selecting and then implementing a formalized solution.

The Incompleteness Theorem comes into it at the stage where you divide the solution into the part you solve for the user and the part the user solves for themselves. Another way of looking at this is, the amount of work the user has to do to utilize the perfection. You can balance this equation such that the user has to do no work; this is the complete solution with no expressiveness. I think this balance is probably a continuum on the incomplete side and a point on the complete side.

Elegance is that the problem and the solution are both as small as possible without becoming complete in the incompleteness theorem sense. Only the minimum of what is needed to define the problem and solve it to perfect this universe are included. Nothing extraneous.

The uncharted territory is problem definition itself. This is what computing science has taken for granted, because sorting and searching are intrinsic and easily defined problems that require interesting solutions that vary only by how. This is also why “real world” programming is such a hassle—most of your time is spent defining the problem/solution space rather than working on the solution.

Let’s work an example. The customer wants data management, so this is the problem/solution space. They bring you disks as the imperfect world. You define two concepts, “files” and “directories” and conceive of how they will work and build FAT. The two concepts consist of the problem you formalize and FAT is the formal solution. You’ve also given the customer the work of using files and directories in an appropriate fashion. That’s their problem; you’re done.

Same example again. The customer wants data management. I look to set theory, and then to relational theory. I conceive of “relations,” “tuples,” “tables,” “columns,” and “queries” from relational theory. I define a formal language, SQL. I implement a database, PostgreSQL. I’ve now increased the complexity on virtually every front, but I’ve also increased the expressiveness on the client’s side. He also has to do more up-front work, in that he must learn how to interact with the system via SQL. If we were being fair, he would weigh the time to learn SQL against the time to learn filesystems and the time he would spend implementing against a filesystem that he wouldn’t spend by having access to SQL and understanding it, but this seldom is the case.

Inappropriate abstractions are simply problem conceptions which increase the amount of work the customer has to do in the supposedly perfected universe with the formally defined problem and selected solution. It is more effort to deploy a program using CORBA in the backend than to deploy a program using a custom-written protocol, so the abstraction isn’t really an abstraction, it buys you nothing.

Powerful abstractions reduce the expressiveness by some factor but make the system more coherent. Drupal may consider arbitrary chunks of content uniquely addressable from anywhere, but this makes the management problem so bad the front-end doesn’t even bother. Voltaire is a better abstraction because removing sibling-to-sibling transclusions aren’t common enough to warrant a design that accommodates them. Voltaire simplifies the problem and the solution, and both are elegant and quite powerful.

Carter’s juxtapositional thinking/focussed attention dichotomy is just pointing out that programming begins with the act of creating a good problem formalism and that is an artistic act. It’s process to him. Fred Brooks is describing the design itself when he talks about conceptual coherence. If you have islands of meaningful features that don’t have a common substrate, you’re just pushing complexity from the flawed universe into the formal problem rather than the formal solution.

Dijkstra is arguing that both the problem and the solution need to be simple and elegant or neither will be comprehensible. And I tend to agree.

I need new nouns for these things.

Tags  | 1 comment

Drupal, Zope, and the Importance of Being Really Smart

Posted by Daniel Lyons Fri, 14 Dec 2007 06:50:00 GMT

In response to a -1 ranked remark I made on Reddit, there was a little controversy and I eventually wound up writing a somewhat longer comment which really should be here on my blog instead (and which I will move here if anyone complains about not being able to follow the link). It’s all mostly me complaining about Drupal but there is a kernel in there I want to dredge up, having to do with the importance of having really smart people.

mcantelon on Reddit said this: “If you spend some time in the dev list you’ll likely see quite clearly that Drupal has some very smart people behind it trying to improve it from many angles.” This reminds me of the same kind of crap I used to hear about Zope being written by geniuses who really grok object “technology” and are trying to solve these really hard problems for all time.

I want us all to take a deep breath and realize that there is absolutely no correlation between intelligence and quality of a program. None. And there are three reasons why I think this is so:

  1. Good programs are the concrete manifestation of good ideas, implemented correctly.
  2. Intelligent people often write bad programs.
  3. Good programs tend to be built on simple but elegant principles.

My objection to Drupal is that it is a horrid over-complex morass with no elegant concept. You cannot have a bad idea and implement it so well, everyone will love it. There is no perennial example of this because programs like this (like Drupal) tend to be around only for a few years and then everyone kind of snaps out of it. I guess you could say PL/1 is an example of this. Sometimes you come up with an idea for a solution to some problem and the idea is just plain stupid. CORBA is probably another more recent example of this. Nobody’s using it except people who have to for backwards compatibility. It was a good idea turned extremely stupid. (If you still want remote objects for delivered applications, you should check out Ice which removes a lot of the absurdities.)

On the second point, consider Microsoft. They try desperately to hire the best and brightest people and have for decades. While they were writing Vista, they were also writing C#. They do not lack the capability to bring a good idea to fruition. They are really bad at figuring out what is a good idea and what is not. And of course they have other problems.

Making a good program isn’t rocket science. On the contrary, it’s making something simple. Appparently making something simple is harder than making something complex. I stare in wonder and amazement at the capabilities of the amateur programmer who wrote one of my client’s systems. I just don’t understand how a human being could make something so complex and have it work. Of course it’s brutally unmaintainable. It’s not hard to look at a pile of specs and make a bunch of unrelated features. It’s hard to look at a pile of specs and say, what is this really about? What is the underlying universe that makes this problem complete?

A good programmer is not someone who can manage a thousand complex little exceptions. It’s someone who can unify them and remove them altogether with some commonality. That takes insight and aesthetics. Nobody has to be told that DHH is this incredible genius. You just watch the blog demo and ask yourself how everyone else could have been so stupid. That’s what elegance is about. It’s the opposite of the experience you have when you look at Drupal. You do wonder at the brilliance of the developers. You have to be brilliant just to understand it! You don’t have to be brilliant to use ActiveRecord. Elegant systems try and get out of your way. Egotistical systems have to get in your face in order to remind you how smart their inventors were.

What’s amazing about Lisp and Smalltalk is that the systems are so simple, one has the feeling they were discovered rather than invented. That’s elegance. Nobody will ever be surprised by something some Drupal plugin does. But every day people are surprised by the things they can accomplish with so little code in elegant systems like Lisp and Smalltalk.

Frankly, I found Zope to be tremendously insulting. To be told by the documentation that brilliant minds were behind it made me feel like an idiot for not understanding it. Apparently a lot of other people were struggling to learn and use Zope and also hurt by this marketing, and now they’re moving over to Django and Rails in droves, which do not try to insult you. There’s something disingenuous about saying a system is brilliant, just install a bunch of plugins and don’t ask too many questions about how it works. Again, with Lisp and Smalltalk, you can get everything from a paragraph or two of text and there’s nothing left to learn about how it works. Just a lot of time to really absorb and understand the ramifications. Small but extremely powerful versus large and well-stocked. You can’t evolve something from inelegant to elegant by stapling on more stuff. Stapling on more stuff being, incidentally, the only way programs can evolve.

Dijkstra pointed out something interesting in his Discipline in Thought video. Elegant software has the curious property of often being the most efficient. It seems obvious without thinking about it, but why should it be? Why should there be a correlation between elegance and speed? I’m not sure whether or not it’s harder to create elegant software, though it apparently requires up-front thought which makes it unacceptable to some programmers. Inelegant systems can improve but only so much. Elegant systems can go from being quite abysmal to being really excellent. It’s hard to read early Lisp code today, and early Lisp code deserved its reputation for being slow. Today it’s quite readable and substantially faster than the in-vogue languages, and often faster than C. PHP will never be much faster than it is today. It derives much of its speed from dirty tricks it should stop doing—earlier versions of it, which no doubt were faster, never freed memory, depending on the short lifetime of HTTP requests to manage that problem as a primitive form of garbage collection.

There’s nothing new about what I’m saying. I’m saying the same thing programmers from every generation have been saying going back to the 60’s. If you want to build good systems they have to be simple. If they’re not simple and elegant they’re going to be large and clunky and we won’t be able to understand them. Don’t trust any software that comes from someone who is trying to convince you they’re smart. If you want to worry about that, let the technology convince you.

Tags , ,  | no comments

A Summary Of Sorts

Posted by Daniel Lyons Mon, 10 Dec 2007 06:41:00 GMT

I want to enumerate a few things I’ve been thinking about, in no particular order, just to share them with you.

  • I want to encourage everyone to read Alan Carter’s essays, because I think this is extremely relevant to all programming, particularly his dichotomy between focussed attention and juxtapositional thinking and how the human brain and organizations build up around these concepts.
  • I am quite passionately studying Dijkstra and I am very interested in two of his concepts from On the Cruelty of Really Teaching Computing Science, namely the radical novelty and the follies of operational reasoning and anthropomorphism.
  • There are a number of dichotomies I’m interested in lately. One of them is false, the “software engineer” versus “programmer.” I am interested in whether or not the others are really the same relationship in different terms, or different aspects of the same relationship, or wholly separate. Namely, operational reasoning versus non-operational semantics (Dijkstra), focussed attention versus juxtapositional thinking (Carter), conceptual integrity (Brooks) versus local consistency (Carter), and generally simplicity versus elegance (nobody in particular).
  • I am also interested in a few neglected media, among which I include the blog entry. Quality over quantity. I think my writing, while better than average for a blog, isn’t very good for an essay, and I think it’s time I start collecting my thoughts more solidly so I don’t lose track of what I’m trying to say before I say it. I also think I have some interesting things to say about programming, finally.
  • For having such a poor liberal arts background, I am coming to see a literary appreciation for things as drastically underestimated. Code must be seen as linguistic expression, as literature. I believe, as of tonight, that I should also embark on a literary study of math. I think the way forward for me at this point is to learn more math, semantics and philosophy.

Once again I do not feel like I have gotten everything out but at least it is a starting place. I am thinking very seriously about going back through my blog posts and culling the good stuff for essay material. It’s becoming ridiculous to try and write an essay in one pass with no plan.

no comments

Simplicity and the GWT

Posted by Daniel Lyons Sat, 08 Dec 2007 23:48:00 GMT

“GWT 1.5, due in the first quarter of 2008, will produce “better” JavaScript code than manual programming by the industry’s best and brightest – in terms of speed, size and manageability of code. GWT 1.5 is also expected to improve compilation of Java code.” —Google’s next web toolkit thinks it’s better than you

Let’s try that claim again with some different technologies. “gcc will produce ‘better’ assembly code than manual programming by the industry’s best and brightest—in terms of speed, size and manageability of code.” The claim sounds pretty unlikely, don’t you think? How are you going to do better than manual human intelligence on all three fronts that matter? But something is missing. What language are we compiling from and to?

GWT is in the somewhat ironic position of compiling Java to JavaScript. By analogy, this is like saying you can compile from C to Lisp and produce better Lisp than experts could—in terms of speed, size and manageability. Does that seem likely? Then how, pray tell, could someone compile from a language that lacks full closures and prototyping OO to one that does, improving all three of those things at the same time? For that matter, when has compiled code ever been smaller than manually written code?

I don’t know anyone using GWT, because the only people who would use it would already be using Java and I don’t know anyone doing serious web development in Java. Web development is hard in a way that precludes clunky languages (but not stupid ones like PHP).

It reminds me of the other night when my room mate David Baird and I were talking about simplicity. To some idiots, MySQL is simpler than PostgreSQL. This claim is bizarre to me, since MySQL’s source is 10 MB larger compressed, MySQL deviates intentionally and insanely from the SQL standard, and MySQL includes a variety of obnoxious features that no true database would provide. Yet it is considered simple and “industry standard.”

Half of it is from The Rise of Worse is Better, MySQL chooses to make the implementation simpler than the interface, whereas PostgreSQL prizes the interface more. Why else would MySQL’s SQL syntax change with every release, while PostgreSQL’s remains the same? But this doesn’t explain the absurd notion of table types, which only MySQL has.

There is another dichotomy here, between differing conceptions of simplicity. Which of these is simpler?

sum = foldr (+) 0

Or:

int sum(list_t list) {
  sum = 0;
  for (cur = list; cur != NULL; cur = cur->next)
    sum += cur->value;
  return sum;
}

There are at least three different ways of looking at this:

  1. “You’re comparing apples to oranges! Unfair!”
  2. “The C version is simpler because it’s closer to what’s really happening.”
  3. “The Haskell version is simpler because it’s closest to the concept.”

People who fall under category one are the kind of people who say things like “it doesn’t matter what language you choose to implement something in, because they’re all Turing-complete.” It only doesn’t matter if the time it takes to write, the experience of writing it, the quantity and severity of the bugs introduced while writing it and the human resources required to write it don’t matter. I think a lot of people say this because they don’t want to get into a religious war about language—it’s a cop-out.

What I’m really interested in is what happens to people to make them fall under category 2 or 3. I think this quote from Alan G. Carter’s Why No-One’s Noticed This Before may be the essence of it:

“We don’t miss what we haven’t got, and this can lead to seeing things in profoundly different ways. A person who frequently does juxtapositional thinking is aware of the importance of self-consistency in their thinking. If something doesn’t “hang together”, they know they have made an error. Often they use self-consistency as the basis of their thinking, deducing that something must be missing, and then being able to find it. A person who is rarely if ever in a position to do juxtapositional thinking, will not consider or expect self-consistency in this way. Their view of reality is therefore fragmented. If they don’t require their understanding to hang together, they develop the idea of “mere facts”. What are facts? What do they prove? Nothing! Instead they use their focussed attention to concentrate on compliance with a proceduralism, and they don’t let mere facts get in the way. They certainly don’t trust their own good senses.”

Look again at PostgreSQL. It assumes that the database is there to alleviate certain burdens. It provides you with SQL. At that point, the database’s job is complete and it is up to you to learn SQL. Learning SQL may imply learning the theory of relational databases. PostgreSQL isn’t there to hold your hand and help you do this. If it takes you 30 minutes to write an SQL statement, well, that’s how long it takes you to write it. People in category 3 don’t mind, because they’d rather have one comprehensive solution for their data situation that hangs together.

Look at MySQL again. Table types aren’t part of data management, they’re a leaky abstraction, an exposure of low-level details. MySQL’s query planner also sucks compared to PostgreSQL’s. Perhaps most damningly, MySQL doesn’t support two of the three fundamental set operations (INTERSECT and MINUS/EXCEPT). If you were modeling a relational database on set theory, you probably would have started there.

Yet MySQL is full of tiny details meant to “helpfully simplify” some aspect of databases. Such as the TIMESTAMP type. There is no other type in MySQL which is defined as equivalent to some other type plus some behavior. There is no other type in MySQL defined so, nor in all of PostgreSQL, defined in terms of behavior (when you UPDATE a row with a TIMESTAMP column, the TIMESTAMP column receives the current time even if you didn’t specify that it should be modified). However, I haven’t ever seen someone intentionally use the TIMESTAMP feature for what it’s there for, just people stumbling onto it and realizing that a whole bunch of data they thought they had has actually been obliterated. It doesn’t hang together.

David and I concluded that there is a kind of simplicity which requires learning and a kind of simplicity which attempts to avoid it. Some people find the thought of recursion and higher-order functions a lot less simple than for loops. And yet, for loops become more sophisticated in mundane languages with each successive one.

There are people who find the REPL a horribly frightening place. Look at the complete lack of “noise” in the Haskell code. It’s nothing but you, G-d and the problem. There is no public static void main. There is a desire to be typing while programming, and in plenty of languages you have to push this edifice of text around before you can begin to get anything done. There is a sensation of programming when really you’re doing nothing. You can reason operationally and have the appearance of getting things done. Somebody wrote an API for making new table types in MySQL. I have no doubt this is far simpler than improving the query planner. Someone else contributed a BerkDB table type for MySQL. I have no doubt this was fairly simple. But why would you? This is problem avoidance, but adds so many megabytes to the source code, which nobody even actually uses. There is a digital artifact to this lack of interest in actually getting anything done.

People use ActiveRecord to avoid learning SQL and relational database theory. Yet, I know plenty of people who have not studied relational database theory but who understand it anyway. A lot of people start out making tables that aren’t normalized. After a while they start to use joins. Eventually they acquire the insights, usually after not very long, say a year or two, and then they are as good as someone who has studied it. After a while they begin to be annoyed with MySQL. ActiveRecord is there to make dealing with the database more like dealing with Ruby. As long as everything is in one language, it should hang together better. But of course, ActiveRecord is built for MySQL primarily, but with an eye to portability. The advanced database users grow annoyed at it because it also represents problem avoidance.

The GWT is a lot like ActiveRecord. It wants to mitigate some problem which isn’t, in reality, a problem. It’s a nightlight. When you look at my Rails code, you see a lot of me manually executing SQL. This practice is encouraged by the books and DHH and many other Rails users do this. However, it ties you to a particular database—PostgreSQL in my case. Is your database a problem, or a solved problem? GWT is saying JavaScript is a problem, do you think JavaScript is a problem?

I can certainly look at Ruby and SQL and say, both of these things are great. I have some trouble looking at JavaScript and turning in revulsion, asking for Java to come and mitigate the pain.

Tags , , , , , , ,  | 5 comments

CSS

Posted by Daniel Lyons Thu, 29 Nov 2007 06:50:00 GMT

The way most people format CSS is something like this:

css.selector {
  attribute-name: value;
  attribute-name: value;
}

I read somewhere, probably via Reddit, that a better way to do it is like this for readability purposes:

css.selector { attribute: value; }
other-css.selector { attribute: value; }

Today Josh suggested something a bit more radical: alphabetize them by selector. You arrive at something like this:


a { foo: bar}
a:hover { foo-bar: baz; bazzle-bat: foo; }

b { font-blah: blah; }

I liked this a lot, but I took it a little further. I indented the braces to line up, like this:


a       { foo: bar}
a:hover { foo-bar: baz; bazzle-bat: foo; }

b       { font-blah: blah; }

(For a bigger example, check out the CSS on my tumblog.)

Now, I like this for two reasons. One is that this really does make finding what you’re looking for a lot easier. But another, in my book better reason, is the statement this makes about CSS.

You would never organize a program’s functions alphabetically. You would never indent them all so the code is a big jumble on the right somewhere. This layout turns CSS into a selector rolodex with insanity on the right. And you know something? That’s exactly what CSS is: insanity, complete unmitigated chaos. The best we can do is label the roads. That’s what this layout does. It gives you trails that lead off into the wilderness. And you know something? It’s better.

So this morning when I read Brendan Eich’s The non-world non-wide non-web, I was already in a bad mood because, what has the W3C ever done for us? We’ve got XHTML, which is basically a dead letter. We have CSS, which is absurd. We have the whole XML toolchain. It’s hilarious to hear people slam Lisp and turn around and defend XML’s virtues. (I bet if you printed out the W3C’s paperwork on XML, you’d arrive at more than 1500 pages.) To learn SVG, one I thought I had liked, is also a pile of lies is just the icing on the cake.

Actually, it reveals how the W3C works quite clearly. Look at the commentary on Brendan’s page. A bunch of “invited experts” facing off with a Mozilla developer, scorning the WHATWG as the “WhatthefuckWG.” Granted, I have no idea what they’re about either, but still. Nobody expects programmers with decorum. “Invited experts,” on the other hand…

As time has gone on I have seen that there are fewer and fewer anonymous institutions that are really trustworthy in computing. Zope was a big disappointment, after boosting themselves (anonymously) as being the premier OOP wizards of the universe. W3C has pretended for some time to know everything about the internet and to have the experience and knowledge necessary to make things happen, ultimately culminating in two large fiascos (CSS and XML Schema). In the case of XML Schema, there was a better, simpler concept around which has gained some adoption, RelaxNG. The work mainly of one person.

I bring up Lisp alot because, lately, using it is such a joy. There are some features you’d look at and say, that’s a wart. One example is multiple return values. You have to use this obnoxiously long-named multiple-value-bind form to get at the additional return values past the first one. It’s tempting to look at that and say, why not just return a list?

Well, one reason you wouldn’t think of but might stumble into is because you now want to include some extra information in what’s returned by a function but you don’t want to change all of the call sites to wrap their call with car. You wouldn’t think about this kind of thing unless you were writing in a language in which you would find yourself swapping out functions piece-by-piece. It’s the opposite of Haskell, where you want the compiler to catch every little thing and force you to say exactly what you mean.

Yesterday I implemented pagination. I had already created a paginate function and was using it to clamp the number of results. Then I realized, due to the data structure I’m using (a list masked by a series scanner) I’m not going to want to get the length of things to decide whether or not I have another page. The easiest way to decide if I have another page is to paginate on one more item than I want and see if I get one more item than I want, and then omit that from the return value and return a boolean indicating whether there’s more. So I make the changes and drop in my function which now returns something else. None of my existing code died. Then I went through and changed my existing code, function by function, to utilize the flag I’m now returning. There were something like four call sites so it wasn’t a big deal.

If this were Java, I would have told you all about using the Refactor menu item in Eclipse, and how easy it was to change all my existing code and recompile it and run it and confirm that yes, it is working.

Now you could ask questions about the quality of the design. It would not have been hard, however, to make another function do the actual work and return a list of items and a value in a list and repackage it for the existing call-sites and mark it deprecated. I don’t think that design is any better though, so in this case evolution brought us to where we probably should have been. Assuming there isn’t a dramatically better design. And maybe (probably) there is.

End rant.

Tags , ,  | no comments

Lisp Tumblog: A Couple More Gross Insights

Posted by Daniel Lyons Tue, 27 Nov 2007 15:15:00 GMT

I have implemented paging using the SERIES macros, but now I have no idea how to implement the actual next/previous links. Well, the next link is really the one I’m worried about. :)

I rewrote the HTML template portion and so 2/5ths of the pages are now generated in a reasonably nice way. I would say there are now maybe a hundred or 150 lines of code I like in the program. I may have made a (possibly false) observation about the Lisp/Haskell dichotomy:

When you program Haskell, the program starts out beautiful and gets uglier and uglier as gets closer to completion. When you program Lisp, the program starts out ugly and gets more and more beautiful as you factor it into correctness.

We’ll see if it pans out as I finish implementing the tumblog.

Tags ,  | no comments

Weekend Program: Lisp Tumblog

Posted by Daniel Lyons Mon, 26 Nov 2007 18:16:00 GMT

Yesterday, I wrote a 250 line Lisp program to run my new tumblog. I have a few notes here I wanted to share about it. The next version will probably be open source; right now I can hardly stand to look at the code.

  1. Hunchentoot is very cool. The prefix and regex dispatcher functions are very handy. It was actually very easy to use, so easy it was almost counter-intuitive. I wonder why it took me so long to start actually building this program, since I’ve been thinking about it for so long.

    However, it doesn’t help you build an abstraction atop it. That’s your problem. So my URL handling is very ad-hoc and slimy, which is one reason pagination doesn’t work right now.

  2. CL-WHO is a mixed bag. On the one hand, it seems to be very efficient. On the other hand, it’s a bit hard to figure out how to build a template with it. It also can’t handle XML namespaces, which means my Atom feeds won’t validate due to missing XML namespace declarations and whatnot. I also don’t know how to make it emit an XML DOCTYPE or the XML processing instruction which indicates the encoding. Once I figure out how to do a reasonable templating system with CL-WHO my line count will probably go down by 50 lines or so.
  3. cl-prevalence was a pretty serious win in the storage backend department. I just make a list of instances and as long as I go through the transaction mechanism they’re saved to disk and reappear when I restart the app. Very simple and elegant. I wish I hadn’t had to go by the really old documentation to figure it out though.

    There is one bug with cl-prevalence though, which is that it doesn’t handle the clock—or at least it doesn’t seem to based on what I could find. This is a problem because my instances save their instantiation time as their creation time. I worked around it by making a snapshot immediately after adding an instance to the list. I have mixed feelings about that. In any case, it shouldn’t be very hard to fix this in the library by providing a special variable with the time when the transaction started and telling people to use that instead of (get-universal-time).

  4. I included the Parenscript library but never used it. So it’s Ajax-free for right now.
  5. Initially I was very worried about what format to put the date in. Then I decided, fuck it, nobody really cares what time you post something, they only care whether or not the site is abandoned or if they’ve missed something. So I put the last-updated date at the bottom and my design is even more minimal than Steve Dekorte’s. Top that! :) (There’s no way it could be related to my being a shitty designer.)
  6. Developing with Slime and sshfs was pretty good, but sshfs was definitely the worst part of it. I realized last night I could have just had the code checked out via Mercurial locally and be sending that to the remote Lisp, and then eventually check it in and back out on the server so that startup would work. Kind of a “duh” moment.
  7. There was a general lack of refactoring. I have a to do list with about 5 simple refactorings I should have done during development. Once a little bit of your code is scuzzy, it’s pretty easy to let the rest of it turn scuzzy apparently. I guess programming is no different than any other aspect of life.
  8. Weirdly, when I call read-from-string in Slime, it comes back in the tumblog: namespace, but when my code for processing the form calls it, the atoms come back in the common-lisp-user: namespace. It’s moderately annoying because I’m having to use #'string-equal to compare atoms instead of #'eq.

So there you have it. A short feature review: I can post through the web (but not edit), it understands markdown for my commentary, you can filter by tag, it has Atom feeds overall and by tag, and that’s it. I will hopefully rewrite it soon to be less scuzzy, or perhaps to add pagination, after all I only have 4 more entries to post before I need it. I plan on using tags to point out items of particular interest to some of my friends and family, so if you see your name on an item, that’s why.

Tags ,  | 2 comments

SERIES: Haskell for Lisp

Posted by Daniel Lyons Sun, 11 Nov 2007 01:35:00 GMT

One of the great pleasures of being a Haskell user is using hylomorphisms to accomplish all your work. To wit:


factorial x = foldr (*) 1 [2..x]
fibonacci = 1 : 1 : (zipWith (+) fibonacci (tail fibonacci))

Obviously this kind of obnoxious behavior would have to be ported to Lisp at some point. And it was, via the Series macro package. It’s Appendix A in CLtL.

In Lisp you’ll have to make a few concessions. You have to construct your series from other series. There are some handy ways of getting a series from a list or vector or another series. You’re limited to lazy lists using this functionality. Still, it’s fun.

To get started, install SERIES with (asdf-install:install 'series) and then import it with (require :series) and (use-package :series).


(defun fac (n)
  (collect-product (scan-range :from 2 :upto n)))

This is a pretty straight across port: [x..y] becomes (scan-range :from x :upto y). You can omit the :from and it will start with 0, omit the :upto and it will go on forever. There’s also :by which defaults to 1 for replicating the [n,m..z] syntax in Haskell. You also have :length to ensure that you only get so many (very helpful during programming because of the “P” in REPL.) And misc predicates like :above and :below are useful in certain situations. You can also use :type to change the type to ‘float if you want to produce series of floats.

collect-product does what it sounds like it would, multiplying all of the numbers together. If we didn’t have it built-in, you could replicate the functionality with (collect-fn :integer (constantly 1) #'* (scan-range ...)).

Dealing with the Fibonacci numbers is a bit more complicated:


(defvar fibs
  (scan-fn '(values :integer :integer)
           (lambda () (values 1 1))
           (lambda (x y) (values y (+ x y)))))

This works using Lisp’s multiple return values system. Basically, we’re returning two values with each function call; one of them is being passed out to be the item, and both are being fed back through the series generator. It’s not as beautiful as the Haskell but it captures the same concept, is as general (for lists) and performs some similar optimizations.

Tags ,  | 1 comment

Philosophical Cryptotypes

Posted by Daniel Lyons Fri, 09 Nov 2007 10:10:00 GMT

Whorf introduces a concept he calls cryptotypes in talking about language. I don’t remember his exact examples, except that it has to do with when you can use “up” to strengthen a verb. You can stir it up but not swing it up or pour it up, etc. You can break it up or smack it up but you can’t explode it up. What’s the rule? It’s a big hairy complicated cryptotype.

I noticed a good one the other day. The official rules of a four way stop have to do with when you arrive and taking turns clockwise. As Jim Loy points out, in reality, it’s a big cryptotype. There is this supposition that if the oncoming driver is moving, you can go too. That doesn’t come from the law (it seems to come from common sense). Turning left is complex, because you have to enter the lane with your blinker on or you’ll fuck everything up, but you have almost no room at many 4-way stops. If you’re turning right, you have to stop and make sure you’re not going to hit anyone, but often, you can stop and then keep going. This is all messy and intimidating to the new driver, who is trying to adhere to the law but instead confusing and screwing everything up for other drivers.

A religious cryptotype I’ve been thinking about recently is the “G-d will reveal everything to us in Heaven” motif. Where did that come from? It’s a Jewish principle that anything which doesn’t affect halacha not be settled in Talmud, so to some extent I’m welcome to believe whatever I want, but where did this idea come from? I don’t see any precedent for it in Torah. Maybe it’s there but it must be fairly vague. None of the afterlife teachings are very firm in Judaism. But I’m also unaware of a Christian source for this belief. Yet most of my Christian friends take it for granted (as I do) that G-d will show us his cards in the hereafter.

It’s important for philosophers like myself to believe that G-d wants believers to be thinkers. As I said before, by voluntarily restricting his actions to those that can be reasoned about effectively, G-d is giving us the gift of reason. G-d certainly doesn’t need either to restrict his omnipotence or to use abstraction to help deal with the magnitude of the universe as we do. Would G-d would give us such a gift, especially with a corresponding hunger which can never be sated? I don’t have the answer.

Tags ,  | 1 comment

Older posts: 1 2 3 4 ... 43