Search code examples
haskellscotty

Do block resolve types


I just start coding in Haskell recently and I start getting use of do block. I'm coming from Scala world, and after read a book and some blogs I see that do block was the inspiration of our from comprehension. But still I´m struggling with the arguments that pass in every function as input -> output

Here in my code I'm using scotty http server library to get a request and I'm trying to persist that request in mySQL.

But in this line where I try top get the value from the Maybe to send to the another function to be persisted

user <- (fmap (\user -> insertUser user) maybeUser)

It never compile since the function does not return the expected type

ActionT Text IO (Maybe User)

but

IO User

Here my hole program

createUser :: ActionM ()
createUser =  do maybeUser <- getUserParam
                          -- Persist the user
                          _ <- persistUser
                          json maybeUser

getUserParam :: ActionT Text IO (Maybe User)
getUserParam = do requestBody <- body
                  return (decode requestBody)

persistUser :: Maybe User -> ActionT Text IO (Maybe User)
persistUser _maybeUser = let maybeUser = _maybeUser in do
                           user <- maybeUser
                           user <- (fmap (\user -> insertUser user) maybeUser)
                           return maybeUser

insertUser :: User -> IO User
insertUser _user = let user = _user in do
    conn <- createConnection
    status <- execute conn insertUserQuery [MySQLInt32 (intToInt32 $ getUserId user), MySQLText "hello_haskell_world"]
    return user

Solution

  • Let's consider the following function:

    persistUser :: Maybe User -> ActionT Text IO (Maybe User)
    

    A value of type Maybe User is passed as an argument, and we need this user to be inserted into database. In order to do that, we can use (<$>) (or fmap) function as:

    insertUser <$> maybeUser
    

    The resulting type is: Maybe (IO User). Now we need to lift this type to ActionT Text IO (Maybe User) somehow.

    Web.Scotty.Trans has a liftAndCatchIO function (also available in Web.Scotty module), which mostly does what we need, but it accepts IO a as an argument, so we need to "swap" Maybe and IO. Let's find a function for this. So sequence does what we need.

    As a result, we have the following implementation of persistUser function:

    persistUser maybeUser =
        liftAndCatchIO $ sequence $ insertUser <$> maybeUser