repak shawahb
armed and hammered

^

   

rsw@jfet.org


blogroll

       
Tue, 16 Mar 2010

mixin fixin

"To me, making a tape is like writing a letter—there's a lot of erasing and rethinking and starting again. A good compilation tape, like breaking up, is hard to do. You've got to kick off with a corker, to hold the attention (I started with "Got to Get You Off My Mind", but then realized that she might not get any further than track one, side one if I delivered what she wanted straightaway, so I buried it in the middle of side two), and then you've got to up it a notch, or cool it a notch, and you can't have white music and black music together, unless the white music sounds like black music, and you can't have two tracks by the same artist side by side, unless you've done the whole thing in pairs and...oh, there are loads of rules." - High Fidelity (wr. Nick Hornby)

Here's the problem: no one really uses tapes any more. Hell, no one really wants to use CD-Rs either: you just have to rip them again, or copy MP3s from them to your iPod or whatever. No, today's mixtape medium of choice is a USB stick. The problem with this is that there's just too much freaking room on a USB stick. Giving someone a dozen songs on a USB stick is... flaccid. Be generous, for Chrisake.

For myself, when I run into a problem like this, I just ask: what should any reasonable engineer do? Go up a level in the hierarchy. It's time for a new kind of mixtape: the album mixtape, a mixtape of albums rather than of songs. Now, I'll be the first to admit, the album as an art form seems to be dying: pop artists just aren't good or prolific enough to make an entire album of songs, let alone a cohesive, gestalt kind of thing. At the end of the day, yes, we end up eliminating some good one-hit wonder types from consideration, but hey, if you want that you wouldn't be making an album mixtape anyway.

So I set out to make my first album mixtape. My criteria: around ten albums in length; each album has to be one that I consider a really good album on its own (you don't put crappy songs on mixtapes, so...); has to have some kind of glue to it, be it smooth transitions from album to album or some kind of overarching theme (in the end, I went with the former). Fair game here would be Ari's suggestion from earlier today, viz., an album mixtape of concept albums.

Anyhow, this was my raw list:

  • Polo Club - Greenskeepers
  • Silent Alarm - Bloc Party
  • We Are Not Alone - Breaking Benjamin
  • At War With the Mystics - The Flaming Lips
  • The Soft Bulletin - The Flaming Lips
  • Come to Daddy - Aphex Twin
  • Oracular Spectacular - MGMT
  • Carnavas - Silversun Pickups
  • The Bends - Radiohead
  • Superunknown - Soundgarden
  • Songs for the Deaf - Queens of the Stone Age
  • Surfer Rosa - The Pixies
  • Mer de Noms - A Perfect Circle
  • eMotive - A Perfect Circle
  • Listening Tree - Tim Exile
  • There is Nothing Left to Lose - Foo Fighters
  • Forever Changes - Love
  • Turn on the Bright Lights - Interpol
  • Lateralus - Tool
  • The Mollusk - Ween
  • Close to the Edge - Yes
  • Loveless - My Bloody Valentine

Now, I needed to start striking stuff. First, Carnavas, while decent, isn't by itself an awesome album. Gone. Between AWWTM and Soft Bulletin, there's really no comparison; the former didn't make it. TiNLtL is a fucking great album, but it's kind of been overdone; between that and the QotSA album, I'll take the latter for novelty and musical range. Given the surviving albums, MGMT and Radiohead are starting to stick out as a bit incompatible, so they're out. Breaking Benjamin's a good band, and WANA is their best album easily, but it's also not quite right for this collection. This leaves us with a bit more than a dozen, and then it's just a matter of sorting them. It's at this stage that I ended up eliminating the last to go, viz., Lateralus, Close to the Edge, and Superunknown. All are fucking awesome, they just weren't fitting anywhere in the mix in my mind's ear.

So, the final list—in order! which is important for a mix tape, even of albums:

  • Polo Club - Greenskeepers

    This album starts really strong, and it's quirky and awesome throughout. C'mon, a loungey pop rendition of Slayer's "Raining Blood"?

  • Come to Daddy - Aphex Twin

    Polo Club's bonus track is a kind of creepy song with lyrics including "it puts the lotion on its skin / or it gets the hose again." It segues nicely into "IIIIIIIIIIIIIIIIIIII WANT YOUR SOULLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL".

  • Songs for the Deaf - Queens of the Stone Age

    While CtD starts all crazy, it ends on some pretty chill strains with "IZ-US", which always felt to me like a bus ride through a bombed out city. After that, a car starting and a faux AM radio asshole deej introducing the next song seems like a good flow.

  • Forever Changes - Love

    This album starts with a folksy guitar riff, which transitions nicely from SftD's "Mosquito Song". This album is fucking great.

  • The Soft Bulletin - The Flaming Lips

    After the acid-washed depression of Forever Changes, which is kind of an end-of-the-60s retrospective on what was ultimately Timothy Leary's failure to expand our minds with copious amounts of acid, the Lips' album about depression and madness, starting with the deceptively upbeat "Race for the Prize", slides right into place. The Lips' constant stream of psychedelic rock homage is a fitting coda for Forever Changes.

  • Silent Alarm - Bloc Party

    Scratchy, guitar-driven rock is precisely what you need to get yourself back out of the dumps of "Waiting for a Superman [Remix]". Yeah, it's already too heavy to lift—and now it's like drinking poison and eating glass. Don't worry, though, this album sweeps you right up and takes you through "Positive Tension" and "This Modern Love" to "Compliments", which closes it out nicely and does a pretty good job of putting us in a darkish, synthy mood—just in time for

  • Listening Tree - Tim Exile

    This dude is relatively unknown; I saw him open for Imogen Heap. He has some good IDM/D&B/&c riffs on here, and the mood starts and stays relatively dark throughout. I'd be hard pressed to claim that this is actually one of my favorite standalone albums, but the combination of novelty (c'mon, everyone knows you get points for stumping your listener) and mood propriety saves it.

  • Loveless - My Bloody Valentine

    You might argue that I should've just skipped straight to this and dropped Tim Exile from the mix entirely. If that's your feeling, call Listening Tree the prologue to this gritty, atmospheric masterpiece. These guys were ridiculously exacting in the sound they were after—and it's just what we want here.

  • Surfer Rosa - The Pixies

    Black Francis is like a kid who just kind of bangs shit together, but the result is an awesome sound. This album is probably most popular for "Where Is My Mind," but the whole thing is just freaking great. I'd go with the extended edition with an extra 9 songs on it; they're worth the listen.

  • eMotive - A Perfect Circle

    What? An album of covers? Well, not quite: "Passive" was actually jointly written by Maynard and Reznor, and it shows in how awesome it is. Beyond that, there is a hauntingly awesome cover of "When The Levee Breaks" on here that by itself makes this album worth having. But at the end of the day, I like it for the "mixtape in a mixtape" aspect of it, all touched and poked by Maynard et al. And it's a damn solid album.

  • The Mollusk - Ween

    This is the best album to have been made in the last 30 years. I doubt any of you agree with that statement, but that just means you're wrong. More to the point, this is my mixtape, so fuck you. We start off with a nice little intro that could transition from anywhere—"Dancing in the Show Tonight"—and immediately jump into the nautical concept of the album. "The Blarney Stone" deserves a place at your St. Patty's Day celebration, and "Ocean Man" is both fun and kid-safe. Really, the reason this album belongs last is because "She Wanted To Leave" is—and has—an amazing ending.

    "So go fetch a bottle of rum, dear friend,
    and fill up my glass to the brim,
    for I'm not the man I used to be,
    now I'm one of them."

