I'm using Happstack to receive some parameters from an HTTP request then pass these parameters to a function that will retrieve data from the database and return this data in the HTTP response as follow:
myFunc :: IO String
myFunc = do r <- look "personId"
conn <- connectODBC "... my connection string ...";
vals <- quickQuery conn ("SELECT Name FROM Person where Id = ?") [(toSql r)];
return (processData vals)
handlers :: ServerPartT IO Response
handlers = do
x <- liftIO (myFunc);
decodeBody (defaultBodyPolicy "/tmp/" 0 1000 1000)
msum [
dir "getData" $ ok $ toResponse x
, ... other handlers ...
]
mainFunc = simpleHTTP nullConf handlers
But when I build the above code I get the following error:
No instance for (HasRqData IO) arising from a use of `look' In a stmt of a 'do' block: r <- look "personId"
After reading questions on similar issues (like this one) I think I have to include HasRqData constraint somewhere, but I couldn't learn where and how.
As you may have guessed, this is too an issue with monads. There are a handful of them in
happstack(HasRqData, among others), so you may well consider it a complicated case.Let us begin with the innocent-looking
lookfunction.Indeed, there is a non-trivial constraint
HasRqData. Let us ask ourselves: what monads HaveRqData? (It so happens thatIOhas not!)The other instances are derivative of these first two, so, it looks like we have to consider these two options first.
RqDatahas limited effects — you can only dolookand its derivatives, extracting information from the request at hand. As we want to also have other effects — querying the database, for one, — this is not enough for us.ServerPartT mis the general form of the same old friend of ours,ServerPart ≡ ServerPartT IO. It happens that it alsoHasRqData. This is not a coincidence, but rather an implication of the design ofhappstack— looks like the authors meant us to use this single monad everywhere, unless we need particular granularity. So, let's give it a try.This compiles.
Now, we don't even need to lift
myFuncinhandlers— our previous predicament solved itself. We will need to lift our access to the database though, by the same jar logic we discussed before.I believe you can figure the details by yourself. In any case, let me know how it works out!