Hi I have a piece of code where I retrieving a Maybe User where User is my own type.
getUserById :: Int -> IO (Maybe User)
getUserById id = let userId = id in do
conn <- createConnection
(columnDef, inputStream) <- query conn selectByIdQuery [One $ MySQLInt32 (intToInt32 userId)]
maybeMySQLValue <- Streams.read inputStream
return (transformToUser <$> maybeMySQLValue)
But the key is that the function that call this functions expect a IO User and not a IO Maybe User
getUserById :: Int -> IO User
Any advice about how to extract in the do block the value from the Maybe?
I´m trying this but still does not work
user <- extractMaybeUser (transformToUser <$> maybeMySQLValue)
return user
extractMaybeUser :: Maybe User -> User
extractMaybeUser maybeUser = case maybeUser of
Just value -> value
Nothing -> User 1 "default User"
Regards
user <- extractMaybeUser (transformToUser <$> maybeMySQLValue)
The reason why this code might not work is that extractMaybeUser has return type of User:
extractMaybeUser :: Maybe User -> User
There is no monadic value to extract from using <-, so what about just wrapping in IO the user we get from extractMaybeUser?
return (extractMaybeUser (transformToUser <$> maybeMySQLValue))
It will at least have IO User type
Related
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
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
I'm new to Haskell so apologies in advance for the potentially stupid question.
I'd like to build a data structure that is constructed from two http requests in my application.
My first request gets a basic list of users which I could choose to decode to Maybe [User]
r <- getWith opts "https://www.example.com/users"
let users = decode $ r ^. responseBody :: Maybe [User]
But if I'd like to enrich my user data by calling a second endpoint for each of the users that respond by doing something like
r2 <- getWth opts "https://www.example.com/users/{userid}/addresses"
let enrichedUser = decode $ r2 ^. responseBody :: Maybe EnrichedUser
I can't quite piece these parts together at the minute. I'm in a do block thats expecting an IO ()
Any help would be appreciated!
I'm assuming that the type of enrichedUser is supposed to be Maybe EnrichedUser and not Maybe [EnrichedUser], right?
If so, after extracting the [User] list from users :: Maybe [User], the problem you're facing is running a monadic action (to fetch the web page) for each User. There's a handy combinator for this in Control.Monad:
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
which can be specialized in your situation to:
mapM :: (User -> IO EnrichedUser) -> ([User] -> IO [EnrichedUser])
This says, if you know how to write a function that takes a User and creates an IO action that will create an EnrichedUser, you can use mapM to turn this into a function that takes a list [User] and creates an IO action to create a whole list [EnrichedUser].
In your application, I imagine the former function would look something like:
enrich :: User -> IO EnrichedUser
enrich u = do
let opts = ...
let url = "https://www.example.com/users/"
++ userToUserID u ++ "/addresses"
r2 <- getWith opts url
let Just enrichedUser = decode $ r2 ^. responseBody
return enrichedUser
where decode = ...
and then you can write (in your IO do-block):
r <- getWith opts "https://www.example.com/users"
let Just users = decode $ r ^. responseBody
enrichedUsers <- mapM enrich users
-- here, enrichedUsers :: [EnrichedUser]
...etc...
I've omitted the Maybe processing here for simplicity. If enriching fails, you probably want to somehow coerce a regular User into a default EnrichedUser anyway, so you'd modify the bottom of the enrich function to read:
let enrichedUser = case decode $ r2 ^. responseBody of
Nothing -> defaultEnrichment u
Just e -> e
return enrichedUser
and everything else would stay the same.
I'm trying to use persistent-postgresql with servant.
I have a User model.
I want to have an endpoint that takes an id and returns the user with that id.
According to other answers I can use toSqlKey to turn an Int64 into a Key to feed to get.
My function looks like:
oneUser :: Int64 -> App (Entity User)
oneUser userId = do
maybeUser <- runDb $ get $ toSqlKey userId
case maybeUser of
Nothing ->
throwError err404
Just user ->
return user
When I try to compile I get the error Couldn't match expected type ‘PersistEntityBackend (Entity User)’ with actual type ‘SqlBackend’
Use of selectList works fine.
allUsers :: App [Entity User]
allUsers = runDb $ selectList [] []
Please tell me what I'm doing wrong and where I should look in the future for stuff like this. I couldn't find get on hackage/the right version of the library on stackage etc.
runDb looks like:
runDb :: (MonadReader Config m, MonadIO m) => SqlPersistT IO b -> m b
runDb query = do
pool <- asks getPool
liftIO $ runSqlPool query pool
taken from this github project.
The difference is that get ... returns a plain User not an Entity User, so this will work:
altSingleUser :: Int64 -> App User
altSingleUser userid = do
let foo = get (toSqlKey userid) :: SqlPersistT IO (Maybe User)
maybeUser <- runDb $ foo
case maybeUser of
Nothing ->
throwError err404
Just person ->
return person
If you want to return an Entity User, just change the last return statement to:
return $ Entity { entityKey = toSqlKey userid, entityVal = person }
I have a function, target say, which demands a parameter of type
target :: Action m UserId -> something
where m is any monad.
I acquire the parameter from an existing function, call it "func"
func :: something -> Action m UserId
to which I wish to retrofit an ErrorT transformer
func :: something -> ErrorT String (Action m) UserId
When I use runErrorT on func in order to extract the successful/failed result, I of course get a result of type
Action m (Either String UserId)
I.e. the either representing success or failure is embedded in the surrounding monad. This is great for some purposes e.g. testing for left and right in the context of the Action monad.
What I really need is a version of runErrorT which returns
Either String (Action m UserId)
because then I could just take the Right value and use it. What do I do in these circumstances? Alternatively is there a clever way of rejigging
Action m (Either String UserId) -> Either String (Action m UserId)
but where I don't have access to the necessary constructor
UserId -> Action m UserId
since it so happens that Action is itself a transformer
type Action = ReaderT MongoDBContext
Let's say you have
func :: a -> ErrorT String (Action m) UserId
target :: Action m UserId -> b
Then
run :: a -> Action m (Either String b)
run a = do
result <- runErrorT $ func a
return $ case result of
Left str -> Left str
Right uid -> Right $ target (return uid)
Or more succinctly
run = runErrorT . fmap (target . return) . func
In general, this can't be done without knowledge of the specific m. For example, this is no function of type IO (Either String Int) -> Either String (IO Int) that doesn't use unsafePerformIO or something like that.
You can write something like:
dupNoEx :: IO (Either String Int) -> IO (Either String (IO Int))
dupNoEx act = do
ev <- act
case v of
Left s -> return $ Left s
Right i -> return . Right $ return i
but, I don't know how valuable it might be.
I got trouble with ambiguous type when developing web app with Snap.
My code is
getUserByUsrnamePwd :: Handler HaskellCalendar HaskellCalendar ()
getUserByUsrnamePwd = do
username <- getPostParam "username"
password <- getPostParam "password"
user <- query_ "SELECT * FROM users WHERE username = ? AND password = ?" (username, password)
liftIO $ print (user :: [User])
I got an error
Expected type: (Maybe ByteString, Maybe ByteString)
-> Handler HaskellCalendar HaskellCalendar [User]
Actual type: (Maybe ByteString, Maybe ByteString) -> [r0]
I really don't know why because according to API it should be (Maybe ByteString, Maybe ByteString) rather than (Maybe ByteString, Maybe ByteString) -> [r0]
Kind Regards
Judging by the documentation, it looks like query_ is only for queries that take no parameters. You want query.