Welp, that's my album mixtape. Obviously I went for the continuity aspect over the single-concept one, but I'd submit that both are reasonable, as are many other approaches.

Now it's your turn: make me an album mixtape.


[ permalink | 0 comments (add one you lazy bastard!) ]

Thu, 31 Dec 2009

after week 16

Note that Indy's dive throws things off a little bit in terms of their offensive ranking and the Jets' defensive.

combined                offense                 defense
--------                -------                 -------
IND	100.000        	NO	100.000        	NYJ	100.000        
NO	91.646        	SD	91.830        	BAL	95.749        
SD	86.626        	PHI	91.822        	DAL	93.576        
PHI	79.168        	MIN	91.079        	NE	92.607        
MIN	77.052        	GNB	90.935        	CIN	89.327        
NE	75.478        	IND	89.343        	SF	83.683        
DAL	72.214        	NE	88.670        	DEN	79.886        
CIN	70.993        	NYG	88.260        	IND	78.597        
GNB	70.450        	BAL	83.602        	CAR	72.561        
ARI	69.379        	ARI	82.140        	GNB	71.179        
NYJ	59.995        	HOU	81.507        	ARI	69.409        
BAL	59.619        	ATL	81.006        	ATL	67.241        
ATL	56.848        	MIA	80.614        	PIT	66.943        
HOU	56.649        	PIT	79.647        	WAS	66.417        
DEN	56.223        	TEN	79.430        	SD	66.388        
NYG	55.115        	DAL	78.356        	MIN	65.096        
PIT	54.285        	NYJ	75.029        	PHI	65.050        
SF	49.062        	CIN	74.061        	HOU	65.034        
MIA	47.653        	DEN	73.744        	BUF	63.172        
CAR	46.999        	SF	72.777        	NO	58.624        
TEN	46.016        	CAR	72.133        	CHI	51.396        
JAC	43.203        	CHI	70.997        	MIA	48.238        
CHI	37.677        	JAC	68.853        	CLE	46.066        
SEA	29.773        	SEA	66.965        	OAK	45.890        
BUF	28.588        	KC	65.263        	JAC	45.735        
OAK	25.806        	WAS	63.496        	TB	42.616        
WAS	22.032        	DET	62.662        	SEA	41.756        
CLE	20.077        	TB	62.391        	NYG	41.546        
TB	15.091        	BUF	60.792        	TEN	38.025        
KC	15.030        	CLE	58.612        	STL	31.421        
DET	6.833        	OAK	52.066        	KC	31.306        
STL	0.000        	STL	47.825        	DET	14.704        


[ permalink | 0 comments (add one you lazy bastard!) ]

Tue, 01 Dec 2009

return to power

In case you're wondering,

Combined                Offense                 Defense
---------------         ---------------         ---------------
IND     100.000         NO      100.000         CIN     100.000        
NO      96.530          MIN     90.914          IND     99.404        
MIN     85.854          SD      87.094          BAL     99.154        
SD      73.787          NE      86.272          DAL     97.433        
CIN     71.224          IND     85.064          DEN     96.653        
DAL     70.499          PHI     83.040          NYJ     94.711        
NE      66.515          GNB     82.737          NE      90.838        
ARI     63.300          ATL     79.940          SF      85.635        
DEN     60.719          NYG     79.766          WAS     85.147        
PHI     60.670          HOU     77.754          PIT     84.737        
GNB     60.126          ARI     77.707          MIN     84.661        
BAL     54.662          BAL     77.599          GNB     79.654        
ATL     52.455          MIA     77.559          ARI     77.114        
PIT     52.065          DAL     75.316          NO      75.706        
NYG     51.601          PIT     75.068          SD      74.312        
JAC     47.213          CIN     71.825          PHI     73.979        
NYJ     45.441          TEN     71.411          BUF     68.004        
HOU     43.562          NYJ     70.387          ATL     66.263        
SF      43.479          SF      70.307          HOU     65.208        
MIA     42.014          SEA     68.625          SEA     63.467        
TEN     38.591          CHI     67.272          CAR     61.805        
SEA     32.860          JAC     64.340          NYG     61.136        
CHI     29.897          DEN     64.291          OAK     59.830        
CAR     27.723          CAR     64.230          CHI     59.151        
BUF     27.607          DET     62.873          JAC     56.308        
KC      18.676          KC      61.394          MIA     53.770        
WAS     17.154          TB      60.568          KC      49.372        
OAK     15.546          BUF     60.357          CLE     48.835        
DET     9.777           WAS     56.923          TEN     45.520        
STL     1.305           STL     46.451          STL     44.678        
TB      1.101           CLE     44.257          TB      37.409        
CLE     0.000           OAK     42.602          DET     25.697        


[ permalink | 0 comments (add one you lazy bastard!) ]

Tue, 27 Oct 2009

motivation

Based on management's favorite catchphrase:


