Posts

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 <- liftM (M.lookup name) ask
liftM2 (==) (liftM password u) (return pass)
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 th…

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 …

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 se…

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 =<< ask
>
> askSessions::MonadReader State m => m (Sessions SessionData)
> askSessions = return . session…

Update: A demo of the finished application is now available. See this post for more information.This post is written in literate haskell, so it should compile as-is
in a .lhs file.In my last article on HAppS, I gave a brief introduction to working
with the HAppS web server to serve a basic user login/registration
page and handle the form submission. In this article we are going to
develop the framework for basic session management. The example file
AllIn.hs in the HAppS source tree is very similar to this. I have
made a few changes to demonstrate some different cases that one might
encounter. So without further ado, we'll start with our standard
import statements.
> {-# OPTIONS -fglasgow-exts #-}
> {-# LANGUAGE TemplateHaskell , FlexibleInstances,
> UndecidableInstances, OverlappingInstances,
> MultiParamTypeClasses, GeneralizedNewtypeDeriving #-}
>
> module Session where
>
> import qualified Data.Map as M
> import Contro…

Update: A demo of the finished application is now available. See this post for more information.This post is the first in a series outlining the process I am taking to get
a basic stateful web application working with the Haskell web framework HAppS.
There is very little documentation available for versions of HAppS after
0.8.8. While this is not documentation, it should aid in getting an idea of
how HAppS manages state. The code in these posts should work with HAppS 0.9.2.For this application, we'll focus on the basic capabilities needed for user
creation, authentication, and session management. The first thing we need is a
form for logging in or creating a new user, and two URLs to handle the
submission of these forms. Well use /login for the form, and we'll have the
login form POST to the same place. The registration form will POST to
/newuser. All other pages will return an error. Here is the basic HAppS code
to do that:
impl = [ dir "login" [methodSP GE…