[Haskell-cafe] Simple design question using Wai

Antoine Latter aslatter at gmail.com
Sun Oct 9 23:57:51 CEST 2011

On Sun, Oct 9, 2011 at 3:57 PM, Arnaud Bailly <arnaud.oqube at gmail.com> wrote:
> Hello,
> I am trying to move a web application I wrote that initially used raw
> sockets for doing HTTP by "hand" to a more sensible Wai-based framework, and
> I am running into a design issue.
> I initially thought it would be a good idea to be able to support various
> I/O methods so I defined a layer called CommandIO (this is a game
> application) to insulate business-level code from the detials of reading
> commands and outputting results to the outside world. Here is the signature
> for this simple monad:
> class (Monad io) => CommandIO io where
>    readCommand :: io Command
>    writeResult      :: CommandResult -> io ()
> then I have an interpret function which looks like:
> interpret :: (CommandIO io, Map t) => Commands t io CommandResult

What is the 'Commands' type? What is the 'Map' class?

> which reads a command from the io, execute it producing a CommandResult,
> then request output from the io using writeResult.
> This works nicely using Reader-based data containing a Handle, both for
> HTTP-based and console-based I/O.
> But when I try to move to WAI, I am a little bit stuck. The core of Wai is
> an application which rougly has type Request -> Response and this basically
> breaks my (simple) model of read commands / write results. I suspect there
> might be a way to stick to my current model using enumerators/streams for
> I/O and a custom type for encapsulating the underlying state of the HTTP
> exchange. I also thought about reversing the dependency : ensuring that
> interpret does not need to know about low-level I/O and only dealing with
> Command/CommandResult, with I/O being handled by wrappers.

Your type class as written doesn't appear to work too well for HTTP -
what would happen if I called 'readCommand' twice? Or called
'writeResult' before receiving a command?

HTTP is, at its core, a server which responds to a single request with
a single response. The WAI type reflects in a way that makes it hard
to do wrong.

This doesn't work because the API you want to provide makes it
possible to do wrong.

Your class might be able to fit into WAI if each back-end provided a
single function:

> execute :: (Command -> io CommandResult) -> io ()

This should make sense for console, Handle-based and HTTP.

Am I on the right track?


More information about the Haskell-Cafe mailing list