This Blog continues on

Monday, November 26, 2012

Building a Haskell web app with Snap: Snap quickstart guide

I'm a Haskell newbie, and it's fun. I thought I'd document my adventures. Starting with my attempt to build a web app.

I could have spent months picking a web framework. There are decent comparisons on the web. I picked Snap, because of the name (and perhaps some advice from a geeky friend of mine). I've written web frameworks (in Python) and the intro to Snap caught my eye. All pretty arbitrary reasons, so let's get started.

First there is a quickstart guide. Great, who doesn't love quickstart guides? It tells me how to install the framework, though that redirects me to another page, but I don't mind. I would have to have Cabal installed, otherwise it wouldn't work. Instead of just plain:

cabal install snap

I do:

cabal install --user --prefix=$HOME snap

Which seems the most convenient way to put things in my ~ tree rather than anywhere on the system. Great it works first time with no dependency issues, conflicts, or compile errors. That's pretty rare, so great start!

I start to follow the quickstart guide. First create a directory, then call:

snap init barebones

This is great too, so we have a utility script to perform basic operations (as any decent web framework should), and by the look of "barebones" it seems that there are multiple possible templates to start from. Another great feature. The guide suggests running

snap init -h

To see the list of templates, and here they are:

snap init [type]

    [type] can be one of:
      default   - A default project using snaplets and heist
      barebones - A barebones project with minimal dependencies
      tutorial  - The literate Haskell tutorial project

So three starter templates, one of which is a tutorial. So, two starter templates: "barebones" and "default". I guess we will use default in the future when writing a real app, with Snaplets. I won't have much cause to write my own templates, I hope, so moving on.

The guide doesn't explain much what it created, but my tree looks like this now:


Pretty much nothing there except Main.hs, which looks like this:

