Posts

Happstack: An Interview with Matthew Elder

HAppS development has been all but stopped for almost a year (as have my posts about it). Recently Matthew Elder took up the flag with a new project called Happstack . I thought this would be a good time to catch up with Matthew and find out why he is doing this and where he is going with it. So without further ado, here is Matthew Elder on Happstack. Is Happstack a fork or a rename? Happstack is both a fork and a rename :) But it is not a fork in the traditional sense -- the original code in Lemmih's words (the only active developer left) is orphaned. So even though we are forking the code base to a new repository under the name "Happstack", the original project is not being worked on so it is more of a direction change than a fork. Why are you trying to take over? What happened to the previous developers? The previous developers tapered off over the last year and the only one left is Lemmih. I started out by submitting a couple of patches -- nothing fancy -- just ...

To Template Or Not To Template

Since developing the tutorial in the last few posts, I have been working on developing a real web app in Haskell with HAppS. Now that I know my way around the basics of HAppS, I need to move on to generating actual HTML (as opposed to the plaint text messages that the tutorial used). Before starting, I had to decide what methodology I would use to generate the HTML. I'm new to web development, so I may be missing something, but as I see it there are three main possibilities: Serve static pages that use AJAX to load dynamic content Dynamically generate pages with Haskell and HAppS Use Haskell to populate static page templates with dynamic content Let's first take a look at the last option, static templates. Most of the web frameworks that I've seen (ROR and several Python frameworks) use templates. The main argument for them seems to be that templates allow a separation (MVC style) of the view and controller. The page template defines the view and the Python c...

HAppS Demo

Several people requested that I post a link to a running instance of the HAppS code that I developed here over several posts. One person was nice enough to actually offer me the use of a server. So the demo is now up and running. It's not at all meant to be user friendly, since it's just a demo of the basic HAppS capabilities. So here are a list of links that are useful. http://happs.dnspass.com:8001/login - A login page where you can create a new user or log in. http://happs.dnspass.com:8001/view - A page that shows you what user you are logged in as. http://happs.dnspass.com:8001/list - A page that displays a list of all the users in the system. Hopefully this will be useful.

How I Learned to Stop Worrying And Love Haskell's Type Inference

In developing the HAppS example that I have been posting here, I came upon a problem that gave me new insight to Haskell. I don't think it was a particularly deep insight, but it is significant to me as someone new to the language, and new to type inference. Consider a user authentication function that retrieves a map from the reader monad, looks up a username, and compares the password retrieved with a passed in parameter. I first implemented this function something like this: data User = User { username :: String, password :: String } authUser name pass = do u In the process of getting there, I stumbled around rearranging and inserting various liftM calls until I finally got it to work. Many of the reasons behind the type errors still seemed like voodoo to me. And my haphazard approach to fixing them is evident looking at the code. The problem with this function is how it behaves when the username does not exist in the map. A look at the lo...

Transactional Integrity Problem

An astute reader pointed out that there is a transactional integrity problem with the HAppS application built over the last 4 posts. The function checkAndAdd in Finished HAppS Application contains a call to "query $ IsUser" as well as a call to "update $ AddUser". This violates that ACID guarantee that was desired from the checkAndAdd function. If two people simultaneously try to create the same username, it's possible that both of them could get past the "query" and "if exists" statements before either of the "update AddUser" statements are executed. In this case, both of the AddUser updates would succeed and both users would think their account was created. But if they had the same username, then first one would be overwritten by the second one. The second user wouldn't notice a problem, but the first user would not be able to log in to the newly created account because his password would probably be different from the ...

Finished HAppS Application

Update: Due to popular demand, I put the plain haskell code for this app on hpaste.org. Here are links for Session.hs , Main.hs , and login.html . The past three posts have laid the groundwork for a full HAppS web app. We have built the infrastructure for an authentication system that can store usernames and passwords as well as the session IDs for active sessions. Here we will tie everything together to make a functional web app. It should all compile with HAppS 0.9.2. Let's get the imports out of the way. > {-# OPTIONS -fglasgow-exts #-} > {-# LANGUAGE TemplateHaskell , FlexibleInstances, > UndecidableInstances, OverlappingInstances, > MultiParamTypeClasses, GeneralizedNewtypeDeriving #-} > > module Main where > > import Control.Concurrent > import Control.Monad > import HAppS.Server > import HAppS.State > > import Session --The session and state code already developed In the first post, we created code to...

Using HAppS-State

Update: A demo of the finished application is now available. See this post for more information. In the last post, I outlined the requirements for making a data type an instance of Component. This is great, but not very useful without a mechanism for accessing the state data. HAppS persists its state by storing functions that operate on the state. This requires a way to serialize the functions. HAppS does this for you with the TemplateHaskell function mkMethods. So how does this affect you? Your functions that manipulate state must be either Update or Query functions. Update functions use the State monad, and Query functions use the Reader monad. First we'll set up some convenience functions that will be used to construct the actual Query and Update functions. > askUsers :: MonadReader State m => m (M.Map String User) > askUsers = return . users = > askSessions::MonadReader State m => m (Sessions SessionData) > askSessions = return . sessions = ...