As someone who has maintained his set of 'dotfiles' faithfully
for a few years now, window-manager choice and configuration
has been of great importance. I used FVWM
for a few years, finally switching to
Sawfish somewhere
in 2005. My sawfish configuration mimics what I had set up in
my fvwm days rather closely, and sporadic periods of messing
around with settings have been the only (enjoyable) disruption
to my otherwise very productive computing life (as far as
my Desktop environment is concerned).
I switched to Sawfish simply because it's scripting
language, librep is a Lisp - one that I had been spending
many commuting Zaurus hours on. Life has been very good
with this the way it is.
Until I read
yesterday's LTU article
a post that talks about side-effects in imperative languages
that cause closures to capture variables in less-than-desirable
ways. It was not the actual post itself, but a link to
a series, with one interesting post featuring a tour of
Haskell and a rather fabulous example to use as a
working demo program: XMonad,
a really good window manager written in and extensible
in Haskell:
- Windows are automatically tiled
- Mouseless
- Configurable (even in real time), using Haskell
I'm tempted to try it; given todays large displays, arranging
windows with your mouse just feels silly.
Imperative-style Iterations and closures don't mix well
The undesirable form of variable capture that
Erik Meijer
describes
is, I think, a lot to do with supporting closures in languages where C-style
iteration is still relatively a norm. The
for (i = 0; i<10; i++){ /*..*/ } lets you
use the
i as a block scope variable
while it remains a part of the
mechanism of the iteration.
It's easy to reproduce this in Perl (the language which is
many things to many people), if you use the C iteration idiom:
my @arr = ();
for (my $i = 4; $i < 7; $i++) {
push @arr, sub {
return $i;
};
}
for (my $i = 4; $i < @arr; $i++) {
my $f = $arr[$i];
print $f->(), "\n";
}
But the idiomatic way does away with this problem;
and things are better now that we don't have to
get distracted by the iteration mechanism:
map and
grep where one can:
my @arr = map {
my $i = $_;
sub {
return $i;
}
} (4..7);
print $_->(), "\n" foreach @arr;
Javascript may not have map/grep, but for Functional-style iterations,
libraries do a great job of providing such utilities. Prototype.js
comes to mind.
var delayedActions = [4,5,6,7].map(function (n) {
return function (i) {
return i;
};
});
In fact this is where these closure-ish APIs shine - they
overcome Javascript's problem (i.e., variables only have function scope)
by expressing loops functionally.