Formlets and Loop

Sun Mar 6, 2011

Just a quick update today.

First, I've pushed an update to the formlets project on github. It now supports input type=file1. Check the [project page](https://github.com/Inaimathi/formlets), or the new wiki, both of which have slightly more robust documentation than you'll find here.

There's really no occasion to this, by the way. I try to be a self-centered realist in terms of design philosophy, so the only reason I added file fields here was that I finally found I needed them. It actually surprises me quite a bit that I got by for so long with only inputs, passwords, textareas and recaptchas, but there you have it. I'm in the middle of another project at work now though, so I may soon add options and dates.

Don't hold your breath though.

Second, I've been figuring out loop for the past little while2. The pieces that loop helped in are ones that would otherwise have to be expressed in terms of recursion and some intermediary variables. If you want to take a look at it in action, check out the "Validation related functions" section in [this diff](https://github.com/Inaimathi/formlets/commit/0e9f9bd1f608ff9f02867e895385c5455ce365ee#formlets.lisp). Seven lines of loop saved me something like 12 lines of recursion and six lines of helper function. And not only that, but it's (in my opinion, obviously) much easier for a human reader to parse this way. I haven't learned it yet, and doubt I ever will, given its specification. It looks like loop itself is, without exaggeration, several times more complicated than the rest of Common Lisp combined3. iterate doesn't seem to be much better in this regard, by the way. It seems to be loop with a few extra parens thrown in. While that does help with modularity, loop isn't hard to learn because it doesn't have enough parentheses, it's hard to understand becuase it's complicated.

In any case, I've found tutorials on both iterate and loop, as well as the CL cookbook loop entry and Seibels' treatment in PCL. The two things that I needed to know in order to make that formlets code work were either omitted or buried, or merely implied. Specifically, I needed to interate by two elements of a list, and I needed to be able to return a flat list that had double the elements of the input (collecting two elements per input element). Basically

'(:a 1 :b 2 :c 3 :d 4) => '(:a :b :c :d)
'(:a :b :c :d) => '(:a "A" :b "B" :c "C" :d "D")

That's very slightly beyond mapcar as far as I know, so the way it ended up getting written was a recursion. That ended up being very complicated4. So, for my own future reference (and hopefully, for the benefit of anyone else that does a search on this), here's how you do it with loop.

;; Iterating by multiple elements
(defvar test-list '(:a 1 :b 2 :c 3 :d 4))
> TEST-LIST

(loop
   for (key value) on test-list by #'cddr
   collecting key)
> (:A :B :C :D)

;; Collecting multiple elements
(setf test-list '(:a :b :c :d))
> (:A :B :C :D)

(loop
   for key in test-list
   collecting key
   collecting (string key))
> (:A "A" :B "B" :C "C" :D "D")

You can actually skip the "ing" in this case, writing the last two clauses as collect key collect (string key). There's also no requirement for making this a multi-line statement, I just feel that it's easier to read here.

Third, and no one other than me cares, so you may want to go read something interesting instead.

A screenshot of my current WPM

I know it's not very impressive yet, but keep in mind that I started off in the 35-45 range.

Hopefully, I can crack 100 this year.

  1. Which includes managing the enctype properly, displaying file inputs and providing a couple of basic predicate generators for validation.
  2. And re-wrote a lot of the formlet internals with it, now that I've realized that it can basically do everything.
  3. With the obvious exception of format.
  4. Not that the situation helped; this would have been relatively straightforward in regular code, but throw in two or three steps of macroexpansion, and it gets ugly fast.


Creative Commons License

all articles at langnostic are licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License

Reprint, rehost and distribute freely (even for profit), but attribute the work and allow your readers the same freedoms. Here's a license widget you can use.

The menu background image is Jewel Wash, taken from Dan Zen's flickr stream and released under a CC-BY license