{-# LANGUAGE OverloadedStrings #-}
module Main where

import           Control.Applicative
import           Snap.Core
import           Snap.Util.FileServe
import           Snap.Http.Server

main :: IO ()
main = quickHttpServe site

site :: Snap ()
site =
    ifTop (writeBS "hello world") <|>
    route [ ("foo", writeBS "bar")
          , ("echo/:echoparam", echoHandler)
          ] <|>
    dir "static" (serveDirectory ".")

echoHandler :: Snap ()
echoHandler = do
    param <- getParam "echoparam"
    maybe (writeBS "must specify echo/param in URL")
          writeBS param

I don't understand this code exactly, but like a lot of things in Haskell, I just don't have to (yet! I imagine one day I will), I can just copy the style. It reads nicely though.

  • Some imports
  • A main function that serves the site
  • A site function that returns some Snap, Snap looking like a monad. This is the part that I don't exactly get: <|> anyone?. We are obviously defining routes, and I am guessing there are 3 ways of hitting this site (This is possibly a bit too much information for a quickstart, I might be happier with just the echo handler, but maybe that isn't possible on its own. Doesn't matter though):
    • / (ifTop, I'm guessing for the root) where we just return "hello world"
    • /foo which just returns "bar"
    • /echo/<something> which echoes the something back at us
  • The echo handler itself, which gets the parameter defined in the route and returns it. Not exactly sure what the maybe line is doing here. I guess it is a failure condition, though I am more used to frameworks where a missing echoparam would not match the route and just 404.

Because the snap utility created a cabal file for us (how convenient), I can just install the app with:

cabal install --user --prefix=$HOME

That's right, my app is an executable, now installed, which I can just run. That's pretty awesome, we don't have stuff like that in Python frameworks. I had called my initial directory snaptest and that is how the executable comes out. Let's run it:

$ snaptest -p 8000
Listening on

And here is what we get:

hello world


No handler accepted echo


Great, as we mostly imagined, except I can't make the maybe condition in the echo handler happen, but I don't care much either. After maybe 256 seconds of actual effort and 16 minutes after deciding to write a Haskell web app, I have one.

This is the best quick start experience I have had for any web application framework in any language, so things bode well for the future.

Wednesday, July 25, 2012

Keeping tallies in Python

Python's collections module has some of the most consistently useful collection data structures you will need for everyday programming. Here's one I didn't know about:

collections.Counter (Python 2.7 only!)

It is designed to keep "tallies" or count instances of something. The example will make it all clear:

from collections import Counter
cars = Counter()
# I see one go past, it is red
cars['red'] += 1
# And a green one
cars['blue'] += 1
# etc

This is pretty much like a defaultdict with an integer value, but it is convenient and neat, with some useful constructors. Don't you think?

Thursday, July 19, 2012

Watching a file system directory with inotify and Linux

"Inotify is a Linux kernel subsystem that acts to extend filesystems to notice changes to the filesystem, and report those changes to applications." [Citation Needed]. You can use this service from Python using Twisted to watch a directory and its contents.

Twisted is perfect for this as you likely want to be doing a number of other things at the same time, for example, making an HTTP request every time a change is noticed.

The code is so monstrously simple, I will just paste it:

from twisted.internet import inotify
from twisted.python import filepath

class FileSystemWatcher(object):

  def __init__(self, path_to_watch):
    self.path = path_to_watch

  def Start(self):
    notifier = inotify.INotify()

  def OnChange(self, watch, path, mask):
    print path, 'changed' # or do something else!

if __name__ == '__main__':
  from twisted.internet import reactor
  fs = FileSystemWatcher('/home/ali/tmp')

Incredibly easy, and another example of how awesome Twisted is.

Tuesday, July 17, 2012

Making two instances behave as the same instance in Python

The use-case is this:

# Two instances of the same class
x = A()
y = A()

x in {y: 1} # True

So we want to be able to check an instance's presence inside a dict, set, or anything that hashes an instance for a key.

You need two things:

__hash__ method which returns an integer
__eq__ method which tests equality against another instance and returns a boolean

__hash__ method returns an integer which is used as the hash. I didn't want to invent a hash method, so instead I used the hash of a tuple, which seems a reasonable hashable type to use, but you could use an integer or string or anything. I wanted the tuple contents to be attributes of the instance, with the added side effect that the instance would pass the test:

x is (1, 2) # True

Here it is:

def __hash__(self):
  return hash((, self.age, self.location))

That is not enough though, if you implement __hash__ you must also implement __eq__, which is simple enough:

def __eq__(self, other):
  return hash(self) == hash(other)

Ok that is just a bit cheap, and you could compare the tuple's values directly if you want to. Here is the complete (toy) implementation:

class Person(object):
  def __init__(self, name, age, location): = name
    self.age = age
    self.location = location

  def __hash__(self):
    return hash((, self.age, self.location))

  def __eq__(self, other):
    return hash(self) == hash(other)

Friday, July 06, 2012

Calling the Google Drive API and other Google APIs asynchronously with Twisted

You may know that the Google API Python Client is built on httplib2. This is a reasonable general choice, but the tight coupling is unhelpful in situations where a different HTTP library, or an entirely different approach to network programming should be used. An example of this is Twisted.

Aside: I won't be going on about how awesome Twisted is, but let's just take it for granted that it is so awesome that I could not write this application without it.

Httplib2 is blocking, and that makes it incompatible with being run inside the Twisted reactor. Fortunately we are only the latest person to have this problem, and a solution exists:


api_call = drive.files().list()

def on_list(resp):
  for item in resp['items']:
    print item['title']

d = deferToThread(api_call.execute)

A blocking call will be called in a thread and will callback on the returned deferred when it is done. I appreciate that no one* is 100% happy with this solution. "Argh, threads!", "Argh, async!" But it is a testament to the Greatness of Twisted that it has this sort of facility to play well with other, less flexible, systems.

*Did I mention? I am 100% happy.

Please comment on this post in Google+