Archive for Haskell

My First WebApp

There are lots of technologies that I have been investigating recently, with the intent of building something useful. However, it’s hard to figure out if my plan makes sense without trying. So I am going to build a very simple application.

The specification looks like:

The application shall allow the user to send email notes to themselves

I often email short notes to myself as reminders or to capture short pieces of information. The number of steps involved in doing this is too many. I have to address the email, set a subject, navigate one of many email clients and then send. I want to IM myself and have it turn up as email.

My design for building this is a little bit more complex than it really needs to be. This is because the application is an excuse to try building a platform.

There are four pieces:

  1. Taskbar applet to send mail
  2. Web application to send mail
  3. Web service to receieve send mail request
  4. Application service to send mail

The task bar applet is the easy part (see QSystemTrayIcon). That will be built, initially for Windows, using Qt. If I’m enthusiastic, it may support RTF and HTML email as well as unicode text.

The web application, likely to be built last, will use django. I’m considering Ruby on Rails, but given I already know python and django provides sufficient functionality, it is my likely choice.

The web service will be built using the same web framework as the web application. I am trying to reduce the number of technologies a little bit.

The aims of the web service:

  • Provide a publically accessible API.
  • To allow for a flexible URL mapping scheme
  • To provide a REST style API.
  • To easily provide different data formats (XML, JSON).

The application service will be built using Haskell. It will be kept as an internal process. It will likely be built using a web service as well, but using JSON as the transport. I am choosing Haskell mainly to explore options.

After my recent foray into Lisp, I am confident I could build the application service using Lisp, but would prefer to use Haskell. This is partially to avoid paying license fees to Allegro, but mostly as I prefer having the type system of Haskell available. The architecture will allow me to swap back-ends if needed.

That is the plan. Progress and learnings should trickle in over the coming months.

Note: This is an exercise in playing with technology. There is no plan for providing this as a production level service.

Bits and Pieces of Haskell

There are a few threads that I’ve been attempting to unravel that don’t quite justify their own post. However, as each is proving to be very interesting, I’ve gathered them together:

  • Arrows - “Arrows are a new abstract view of computation … [that] serve much the same purpose as monads — providing a common structure for libraries — but are more general.”

    A monad generalises a computation across its output. An arrow generalises computation for both input and output.

    For fun, a Kleisli arrow will lift a monad abstraction to an arrow abstraction, but the interesting arrows are the ones that can’t be made into monads. Essentially, the arrow abstraction is a super-set of monadic abstractions.

    If you want to understand the why of arrows, read [Hug00]. If you want to understand the how of arrows, read [Hug05]

    As usual with Haskell, the interesting bits are in research papers.

  • Software Transactional Memory (STM) - “a quantum step forward from locks and conditionals” in concurrent programming.

    Simon Peyton-Jones and Tim Harris were recently interviewed by Channel 9 on STM. The discussion covers the motivation of STM and outlines the types of problems it solves.

    STM is available today in Haskell, as a GHC extension.

  • Types and Programming Languages - If you have an interest in computational theory and type systems, I cannot recommend this book enough. Autrijus blamed this book for him starting the pugs project.

    I’m only part way through the book, and it is stretching my brain in interesting ways. The benefit is that much of the terminology in research papers in functional programming is becoming more clear.

    I haven’t had this much fun since writing a monadic based lambda calculus parser at uni.

  • Category theory - this is floating around the edges of a number of topics. There are veiled and direct references to how category theory is responsible for concepts such as monads and arrows.

    From [Hug05]:

    Arrows in Haskell are directly inspired by category theory, which in turn is just the theory of arrows — a category is no more than a collection of arrows with certain properties.

    For now, category theory is on my “to read” list, having piqued my interest.

To keep up to date with what it happening in the Haskell community, I highly recommend the Haskell Weekly Report (rss).

Installing HAppS

Update: HAppS 0.8.2 is out, which works with the latest version of FPS. (FPS 0.8 from latest darcs)

HAppS is an application server for Haskell. An initial read of the documentation makes it seem like a very good platform for building web applications.

The inspiration for HAppS has come from frameworks such as Python’s twisted, but with the type safety and speed that Haskell can offer. Initial performance benchmarks look quite promising.

To actually evaluate HAppS, it first needs to be installed. Below is the list of packages that go together to get it running on Mac OS X Tiger.

Versions

  • HAppS (from darcs 2006-08-20) - Haskell App Server
  • FPS 0.5 - Fast Packed String library
  • GHC 6.4.1 for Mac OS X - Haskell compiler
  • Haddock 0.7 - Documentation generator
  • Happy 1.15 - Parser generator system
  • HaXml 1.13.1 - XML library
  • Alex 2.0.1 - Lexical analyser generator
  • cpphs 1.2 - Haskell preprocessor