[ permalink | 0 comments (add one you lazy bastard!) ]

Sat, 19 Sep 2009

now with squid bits!

Your brain cannot repel entertainment of this magnitude!

TriHs r465 adds a major feature: two player mode!

True to my word, I've added in the "asshole button" for each player: swap your opponent's next piece for a random one. I don't know yet whether it's a useful addition or not, but at the very least simple strategies like denying them the I or giving them a neverending stream of S and Z are probably annoying enough to get you punched in the face.

I've also added shadow mode, even though I think it's totally cheese. By default it's off, but you can activate it with <Ctrl>-s.

The other somewhat major change I made was breaking the drawing module out of Main. This is a logical partitioning of functionality, and probably makes it a bit easier to swap out Cairo for, e.g., OpenGL. Not that I have any plans to do this, but perhaps someone else will be adventurous. (Hippo, I'm looking in your direction.)

Update: r466 corrects the previous loss condition to bring it in line with the official rules.


[ permalink | 0 comments (add one you lazy bastard!) ]

Tue, 15 Sep 2009

damnit Jim

Because Jim is such a nitpicking bastard, and after reading the Wikipedia page, I have an update for you. (Seriously, thanks for the feedback, Jim.)

r460 has the following changes:

  • CW and CCW keybindings (that you might hate, depending on your keyboard; just fix it if you don't like mine)
  • Instant (hard) drop
  • Hard drop on the final "down" press (or just wait for the soft drop as before)
  • Updated scoring system so that it rewards multiples a bit more
  • Changed the color scheme to match The New Tetris.
  • a README file!

As I add minor updates, I'll just post them here. (Major ones will go in their own entry.) Here's a summary of every version I've posted so far:

  • r457 - first release
  • r458 - added Makefile
  • r460 - fix detailed above
  • r461 - fixed an erroneous return value from the keyboard handler that was really harmless
  • r462 - took focus off the Quit button so that space bar doesn't cause the program to exit
  • r465 - see 2009091901
  • r466 - fixed loss condition to bring it in line with the official rules


[ permalink | 2 comments ]

Mon, 14 Sep 2009

the (not) long awaited...

...is here! You'll need Graphics.UI.Gtk (a.k.a. Gtk2Hs), Graphics.Rendering.Cairo (also part of Gtk2Hs, but sometimes distributed separately), and Control.Concurrent (I use an MVar for game state in case I want to do something crazy later).

For now, this is just a normal tetris game. Ctrl-R restarts, Ctrl-Q (or Alt-Q, or the Quit button) quits.

Enjoy.


[ permalink | 5 comments ]

I don't wanna sound like an Egyptian or nothin'

...but I really like libcairo. Over the weekend I wrote a Tetris-like game using cairo via Haskell's Gtk2Hs bindings.

I have one more obvious bug to fix before I release the source, so I'll probably post tonight once it's fixed. After that, I'm going to implement a bastard function, then scale it out to two players and allow each player to choose the other's next piece if they want.

Obviously we'll need a computer opponent mode as well...

(If you're wondering, I'm hovering around 300 lines of code, but that's a bit on the high side because I went for readability over smallest LoC, and I basically wrote a library of game state transforms and collision predicates and didn't use all of them.)


[ permalink | 0 comments (add one you lazy bastard!) ]

Wed, 12 Aug 2009

a little diversion

On the road trip I started working on an implementation of Set. To make it slightly easier to play I've given it a shitty CGI UI. It works well enough, I guess.

Here's the source (in Haskell, of course).

Oh yeah, also, here's the latest tarball of the crap I hacked up at DefCon for keyboard acoustic eavesdropping.


[ permalink | 0 comments (add one you lazy bastard!) ]

Thu, 16 Jul 2009

end of an era; stroker and hoopdisk

The world is a different place.

Last night, after a trip to Fry's, I replaced the last proud vestiges of positron Mk. III, the IBM Ultrastar DNES-318350 U2W SCSI boot drive (a whopping 18.2 Gb!).

Not that it died, or anything; it's still running great, and I'm keeping it as a cold backup of my boot drive. The reason I replaced it is that the SCSI controller was unhappy when I put the computer into ACPI S3 (suspend-to-RAM), or more specifically when the computer resumed operation: it would timeout for almost a minute before doing a bus reset, and I was concerned that this could cause problems with filesystem consistency. Since I'm running XFS, I'm not taking any chances—as far as I can tell, it's somewhat less robust against corruption than EXT3.

The replacement drive is a 500 Gb Hitachi Deskstar, née IBM Deathstar. These days the Hitachis have a better reputation and a 5 year warranty, plus I have my trusty old Ultrastar in case something goes wrong.

Because I don't need much space on the boot partition, I decided to short stroke the drive for a bit better seek performance and thus faster boots. Basically, I made a 30Gb partition at the beginning of the disk, and left the rest to other partitions. Since the partition is small, the average seek time within the partition is much shorter than the average over the whole disk. The rest of the drive I devoted to a swap partition (kind of a waste, but whatever) and—horrors!—a Windows partition.

I haven't run windows on positron since late 1998, which means I broke an even longer standing tradition than my 10 year old SCSI drive by installing it last night. I doubt I'll boot it at all until I start playing some fancy computer game that isn't happy enough on my T61, but it feels really wierd to see Windows booting.

Also, even with a "fully updated" XP SP3 install CD, the install took longer and required more intervention (during and post install when it hadn't gotten my drivers right) than the last Ubuntu install I did (I'm not going to say it was harder than a debian install would be for the average person, but it was certainly more painful for me (in a "guilty conscience" kind of way, really)). I guess most people never install Windows since they just throw away their computer when it becomes too full of viruses, but it's nice to see just how good Ubuntu et al have gotten, especially when reflecting on the computer on whose earliest versions I ran a 1.0.2x kernel. (OK, there is nothing left of that machine but the name, but what's good enough for Theseus is good enough for me.)


[ permalink | 0 comments (add one you lazy bastard!) ]

Sat, 11 Jul 2009

dude I got a dell

Since I'm going to be doing a bunch of travelling this summer, I decided I wanted a really portable computer. Now, netbooks are all the rage, but I abhor low res screens, and most of them are a paltry 1024x600—utter shit—so I couldn't really get one of those, right? Well...

In the last couple months a new generation of netbooks has become available with higher resolution screens (1366x768) at reasonable prices. (There's also the awesome but stupidly expensive Sony Vaio P with the 1600x768 screen in 9", but I'm not shelling out for that.) At first I dismissed these as lacking, but then I considered that my 14" Thinkpad T30 is ugly but tolerable at 1024x768, so a 1366x768 screen in 10" probably would look pretty nice. Moreover, given that the T30 was previously my best option for travel, I'm going strictly upwards in res, portability, battery life, and modern niceities like USB2. Computing power might be a very small step back from a 1.8 GHz P4-M to a 1.6 GHz Atom Z530, but it's probably not more than 20% or so—plenty for a little travel laptop!

Of the available models, I was most intrigued by the Dell Mini-10 and the Acer AO751h, which are more or less identical. The deciding factor was that I was able to get a refurbished Mini-10 for $330, whereas new both are about $450. Refurbs also have the virtue of shipping really quickly.

The only wart in hardware support is that the Intel GMA-500 video driver is kind of a mess and only readily available under Ubuntu (but it does work for 2d and 3d basically right out of the box). Don't get me wrong, Ubuntu is better than anything RedHat based, but certain pieces of its not-Debianness are annoying as shit. At the end of the day, as long as I can run some combination of fvwm and xmonad (depending on my mood) and apt-get install still works, I'm more or less happy.

Anyhow, for $330 it really can't be beat, and I'm very happy with it so far. Of course, I'll post updates as events warrant.


[ permalink | 0 comments (add one you lazy bastard!) ]

Fri, 10 Jul 2009

delay this

My Thinkpad T30 had a longtime issue where it would delay for 30 seconds after loading the network card on every boot. I never bothered to debug it until last night, which really makes no sense because I've now got a T61 and (very soon now) a Dell Mini-10 which together obviate the T30 entirely; nevertheless, I'm loyal to this little machine because it's still pretty great.

The issue started after a dist-upgrade several months (or more) ago, so I was thinking it was either the new kernel or maybe udev. After following a couple dead end leads (mostly regarding problems with the Cisco Aironet 802.11 card), I found a couple discussions about udev trying to rename the network cards but getting confused about the dual nature of the Aironet device (i.e., wlan0 and wmaster) and trying to just wait it out. The solution is simple: rm /etc/udev/rules.d/*persistent-net.rules to clear out stale entries from earlier versions of udev.

Note that since I use ifrename I don't care about having persistent network interface names assigned by udev. If you do, your solution may involve deleting this file and then editing the newly created one after a reboot so that your network cards are assigned the right names.

More discussion on this:

Hopefully someone will find this useful.


[ permalink | 0 comments (add one you lazy bastard!) ]

Mon, 15 Jun 2009

wrap this

rlwrap is awesome. It takes any commandline tool and makes it behave like it uses GNU readline.


[ permalink | 0 comments (add one you lazy bastard!) ]

Sun, 14 Jun 2009

yay!(cd)

or, Yet Another Y-Combinator Derivation

In the comp.lang.ml FAQ one of the questions asks about the Y-combinator; the answer is provided without derivation or explanation of the subtle datatype backflip you need to use. So we'll derive it together here.

We've all seen the standard Y-combinator derivation in Scheme, right? Y is a fixed-point combinator which represents, in effect, the distilled essence of recursion. To sketch Gabriel's argument (in Scheme first), we start with an example recursive function—factorial, of course:

(define fact (lambda (n) (if (= n 0)
                             1
                             (* n (fact (- n 1))))))

> (fact 5)
120
>

Now, what we want to do is define fact without using fact—so what if we change it so that we can pass the function in that we'll call recursively?

(define f (lambda (fz n) (if (= n 0)
                             1
			     (* n (fz fz (- n 1))))))

But what function do we pass in as fz? f itself, of course—it'll happily keep passing itself all the way down to the base case, and what we get out is factorial.

> (f f 5)
120
>

Now, for reasons which will become clear in a second here, we will curry this function, i.e., turn one function of two arguments into two nested functions taking one argument each:

(define ff (lambda (fz) (lambda (n) (if (= n 0)
                                        1
					(* n ((fz fz) (- n 1)))))))
> ((ff ff) 5)
120
>

See? Basically the same thing, but now ff takes one argument—another function—and returns a function that takes a number and returns its factorial. But we're not done yet: we started with (fact n) and now we have ((ff ff) 5). Well, let's start by fixing the recursive call, recognizing that we can hide the (fz fz) inside lambda:

(define ff (lambda (fz) (lambda (n) (if (= n 0)
                                        1
					(* n ((lambda (n) ((fz fz) n)) (- n 1)))))))

Well, that lambda in there is ugly, but we can always just pull it out and then pass it in via a variable:

(define ff (lambda (fz)
                   ((lambda (z)
		            (lambda (n) (if (= n 0)
			                    1
					    (* n (z (- n 1))))))
		    (lambda (n) ((fz fz) n)))))
> ((ff ff) 5)
120
>

It doesn't look like we're getting any better in terms of recovering the original (fact 5) syntax, but I assure you we're getting closer. Recognize that we could recover the original behavior by just defining a new function fff like this:

(define fff (lambda (n) ((ff ff) n)))

Yup, we've seen this trick before. But let's expand out the (ff ff) so we can do just one definition:

(define fff ((lambda (fz)
                     ((lambda (z)
		              (lambda (n) (if (= n 0)
			                      1
					      (* n (z (- n 1))))))
		      (lambda (n) ((fz fz) n))))
             (lambda (fz)
	             ((lambda (z)
		              (lambda (n) (if (= n 0)
			                      1
					      (* n (z (- n 1))))))
		      (lambda (n) ((fz fz) n))))))
> (fff 5)
120
>

And we've done it. Nothing but arithmetic operations and passed-in function names for defining a recursive operation. But we can generalize this by realizing that we can separate out the "guts" of factorial relatively easily:

(define Fguts (lambda (z)
                      (lambda (n) (if (= n 0)
		                      1
				      (* n (z (- n 1)))))))

This is a function that requires us to pass in the recursive continuation, so it is not itself recursive, and even better, now that we've defined it we can pull Fguts out of fff and make it somewhat prettier:

(define f3 ((lambda (fz) (Fguts (lambda (n) ((fz fz) n))))
            (lambda (fz) (Fguts (lambda (n) ((fz fz) n))))))

This is identical to fff, but we've folded the mess into Fguts. Note that we are still using (lambda (n) ((fz fz) n)) just as before—because this was really the first glimmer of the prize. Consider adding one more layer of lambda where we completely generalize by passing in Fguts or any other "guts"-style function:

(define Y (lambda (X)
                  ((lambda (fz) (X (lambda (n) ((fz fz) n))))
		   (lambda (fz) (X (lambda (n) ((fz fz) n)))))))

And we've arrived at the applicative-order Y-combinator. Taa daaaaaaa!

> ((Y Fguts) 5)
120
>

So could we do the same thing in Standard ML? Well... kind of. The type system gets kind of bitchy if we try to follow exactly the same derivation:

- fun f fz 0 = 1
=   | f fz n = (n * (fz fz (n-1)));
stdIn:3.20-3.31 Error: operator is not a function [circularity]
  operator: 'Z
  in expression:
    fz fz

Many ML programmers are unaware that there is a trick to deriving the Y-combinator in the same wy as above; we simply have to define a recursive datatype so that the type checking unification function doesn't complain about circular substitutions:

datatype 'a t = T of 'a t -> 'a

Now we can start at the top (almost; we'll take advantage of SML's automatic currying for now):

fun ff (T fz) 0 = 1
  | ff (T fz) n = (n * (fz (T fz) (n-1)))

- ff (T ff) 5;
val it = 120 : int

The above step is conceptually the most important and difficult in terms of getting Hindley-Milner on our side. ff has type (int -> int) t -> int -> int, meaning that we will need to keep the same fz (T fz) structure throughout the rest of this derivation. Without it, the type inference system will shun our circular definitions.

Continuing the same argument as before, we wrap the ugly fz (T fz) inside a lambda, then pull it out as an argument (with a little acrobatics because we can't take advantage of automatic currying for this step):

fun ff (T fz) 0 = 1
  | ff (T fz) n = (n * ((fn n => (fz (T fz) n)) (n-1)))

(* now pulling the new "inner function" out *)

fun ff (T fz) = ( ( fn z => ( fn 0 => 1
                               | n => (n * (z (n-1)))
		            ) )
                  ( fn n => (fz (T fz) n) ) )

Now we're ready for fff, and ditching the fun syntactic sugar completely.

(* fun fff n = (ff (T ff) n) *)

val fff = ((fn (T fz) => ((fn z => (fn 0 => 1
                                     | n => (n * (z (n-1)))))
                          (fn n => (fz (T fz) n))))
           (T 
	   (fn (T fz) => ((fn z => (fn 0 => 1
                                     | n => (n * (z (n-1)))))
                          (fn n => (fz (T fz) n))))))

We're close now! Time for Fguts (returning for the sake of brevity to automatic currying) and then f3:

fun Fguts z 0 = 1
  | Fguts z n = (n * (z (n - 1)))

val f3 = ((fn (T fz) => (Fguts (fn n => (fz (T fz) n))))
          (T
	  (fn (T fz) => (Fguts (fn n => (fz (T fz) n))))))

So close we can taste it. Abstracting Fguts gives us the Y combinator once more:

val Y = fn X => ((fn (T fz) => (X (fn n => (fz (T fz) n))))
                 (T
		 (fn (T fz) => (X (fn n => (fz (T fz) n))))))

Thus sayeth the interpreter:

val Y = fn : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
- (Y Fguts);
val it = fn : int -> int
- (Y Fguts) 5;
val it = 120 : int

By the way, there is a ridiculously simple way to define precisely the same Y-combinator in SML:

fun Y f n = f (Y f) n

(* or, using the built in compose operator "o" *)
fun Y f n = (f o Y) f n

Of course, both of these "cheat" because they're explicitly recursive.


[ permalink | 0 comments (add one you lazy bastard!) ]

Mon, 08 Jun 2009

formalism paradox

In perusing the veritable cornucopia of languages mentioned in my previous post (and others), I've noticed a curious pattern: languages with formal standards are, strangely enough, the ones most likely to have several competing, somewhat incompatible implementations. Languages like Standard ML, Common Lisp, Haskell, Scheme, and C are all standards-based, and yet their respective compiler/interpreter implementations have various incompatibilities.

Conversely, Perl and OCaml, whose featuresets are basically defined by their implementations, have essentially one version each (OCaml has VM versus native compilation, but with common maintainers).

Now, having multiple competing implementations certainly has its upsides, and I'm in no way arguing that it's bad to have a formal standard. It is really weird to consider, though: having a standard naturally encourages multiple implementations, which are almost certainly going to have at least some inconsistencies. By eschewing formal standards and adopting the perl "descriptive" (versus authoritative) documentation model, you virtually guarantee interoperability.


[ permalink | 0 comments (add one you lazy bastard!) ]

postpartum bliss

The chip taped out last Thursday; Friday I did some final cleanup stuff, and now I'm off until Friday. So now I'm just hanging out doing nothing.

Not really nothing. I might go out and buy inFAMOUS at some point—the demo is freaking badass and you should stop reading this and play it immediately—but right now I'm busy.

With what, you'll ask? Learning me some new programming languages. Yeah, plural—Standard ML right now, but I also plan to learn some subset of [Haskell, Erlang, OCaml]. In fact, Joe Armstrong's Programming Erlang is sitting right next to me on the couch because the nice mail lady just dropped it off; first impression is that it's a very decent deal at $25. The forthcoming Erlang Programming book from O'Reilly may also be good, but Armstrong seems to be universally loved, so I'm not going to argue.

The SML book I'm reading right now is one available online, Programming in Standard ML by Robert Harper. It's well written and gets you going. I burned through 10 chapters of it in a couple hours yesterday, and I've been playing around with what I've learned so far to help the syntax set in. So far, my impressions are that type inference is an astoundingly cool idea, and while SML/NJ is friendly inasmuch as it has a REPL, MLton produces code that runs substantially faster. Identical implementations of Rabin-Miller (modulo the differences in library calls) yielded a 3500x (yes, ~3.55 orders of magnitude) difference in speed. I'm pretty sure this implies that my implementation is crap and MLton is optimizing away my painful scribblings. Also with regard to SML/NJ versus MLton, the build sequence for the former is more annoying than for the latter—but that's what makefiles are for, so it's hardly worth mentioning (though the documentation on the build process is admittedly somewhat annoying).

Anyway, also on the menu for SML are UNIX System Programming with Standard ML (free online) and ML for the Working Programmer (can be had for like $12 used on Amazon). The MLton.org wiki's Standard ML page and the SML/NJ literature page also list some more resources, and the SML sourceforge project has good SML basis library documentation.

For OCaml, the official user's manual is free, very complete, and is well regarded. There is also Introduction to Objective Caml by Jason Hickey, which despite being distributed from the Caltech website comes with ominous redistribution warnings. Apparently Practical OCaml by Joshua B. Smith is fucking terrible, so I'm not even bothering to link it. On the other hand, OCaml for Scientists seems well regarded. You can find it in DjVu format from a few pirate websites, but please buy the book if it's any good—or steal it brazenly if it's bad, I guess. Wikipedia lists a few online tutorials in the "External links" section of the OCaml article.

Among Haskell books, the best received seems to be the newish one by O'Reilly, Real World Haskell. You can read the whole thing online and perhaps even get lost in the paragraph-by-paragraph comments. I don't know enough about other resources to make specific recommendations, but the Haskell Wiki's Learning Haskell page has a bunch.

While I'm nerding on programming languages, I gave F# a spin under mono and, impressively, it works. It's pretty trippy to see this pop up in an xterm:

[kwantam@muon ~/Desktop/FSharp-1.9.6.16/bin]$ mono ./fsi.exe 

Microsoft F# Interactive, (c) Microsoft Corporation, All Rights Reserved
F# Version 1.9.6.16, compiling for .NET Framework Version v2.0.50727

Please send bug reports to fsbugs@microsoft.com
For help type #help;;

> _

Brings me back to my old QBasic days. Speaking of which, apparently the FreeBasic project is pretty badass. I say this just in case you're missing nibbles or gorillas.


[ permalink | 0 comments (add one you lazy bastard!) ]

Sat, 30 May 2009

mouserx

My old work mouse, a borrowed-ish MS Intellimouse Explorer 3.0A, had this odd habit of causing X to crash every once in a while. I don't know how this is possible, I only know that it had to do with the scroll wheel and it was very hard to reproduce. (OK, I can't say 100% for sure that it was actually the mouse, but the frequency of crashing with the same usage model dropped to zero abruptly after switching, which is good enough for me until I find a counterexample.) It may be that the thing is dying and somehow exposing a flaw in the xorg evdev driver.

All of that is beside the point. I went out and bought a new mouse, which was a frustratingly difficult task: apparently everyone likes their mouse wheel to feel like rotting fruit, whereas I want positive, LOUD clicks like the nearly unused Logitech bottom-of-the-line optical mouse connected to positron. Aside: I really ought to do something other than VGA mode on a text console considering I spent the $80 on an 8800GT when I rebuilt positron last year, right? Oh well.

So, because I wasn't particularly happy with any of the scroll wheels, but because I did still want a new mouse for work, I bought a $10 GearHead LM6000U laser mouse—if I can't be happy, at least I can be cheap. Laser mice, as far as I can tell, all use much higher resolution imagers than their diode-equipped optical siblings. As a result, when I move my mouse an inch, my optical mouse registers a 400-pixel movement, but the laser sees 1600 pixels go by. This is great, except that my fine motor skills haven't magically improved by 4x just because I spent a Hamilton at Fry's. So just turn down the mouse sensitivity, right? Well, kind of...

X has an interesting way of doing mouse sensitivity. Basically, you say xset m <accel> <thresh>, and when your mouse moves more than thresh pixels in a "short period of time" (probably one or two mouse refresh intervals, but I'm too lazy to find out for sure), the movement rate is multiplied by accel. But what if you want to slow down the pointer instead? Well, accel can be a fraction (yes, you specify a fraction, not a float), and thresh can be set to 1, and then all mouse movements end up slower. But then you lose the whole long distance movement acceleration thing which is really the point of this setting.

Well, now that we know that, we have to look a little more closely at the way X interacts with the mouse driver. In most modern implementations, e.g., default Debian behavior, X gets input device information from hald via the evdev module and sets up your pointers, ignoring any InputDevice sections in xorg.conf. While this is all soft and friendly, evdev is still a bit sparse in terms of configurability.

The other option is to use the traditional mouse module, wherein you can specify mouse resolution and, more importantly, mouse sensitivity. To convince X to do this, however, you first have to tell it to ignore hald-detected devices, like so:

Section "ServerFlags"
        Option          "AllowEmptyInput" "false"
        Option          "AutoAddDevices" "false"
        Option          "AutoEnableDevices" "false"
EndSection

AllowEmptyInput disables the kbd and mouse drivers; AutoAddDevices is the setting that tells X to talk to hald. You don't actually need the third line; I just put it in there out of spite. You can see more about all of these options in the xorg.conf(5) manpage.

Now that X isn't autoconfiguring your mouse and keyboard, you're going to have to specify them manually... but you can handle that. The point for us is to enable the use of the mouse driver in an InputDevice section pointing to our nifty high-resolution mouse so that we can take advantage of that driver's greater configurability:

Section "InputDevice"
	Identifier	"Mouse1"
	Driver		"mouse"
	Option		"Device" "/dev/input/mice"
	Option		"CorePointer"
	Option		"Resolution" "1600"
	Option		"Sensitivity" "0.25"
	Option		"Protocol" "Auto"
	Option		"Emulate3Buttons" "no"
	Option		"ZAxisMapping" "4 5"
EndSection

Now our nifty mouse is running at its maximum resolution, but we're scaling down the movements by a factor of four so it feels the same as the old mouse. This means that there are 4x the number of mapped mouse motion pixels in the same distance across the screen, i.e., you have higher precision control over your mouse pointer by a factor of 4 (no claims here about the practical limit of such things... if you don't think you need this, why did you bother buying a laser mouse?). It also means that we can go back to our friend xset and use the long distance accelerator function.

One caveat (this one bit me!): you cannot have two different pointer devices set at two different sensitivities. Don't complain to me, that's how xorg works. If you have multiple pointing devices, the highest (numerically greatest) sensitivity setting provided will be used, meaning if you have another mouse and have forgotten to set the sensitivity option in its InputDevice section, the above snippet will seem not to work because the default sensitivity is 1.0.

Another comment: for various reasons (basically I want firefox to work correctly), I run gnome-settings-daemon even though I use fvwm2 and abhor desktop environments. If you use a desktop environment like gnome or KDE, it will very likely override your xset settings with the settings from whatever crappy mouse config applet you use. If you don't want this to happen, at least in gnome, you can use gconf-editor to set desktop / gnome / peripherals / mouse / motion_acceleration and desktop / gnome / peripherals / mouse / motion_threshold to -1; this will apparently prevent gnome from screwing with your settings. Then, of course, just call xset at login from your .xsession (or whatever you call it) file. Or just use your crapplet to set it up and get off my lawn.

(Lest you point and laugh at my fvwm2 use: come back and talk to me when your windowmanager's configuration file is written in a turing-complete scripting language.)


[ permalink | 0 comments (add one you lazy bastard!) ]

Sat, 18 Apr 2009

whitespace Nazis must die

How am I the only person who sees how retarded Python is? It is, no lie, the worst programming language ever created.

Seriously. This is a language for which scripts can go from working to completely broken because your text editor converted tabs to spaces or vice-versa. I can email a working script to you and have it arrive broken. Newsflash: no one bothers to preserve whitespace because you can't fucking see it. Differentiating between a tab and seven spaces makes you retarded.

If you program in Python and like it, you are dead to me. If I see you programming in Python, I will kill you. Seriously, if you see me walking down the street while you're programming in Python you best jump right in the nearest coffin, I don't care if it's your birthday and you mama needs the coffin 'cause she's dead.


[ permalink | 8 comments ]

Thu, 11 Dec 2008

shackleds' revenge

Some of you might have read about this travesty of education. As a concerned resident of Austin, I did my part to help correct this injustice by writing the following letter to the AISD ombudsman:

From: "Riad S. Wahby" 
To: ombudsman@austinisd.org
Subject: Austin teacher versus Free Software

Ms. Reeves,

I'm writing to you today on behalf of "Aaron," the student mentioned in
this article:
	http://linuxlock.blogspot.com/2008/12/linux-stop-holding-our-kids-back.html
To summarize: "Karen," Aaron's teacher, found him discussing and
distributing copies of the Linux computer operating system, and
responded by confiscating said copies and making outlandish and
factually incorrect claims concerning computer software in general,
Linux in particular, and the legality of distributing same.  I urge you
to familiarize yourself not only with the details of the article above,
but with the facts concerning the Linux operating system and Free
Software in general:
        http://en.wikipedia.org/wiki/Linux
        http://en.wikipedia.org/wiki/Free_software

Before I continue, I'll inform you of my qualifications and experience
in this matter: I am not at all affiliated with Aaron, Ken Starks, or
HeliOS Solutions; I hold a Master's Degree in Electrical Engineering and
Computer Science from the Massachusetts Institute of Technology; I write
Free Software, both as hobby and at times in the past professionally; I
am an avid Linux user nearly to the exclusion of all Microsoft products,
personally and on behalf of my employer---I am a Senior Integrated
Circuit Designer at Silicon Laboratories here in Austin; and like Aaron
I have experienced oppressive ignorance at the hands of primary-school
"educators."

I shall not bore you by fully deconstructing Karen's claims concerning
computer software.  However, please note the following:
        - Dissemination of Linux and related software at no cost is
          completely legal.  There are many organizations whose purpose
          is to package Linux in a user-friendly way and distribute it
          for free:
                http://www.debian.org
                http://www.ubuntu.org
                http://www.fedoraproject.org
                et alia
        - Most Linux-related software is distributed at no cost under a
          software license called the GNU General Public License, which
          requires distribution of human readable source code along with
          the software. For students who are learning about computers
          and programming, being able to examine and experiment upon the
          code underlying a piece of software is of paramount
          importance; thus, Linux and Free Software in general are
          superlative learning aids.
        - The claim that "no software is free" is so incorrect as to
          verge on frightening.  Linux and related software have become
          pervasive to the point where they are used in everything from
          cellular telephones and computer networking infrastructure to
          video game systems and vending machines---precisely because
          the software and source code are available at no cost.
        - Karen's claim that she "tried Linux during college" is
          dubious; more to the point, it's apparent that if she did so,
          she certainly didn't learn anything from the experience!  As a
          seasoned Linux user, the notion that Linux conveys a
          disadvantage is amusingly parochial (especially in light of
          the wide variety of applications in which it is being used).
          That Karen believes this is the case is evidence that she has
          already been surpassed in computer knowledge by her student---
          and doubtless this gap will only grow as Aaron continues to
          use Linux.

In light of the above, I strongly urge you to intervene on Aaron's
behalf; moreover, if necessary I will happily testify in this matter.
That your teachers are misinformed about matters beyond their ken is
hardly surprising; that they would overstep so far as to discipline a
student, confiscate his property, and engage in calumny as a result is
inexcusable.

Thank you for your time,

-=rsw

Bets on whether I get a response?


[ permalink | 0 comments (add one you lazy bastard!) ]

Tue, 25 Nov 2008

heavy irony

Today I stole a book on ethics.


[ permalink | 0 comments (add one you lazy bastard!) ]

Wed, 05 Nov 2008

democracy rules

I'm not normally a sentimental patriotic type, but spontaneous anthem choruses at 2a following an amazing and cathartic election night make me go all tingly.

This is the first time I've ever embedded a YouTube video here. Slouching Towards Gamorrah, certes.


[ permalink | 0 comments (add one you lazy bastard!) ]

Mon, 15 Sep 2008

ultimate rickroll

Last week, Jeff was out of the office on vacation. Since he'd previously pranked Ion, a few of us plotted to even the score. Stretch suggested that we take the MP3-filled 300Gb external hard drive on his desk and replace all the files with some godawful music. We settled on a slight modification of this plan: for each MP3, I took the first 5 seconds of the real song and pasted it onto the front of one of a selection of songs, including

  • "Ventolin"—Aphex Twin
  • "Heut' Ist Mein Tag"—Blümchen
  • "Rollerskate Date"—Group X
  • "Party 4u (Holy Nite Mix)"—Cranky
  • "Call On Me"—Eric Prydz
  • "Dragostea din tei"—O-zone (a.k.a., the Numa Numa song)
  • "Quit Playing Games With My Heart"—Backstreet Boys
  • "What Is Love?"—Haddaway
  • "The Sign"—Ace of Base
  • a few pieces of Romanian folk music provided by Ion
    and of course...
  • "Never Gonna Give You Up"—Rick Astley

As luck would have it, the first song Jeff chose to play had been stapled to "Never Gonna Give You Up"—a dead giveaway to him that something was very wrong. During testing, our favorite combination was "What A Wonderful World" cutting into "Heut' Ist Mein Tag".

I learned a few things from this. First, most MP3 players will barf if you give them an MP3 whose samplerate (not the bitrate, the samplerate of the decoded PCM stream) changes halfway through. This includes some versions of mpg123, iTunes, Windows Media Player, and WinAmp; mpg321 seems to work fine. Second, the quelcom package is very nice, comprising commandline utilities to cut and paste together MP3s without reencoding (and WAV files, too); if qmp3cut doesn't like an MP3 file, cutmp3 probably will. Third, id3cp (from id3lib) is very useful when you want to replace every mp3 on someone's hard drive without raising too many suspicions. Finally, in retrospect putting 10-20 seconds of the original MP3 rather than 5 would probably have been a little more effective on the confusion front.


[ permalink | 0 comments (add one you lazy bastard!) ]

Mon, 25 Aug 2008

semilunar hiatus

Or is it bilunar?

Anyway... I haven't posted in a while, so here's what's new with me:

  • About a month ago, we got a second dog! He's a Nova Scotia Duck-Tolling Retriever. His official AKC name is KD's Ten Thousand Gauss, but we call him Niko (shortened from Nikola Tesla. Get it? 1 T = 10 kG). Niko and Shockley are best friends, and while Niko will eventually be about twice Shockley's size (45 pounds versus 25), for now they're within a couple pounds of one another. To the right is a picture of him and Shocks eating.
  • I'm turning into a soccer mom.
    Well... not really, but I am trading in my beloved STi for a Volkswagen Jetta SportWagen TDi. Apparently I have a penchant for three letter trim designators ending in "i," but this time it's not a rice rocket—it's a diesel. The wagon (similar in size to an Outback, but a little tubbier looking) will hold the pups nicely, transport too many people to ridiculous parties, and carry three or four kegs in the back, all the while getting 50 MPG.
    I'm picking up the car tomorrow in El Paso (the diesel wagons are ridiculously hard to find because there are only like 2000 of them being made this year, so I've heard) and I expect to get back to Austin on one tank with fuel to spare. Eat that, Prius.


[ permalink | 0 comments (add one you lazy bastard!) ]

Tue, 24 Jun 2008

pix plz kthx

Here, you happy now?


[ permalink | 0 comments (add one you lazy bastard!) ]

Mon, 16 Jun 2008

broken promise of a thousand words

No pictures this time, patient readers. My apologies.

Well! We finally taped out the Thursday before last, so I was off all last week catching up with things around the house. The main event was setting up irrigation for my poor parched yard, which involved lots of soaker hose for all the planters and a few impact sprinklers for the grass. I have things divided into two zones on each of the three spigots placed around my house, and as long as I only run one of the two sprinkler zones at a time the water pressure is sufficient to run soakers on the other two spigots.

This strongly suggests my next project: none of the electronic timers I've found can be programmed for the odd watering schedule around here, viz., Wednesdays and Saturdays, so I'll just have to build my own. Either I'll make individual ones for each sprinkler, or I'll do a little control interface for some solenoid valves and hook it up to positron.

Speaking of positron, that was the other time sink this week: positron Mk. V died a slow lingering death. A couple weeks ago I started getting random lock-ups; figuring it was a heat problem, I reduced the CPU core voltage, and this seemed to work for a while. Unfortunately, it started happening again, and the frequency of occurrences increased to the point where it wouldn't even get through a boot sequence. I swapped video cards, pulled RAM, and even swapped the processor (since I found one for $20ish), to no avail. My last effort was replacing the power supply, since I figured if I had to replace the motherboard I'd need one anyway. Fortunately, Fry's had a sale on the Antec Neopower 500 (for $65, no less!). Unfortunately, the new supply did nothing, but that just meant that I had an excuse to build positron Mk. VI.

Initially I really liked the abit IP35-Pro, but decided that spending that much on a motherboard wasn't worth it unless I was actually planning on running a FSB upwards of 500 MHz. Instead, I ended up getting a DFI LanParty DK P35-T2RS, which is a reasonably priced board that's another favorite for dual and quad core overclocking. Since I'm kind of cheap, I only sprang for an Allendale E4600, which should overclock by 30% with relative ease; I figure by the end of the year quads will be even cheaper and I'll trade up. I also picked up 4 Gb of RAM (a new personal best!) and a reasonably-priced GeForce 8800 GT board (thanks for catching me up on the NVidia chipset line, Wikipedia). For now, Mk. VI will inherit Mk. V's RAID array, and yes, I'm still running Mk. III's 18 Gb IBM Wide Ultra2 SCSI drive as the boot drive. Pretty soon I'll go to a small (30ish Gb) 10k RPM SATA drive for the boot and get four 500 Gb SATAs for a new RAID5 array.

Since I'm talking about positron, I think it's time for a retrospective:

  1. 1994: Pentium 133 MHz, 8 Mb RAM
  2. 1997: Pentium-MMX 233 MHz, 40 Mb RAM
  3. 1999: Dual Pentium II 450 MHz, 512 Mb RAM
  4. 2004: (July) Dual Pentium IIIs at 1 GHz replaced Mk. III's processors
  5. 2004: (October) Athlon64 3200+ (2.2 GHz), 1 Gb RAM
  6. 2008: Core2 Duo E4600 (2.4 GHz), 4 Gb RAM

Just brings a tear to your eye...


[ permalink | 2 comments ]