Another Blog

Mostly about computers, generally Linux-related

Wow… xmonad does it again!

I’ve been happily using xmonad for a while now. It’s a tiling window manager written in Haskell. To me it’s a huge boost in productivity and it has helped me rediscover the fun of using a computer. Although I’ve initially tried it simply because it was written in Haskell (I was a happy wmii user then) , I now dread every single moment of using a different window manager.

Above all, xmonad is incredibly flexible. This comes from the huge extension library it has. It can tile windows in a myriad of ways, and even float them in unexpected manners. It has per-workspace configuration, so I can have 9 or more workspaces, each with different layout algorithms. I greatly appreciate a program which has allowed me thus far to go through 4 “patterns of usage”. To be more specific, I’ve gone through:

  • The “tall” default configuration. This keeps my “main” (master) window occupying 70% of the screen, and the other windows stacked to the right of the screen. The proportion occupied by the master is adjustable (see screenshot) and so is the number of masters. This is a lot more flexible than it sounds — I can have 4 equal xterms in a few keystrokes, by setting the number of masters to two and the split point at the half of the screen.
  • Three columns. I have tried this briefly for my widescreen laptop, before realising I rarely need to view 3 different source files at once. I’ve also realised I’m greedy with my non-xterm windows, so I prefer Firefox or Evolution to grab the entire width of my screen, which is what brought me to the next iteration.
  • Tabbed windows. I’ve whole-heartedly returned to my first tiling experience (with Ion3) and used Tall and Tabbed exclusively up till, well, today. The general pattern was to stuff a lot of related windows into a single tabbed workspace if I only needed to see one of them at a time. This worked wonders, but I’ve long wanted an extension to it, cue a few hours spent reading and tweaking today. I’m not delusional — I don’t consider my work so important and difficult that I needed to change the perfectly fine configuration I had; changing it was just a lot of fun. If I realise I’ve made a mistake, I’ll just use darcs to change back to my old config.
  • Tall-Tabbed Combo. Today I’ve added a new layout mode to my configuration, partly inspired by David Roundy’s sample. It splits the screen in two, similarly to Tall, and each half of the screen contains tabbed windows. This enables me, for example, to keep half a screen containing a few documents which I can cycle through, and the other half containing code which I clumsily write. I can easily move windows from one half to the other, bar a few hours of getting use to the commands. Of course, “half” is a generic term, since I can resize the two chunks to any proportion. This uses the excellent Layout.Combo and Layout.WindowNavigation extensions, in addition to Layout.Tabbed, Layout.NoBorders, and Layout.PerWorkspace, which I had previously been using.

So, to sum up another probably tl;dr post, xmonad rocks because:

  • I’m immensely productive with it.
  • It’s fun to both configure an use.
  • It’s alive. When I first started using xmonad (which was, mind you, not at its very beginning), many of the extensions I use or have used in the past didn’t even exist.

If you feel like giving it a try, be aware that you need some knowledge of Haskell if you want a custom configuration, but I’m more than happy to help with what limited knowledge I have. A much better place to go if you have a little background is #xmonad on FreeNode.

December 22, 2008 Posted by | functional programming, haskell, linux, school | 2 Comments

A Different Kind of Obscurity

Learning Haskell is probably the hardest thing I’ve tried regarding computers. It requires giving up all previous conceptions about programming and adopting a different, more pragmatic and heavily mathematical approach. I’m currently struggling with basic monads and haven’t even touched on monad transformers, arrows, and who knows what more Haskell has in store for me.

You may be wondering why I find Haskell interesting, despite its initial difficulty to understand (and despite a serious lack of time on my part). The main reason is that, after I have written or otherwise fully understood a code snippet, I frequently find myself seemlessly pausing to admire its elegance and simplicity. I value simplicity above all, and clearly distinguish it from easiness. Haskell is simple in that it is governed by simple and few rules, but it is by no means easy to learn or master. I often find myself asking silly, if not outright stupid, questions on #haskell or #xmonad (both are hosted on the Freenode network). The people there are, however, kind enough not to complain about it.

The `obscurity’ in the tile comes from the difference in Haskell’s syntax, compared to what I have used so far (and continue to use and study). C, C#, Java, Python. I’ve been hyped up about all of these at one time so far, and I still consider C and Python to be useful and not broken. Haskell, however, is different in both philosophy and, inherently, syntax. Programs end up being unusually terse, but pack a lot of meaning in every line of code. I estimate that I can understand about 10% of all the Haskell code, based on what I have seen, but that 10% (maybe even less) I understand into such depths that I can easily explain them to another person, if they have the appropriate prior knowledge. Or at least so I hope.

As to writing programs myself, I’ve stuck to simple ones, emphasizing on understanding the various language features. It’s quite common that a program that I would normally write in an hour in C takes up to one or two days in Haskell (allowing time for daily routine and documentation), but ends up being a lot shorter, clearer and more meaningful than the C version. As such, the obscurity I have mentioned is beneficial — people communicate more efficiently when their language is more precisely defined and they think more efficiently when they needn’t consider underlying details (the last part is valid for all high-level programming languages). Which is not to say Haskell won’t let you touch those details, though.

I also have a code snippet to show off; it is probably inefficient and could easily have been written more elegantly by one with more experience, but I am happy that I made it work. Any suggestions or commentary will be very appreciated. But before the code, the problem (it is taken from my Algorithm Analysis course):

Given an undirected graph G = (V, E) and an integer k \le card(V), find all the complete subgraphs of G that have exactly k elements.

The problem was proved to be NP-Complete, and we solved it using C during a class. Now, the interesting part in implementing it in Haskell was using the Writer monad, something I had never done before. The representation of the graph is by all means faulty (vertices are numbered 1 through nrNodes, there may be pairs containing numbers outside that range, etc.), but the algorithm works for correct input, which is clearly the key element. The terseness and expressiveness of the code still amaze me, although I must reiterate: it’s probably faulty and ugly in the eyes of an expert. The lack of I/O is compensated by excellent interactive support (I use ghci). So, without further ado, the code, in all its (perceived) glory:

import Control.Monad.Writer

data Graph = Graph { nrNodes :: Int, edges :: [(Int, Int)] } deriving Show

isConnected :: Graph -> Int -> Int -> Bool
isConnected g a b = or [(a,b) `elem` (edges g), (b,a) `elem` (edges g), a == b]

isComplete :: Graph -> [Int] -> Bool
isComplete g vs = let
    isConnectedToAll x = all (isConnected g x) vs
  in and (map isConnectedToAll vs)

generateCompleteSubgraphs :: Graph -> Int -> [[Int]]
generateCompleteSubgraphs g k = map reverse $ execWriter $ f 1 []
    f n set
      | n == k+1  = if isComplete g set then tell [set] else return ()
      | otherwise = mapM_ (\x -> f (n+1) (x:set)) (filter (not . (`elem` set)) validChoices)
        where validChoices = if n == 1 then [1..(nrNodes g)] else
                if head set == nrNodes g then [] else [1 + (head set) .. (nrNodes g)]

PS: If anyone knows of a better way to include Haskell source code in WordPress, please let me know.

December 14, 2007 Posted by | functional programming, haskell, programming | , | 3 Comments