For Haddock to work you will also need a LaTeX system and the DocBook XSL stylesheets.

Building

GHC installs as a binary package. The remainder of the packages are installed using a reasonably standard configure; build; install process.

Haskell has its own build system, based around Cabal files that list dependencies. Most source packages will include a Setup.hs file and a *.Cabal file.

To invoke the Setup.hs file, use either the runhaskell script or make the Setup.hs file executable (it will then hunt for runhaskell). You need to have /usr/local/bin in your path.


% runhaskell ./Setup.hs configure
% runhaskell ./Setup.hs build
% sudo runhaskell ./Setup.hs install

FPS

The Fast Packed String library allows for fast string manipulation from within Haskell. However, there is a bit of a version problem with HAppS.

  • HAppS 0.8 - needs FPS 0.4 (or earlier)
  • HAppS dev - needs FPS 0.5 (0.7 breaks)

FPS changes its interface between minor versions, thus breaking dependencies for HAppS. It would be good for the HAppS installation to include the list of versions used to build against, or for FPS to use better versioning.

Examples

The example that looks most interesting is httpd.hs. Based on the behavior of http://happs.org/ it appears that they are running this example as base of the site.

In the examples directory, change the import statement for the httpd.hs file as follows:


import Data.ByteString.Char8
--import Data.FastPackedString

Assuming that you are using FPS 0.5 and the development version of HAppS.

The example can then be run from examples/ as follows:


% make
% mkdir HAppS
% echo '<h1>Hello World</h1>' > HAppS/README.html
% ./httpd

Then point Safari to http://localhost:5000/. The example will redirect to the file created above and serve the page.

Joel: The Perils of JavaSchools

Joel Spolsky has an interesting article about the difficulty of identifying an exceptional programmer if they are using Java.

To quote:

The recruiters-who-use-grep, by the way, are ridiculed here, and for good reason. I have never met anyone who can do Scheme, Haskell, and C pointers who can’t pick up Java in two days, and create better Java code than people with five years of experience in Java, but try explaining that to the average HR drone.

Target (redux)

After having spent some of last week solving the Target word problem using Haskell, I thought I might try another language.

C++ is one of those languages that retains low level control and simple machine semantics while providing high abstraction levels. The first language I learnt, it is also the one I’ve used the most. I usually skip it for attempting to understand an algorithmic problem, but once the algorithm is well understood it can make a big speed difference.

As I’ve been pondering this from a productivity point of view, the interesting bit is how I approached the problem. Fortunately, C++ includes pseudo functional constructs via the STL. This meant that I could keep a reasonable level of abstraction. Loops replaced recursion, as it is technically possible to use recursion in C++, it just doesn’t feel right.

The time spent building the C++ version was around the same time as for the Haskell version. When run against a large dictionary of words (234937), the Haskell version took around 4.5 seconds, with the C++ version taking just less than a second.

I believe there is still some optimisation space left in both programs.

Given a similar problem, I would pick Haskell to explore, even with a slower result. For some reason, it was more fun to program against.

To continue this, I’m going to pick a trickier problem and try implementation in multiple languages. In theory, there is a Cocoa to Haskell binding …

For future reference, my code looks like:


#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <set>

using namespace std;

bool containsWord(char const&, string const&, string const&);
bool includesAllLetters(string const &, string const &);

int main(int argc, char** argv) {
    string from, word;
    char letter;

    if(argc < 4) {
        cout << "usage: mainChar allLetters wordListn";
        return 0;
    }

    letter = argv[1][0];
    word = argv[2];
    from = argv[3];

    ifstream is(from.c_str());
    istream_iterator<string> ii(is), eos;

    int count = 0;
    vector<string> targets;
    cout << "Words: ";
    for( ; ii != eos; ++ii)
        if(containsWord(letter, word, *ii)) {
            cout << *ii << " ";
            ++count;
            if(word.length() == (*ii).length()) targets.push_back(*ii);
        }
    cout << "n";
    cout << "Found " << count << " words.n";

    cout << "Targets: ";
    for(vector<string>::iterator p = targets.begin(); p!=targets.end(); ++p)
        cout << *p << " ";
    cout << "n";

    return !is.eof();
}

bool containsWord(char const& c, string const &word, string const &testWord) {
    if(testWord.length() < 4 || testWord.length() > word.length() || testWord.find(c) == testWord.npos) return false;

    if(includesAllLetters(word, testWord)) return true;

    return false;
}

bool includesAllLetters(string const &word, string const &testWord) {
    string letters(word);
    for(string::const_iterator p = testWord.begin(); p !=testWord.end(); ++p) {
        size_t loc = letters.find(*p);
        if(loc == letters.npos)
            return false;
        else
            letters.erase(loc, 1);
    }
    return true;
}