I am learning Haskell, and I'm trying to learn the happstack server as well.
I am following the guide at http://happstack.com/docs/crashcourse/index.html#matching-on-request-method-get-post-etc , and their usage of the 'dir' and 'method' functions isn't working in my case.
I am trying to split up the routing sections into helper functions for my sanity, by I am having a hard time understanding how to properly handle the return types in regards to do blocks, the unit ('()') type, and monads.
The repository for my learner project isn't public yet, so I will paste the relevant code in it's entirety here.
EDIT: the below code is using tabs for indentation
main :: IO ()
--main = simpleHTTP nullConf $ ok "Hello, Haskell!!!"
main = simpleHTTP nullConf $ msum
[
dir "signup" $ serveFile (asContentType "text/html") "static/index.html",
dir "static" $ serveDirectory DisableBrowsing [] "static",
dir "api" api
--do dir "account" $ ok $ toResponse "account page",
--do dir "welcome" $ ok $ toResponse "welcome page",
----dir "api" $ ok $ toResponse "api endpoint",
----do dir "api" $ dir "person" (do method PUT
---- ok $ toResponse "api/person"),
--(do dir "api" $ apiRouting),
--do dir "static" $ serveDirectory DisableBrowsing [] "static"
----seeOther "welcome" ""
]
--apiRouting :: (ToMessage a) => ServerPartT IO a
--apiRouting = do
-- dir "person" (do method PUT ok $ toResponse "api/person")
--personHandler :: ServerPartT IO String
--personHandler = return (method PUT (return ok $ toResponse "api/person"))
api :: ServerPartT IO Response
api = msum
[
dir "person" person
]
person :: ServerPartT IO Response
-- this works
-- person = ok $ toResponse "api/person"
--so does this
--person = msum
-- [
-- ok $ toResponse "api/person"
-- ]
person = msum
[
--so, method PUT does nothing besides control which code branch is ran, based on the request
--that is why the happstack tutorial was using do notation
--but for some reason, do notation did not work when I tried it
--if it was because of whitespace or indentation, that's just silly
--this is the same as the happstack guide, doesn't work because "Couldn't match type ‘()’ with ‘Response -> ServerPartT IO Response’"
(do method PUT
ok $ toResponse "api/person put")
--this works and I think this syntax is nicer, but why does the do block not work?
--the thing1 >> thing2 operator does thing1, ignores any return value it might have had, and then returns the result of thing2
--method PUT >> (ok $ toResponse "api/person put")
]
for some reason, the do method PUT way does not work, but the '>>' way does.
I was afraid that the do block wasn't returning what I wanted it to, so I tried to use the 'return' statement, but to no avail.
In the Happstack guide, it looks like this:
main :: IO ()
main = simpleHTTP nullConf $ msum
[ do dir "foo" $ do method GET
ok $ "You did a GET request on /foo\n"
, do method GET
ok $ "You did a GET request.\n"
, do method POST
ok $ "You did a POST request.\n"
]
I've tried things like below, but it doesn't work.
person = msum
[
--so, method PUT does nothing besides control which code branch is ran, based on the request
--that is why the happstack tutorial was using do notation
--but for some reason, do notation did not work when I tried it
--if it was because of whitespace or indentation, that's just silly
--this is the same as the happstack guide, doesn't work because "Couldn't match type ‘()’ with ‘Response -> ServerPartT IO Response’"
do method PUT
(return (ok $ toResponse "api/person put"))
--this works and I think this syntax is nicer, but why does the do block not work?
--the thing1 >> thing2 operator does thing1, ignores any return value it might have had, and then returns the result of thing2
--method PUT >> (ok $ toResponse "api/person put")
]
I thought that do blocks return the result of their last statement, but from the error message it looks like the 'do method PUT' part is just returning '()', which I understand to be similar to the void or unit types in other languages.
I am working my way through Learn You A Haskell, but when I try and do some hands-on learning like this I run into a bunch of gotchas.
EDIT: entire compiler error
web/app/Main.hs:72:20: error:
• Couldn't match type ‘()’ with ‘ServerPartT IO Response’
Expected: m0 (m1 Response) -> ServerPartT IO Response
Actual: m0 (m1 Response) -> ()
• In the result of a function call
In a stmt of a 'do' block:
method PUT (return (ok $ toResponse "api/person put"))
In the expression:
do method PUT (return (ok $ toResponse "api/person put"))
|
72 | do method PUT
Causes the error:
because the indentation in the do block is incorrect. The 'return' keyword here is incorrect, as well.
The alignment rules of a 'do' block are such that the first character of the first word after the 'do' block becomes the column value that all subsequent lines of the do block must be aligned with.
Because the 'm' in 'method' did not line up with the second statement in the do block,
the do block actually only contained the contents. EDIT: The too indented line was actually being interpreted as a continuation of thedo method PUT
method PUT
expression, becomingdo method PUT (return (ok $ toResponse "api/person put"))
Thanks, Ben!The Happstack 'method' function has the return type
, so the value that the do block "returned" ended up just being m (), causing the error.
If you use tabs instead of spaces, it is necessary to place the first keyword after a statement that creates a block, like 'do', on a new line.
EDIT: read this too
An example from the wikibook is as follows, and an alternative way of solving these white-space related issues would be to use the curly bracket and semicolon syntax: