[Haskell-cafe] Simple design question using Wai

2011-10-09 Thread Arnaud Bailly
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

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.

Thanks in advance for any insights,

Arnaud

PS: the code is on github: http://github.com/abailly/crete1941. Not that I
deem it ready for prime-time though...
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Simple design question using Wai

2011-10-09 Thread Antoine Latter
On Sun, Oct 9, 2011 at 3:57 PM, Arnaud Bailly arnaud.oq...@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?

Antoine

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Simple design question using Wai

2011-10-09 Thread Arnaud Bailly
Hi Antoine,
Thanks for your interest.

On Sun, Oct 9, 2011 at 11:57 PM, Antoine Latter aslat...@gmail.com wrote:


  interpret :: (CommandIO io, Map t) = Commands t io CommandResult
 

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


More details here :
https://github.com/abailly/crete1941/blob/master/CommandsInterpreter.hs


 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?


Yes, sure. I actually think I over-engineered the whole thing and inverting
the dependency might simplify a lot of things. The signature you provide is
exactly what I was thinking about after posting my mail : simply a
game-features focused request/response conversation wrapped by whatever I/O
is needed.

Arnaud
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe