Haskell Snap: Executing an IO action within a handler? - haskell

Say, I have a random DB function in my separate DB.hs file.
Something like this:
savePerson :: Person -> IO ()
savePerson p = do
c <- connect
run c "INSERT INTO persons (name, age) \
\VALUES (?, ?)"
[toSql (personName p), toSql (personAge p)]
commit c
disconnect c
return ()
Now, how do I execute this functions within my handler in Site.hs if I import my DB.hs?
If I simply stick it in my handler like this(this is just an example):
insertPerson = do
par <- getPostParams
let p = toPerson par
savePerson p
return ()
where
toPerson m =
Person {personName = head (m ! (B.pack "name"))
,personAge = read (B.unpack (head (m ! (B.pack "age")))) :: Int
}
This does not work. I dont want the handler to return anything, I just want it to save the Person and not return/render anything.
What is the correct way of doing it?
Thanks.

Your problem seems to be that you do not understand what the unit type and value are about.
The unit type is a special built-in type called "()", which has exactly one value, also called "()".
So for instance I can create a list of 4 units, which is of type "list of units".
fourUnits :: [()]
fourUnits = [(), (), (), ()]
The unit type is used where we don't want to have any other information. So technically the type "IO ()" is the type of an IO action that gives the unit value.
A "do" clause unsugars to a chain of ">>=" invocations. ">>=" has the type
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
In other words, the type of a "do" clause is the type returned by its last action.
So where you say
savePerson p
return ()
the "return ()" is spurious because it has exactly the same type as "savePerson p".
Remember that "return" has nothing to do with flow of control: it is merely a function with the type
return :: (Monad m) => a -> m a
It would have been better called "wrap" or "inject" or something similar to avoid this confusion.

Related

How to add Mask to a monadic stack

I am trying to use the bracket function from Exception.Safe Package which has a return type of
forall m a b c. MonadMask m => m a -> (a -> m b) -> (a -> m c) -> m c
This implies that my monad stack must have the Mask monad added to the stack ?
My calling function looks like this
sendMessage :: String -> Config.KafkaP (Either KafkaError ())
sendMessage msg=do
getProperties <- producerProps
let
mkProducer = newProducer getProperties
clProducer (Left _) = return ()
clProducer (Right prod) = closeProducer prod
runHandler (Left err) = return $ Left err
runHandler (Right prod) = messageSender prod msg
res <- bracket mkProducer clProducer runHandler
return res
And config.KakfaP has the type
ReaderT ProducerConfig IO a
And the error I get is ,
No instance for (exceptions-0.10.0:Control.Monad.Catch.MonadMask
Config.KafkaP)
arising from a use of ‘bracket’
Does this mean the monad stack needs to be something like this
Mask (ReaderT ProducerConfig IO a)
Ideally I would want the function to return what the run Handler returns which is Config.KafkaP (Either KafkaError ()) ,or anything more robust .
Adding a solution based on an answer
sendMessage :: String -> Config.KafkaP (Either KafkaError ())
sendMessage msg=do
getProperties <- producerProps
let
mkProducer = newProducer getProperties
--newProducer :: MonadIO m => ProducerProperties -> m (Either KafkaError KafkaProducer)
--mkProducer :: Config.KafkaP (Either KafkaError KafkaProducer)
clProducer (Left _) = return ()
clProducer (Right prod) = closeProducer prod
--closeProducer :: MonadIO m => KafkaProducer -> m ()
--clProducer :: Config.KafkaP (Either () ()) -- ??
runHandler (Left err) = return $ Left err
runHandler (Right prod) = messageSender prod msg
--messageSender :: KafkaProducer -> String -> Config.KafkaP (Either KafkaError ())
--runHandler :: Config.KafkaP (Either KafkaError ()) -- ??
Config.KafkaP $ bracket (Config.runK mkProducer) (Config.runK .clProducer) (Config.runK .runHandler)
If you were using the type ReaderT ProducerConfig IO a directly, there wouldn't be a problem, because the exceptions package provides an instance
MonadMask IO
That says you can use bracket with IO, and another instance
MonadMask m => MonadMask (ReaderT r m)
That says that if the base monad is an instance of MonadMask, then ReaderT over that monad is also an instance of MonadMask.
Notice that MonadMask is not a transformer that is part of the monad stack. Instead, it is a constraint that says "this monad stack supports masking / bracketing operations".
If you were using a type synonym like
type KafkaP a = ReaderT ProducerConfig IO a
there wouldn't be a problem either, because type synonyms don't create a new type, they just give an alias to an exiting one. One can still make use of all the existing typeclass instances for the type.
You mention in the comments that KafkaP is a newtype. A newtype is a cheap way of creating, well, a new type out of another. It's basically a constructor that holds a value of the original type.
And that's the problem. Because it is a new type, it doesn't share automatically all the typeclass instances of the old one. In fact, having different typeclass instances in newtypes is one of the main motivations for using newtypes!
What can be done? Well, supposing the newtype constructor is exported (sometimes they are hidden for purposes of encapsulation) you could unwrap the KafkaPs actions into ReaderT ProducerConfig IO a before sending them into bracket, and then re-wrap the result into KafkaP again. Some of the parameters are KafkaP-returning functions, so you'll probably need to throw in some function composition as well. Perhaps something like (assuming KafkaP is the name of the constructor, and runKafkaP the name of the corresponding accessor):
KafkaP $ bracket (runKafkaP mkProducer) (runKafkaP . clProducer) (runKafkaP . runHandler)
All this wrapping and unwrapping is tedious; sometimes using coerce from Data.Coerce can help. But this only works when the newtype constructor is exported.
You might also think of defining your own MonadMask instance for KafkaP using the technique above. This can be done, but instances which are defined neither in the module that defines the typeclass nor in the module that defines the type are called orphan instances and are somewhat frowned upon.

How to deal with a monadic return value `m (Maybe Foo)`?

I have a function which returns a value wrapped in a Monad,
produceMessage :: MonadIO m => KafkaProducer -> ProducerRecord -> m (Maybe KafkaError)
And I have some code to call this function like so
err <- produceMessage prod message
return $ Right ()
The above code has been written by someone else, I am just trying to understand what is happening here. This is the rest of the function
messageSender :: KafkaProducer -> String -> Config.KafkaP (Either KafkaError ())
messageSender prod msg = do
message <- mkMessage Nothing (Just $ pack msg)
err <- produceMessage prod message
--forM_ err print
return $ Right ()
I have three specific questions,
I am confused what does the type signature of produceMessage mean? The type constraint is MonadIO m, what does this mean?
The return type is m (Maybe KafkaError), so this returns a Maybe value wrapped in which monad?
How does Right () come into picture here? In general I am really not
able to understand the last two lines of messageSender.
The type constraint means that the function can be used to return a value for any type m that has a MonadIO instance. Typically, that means IO itself or a monad stack built on top of IO.
The value returned by produceMessage is in part determined by the caller. Need an IO (Maybe KafkaError) value? You can get that, because IO has a MonadIO instance. Need a MyCustomMonadStack (Maybe KafkaError)? You can get that, if you define a MonadIO instance for MyCustomMonadStack.
Presumably, Config.KafkaP also has a MonadIO instance, based on how messageSender uses produceMessage.
messageSender has a return value of Config.KafkaP (Either KafkaError ()). The expression return $ Right () first uses Right () to produce a value of type Either KafkaError (), then return is applied to that to produce a value of type Config.KafkaP (Either KafkaError ()). Note that the commented line -- forM_ err print is the only thing that might have used the value coming from produceMessage, so right now messageSender pretends that produceMessage worked, whether it did or not.
A more robust definition would actually use the return value of produceMessage in some way, perhaps like
err <- produceMessage prod message
return $ case err of
Nothing -> Right ()
Just theError -> Left theError

Haskell: Pattern matching with named fields

I got ReaderT from Control.Monad.Reader:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
and Action from Database.MongoDB.Query:
type Action = ReaderT MongoContext
Query functions of MongoDB are something like this:
delete :: MonadIO m => Selection -> Action m ()
I'm trying to use pattern mathing with Action m () to check if it is Action IO () or Action _ ()
A simple case like this
case x of
Action IO () -> True
Action _ () -> False
doesn't work, because Action is not a data constructor. Probably I should use something like this:
case x of
ReaderT MongoContext IO () -> True
ReaderT MongoContext _ () -> False
But then I get an error:
The constructor ‘ReaderT’ should have 1 argument, but has been given 3
In the pattern: ReaderT MongoContext IO ()
In a case alternative:
ReaderT MongoContext IO ()
Should I pass MongoContext -> IO () instead? I'm out of ideas, please help me with that expression. Thanks <3
IO is a type, you absolutely cannot case match against it, it only exists at compile time.
In general, if you have a type variable constrained by a type class, you can only call things supported by that type class. You cannot know which particular type it is unless the typeclass implements methods for inspecting it, like Typeable. Neither Monad nor MonadIO implement this kind of run-time type discrimination, so what you want is, by design, not possible.
Also note that, you don't need to know "which m" delete is, since it's specialized to whatever m that YOU want it to be, so long as it is an instance of MonadIO. You can simply declare deleteIO sel = delete sel :: Action IO ()
What are you actually trying to get done here?
As Steven Armstrong said, what you're trying to do is very weird, you cannot pattern match on IO because is an abstract data type (constructors aren't visible) and if I were you I would rethink what I'm trying to achieve. Having said that, Haskell still gives you a way of inspecting types at runtime using Typeable eg (inside a ghci session):
import Data.Typeable
import Control.Monad.Trans.Reader
type MyType = ReaderT String IO
f :: MyType ()
f = ReaderT $ \env -> putStrLn env
checkF :: Typeable a => MyType a -> Bool
checkF x = case show (typeOf x) of
"ReaderT * [Char] IO ()" -> True
_ -> False
-- checkF f => True

Type signature of runErrorT

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.

How do closures work in Haskell?

I'm reading about the math foundation behind Haskell - I've learned about how closures can be used to save state in a function.
I was wondering if Haskell allows closures, and how they work because they are not pure functions?
If a function modifies it's closed-over state it will be capable of giving different outputs on identical inputs.
How is this not a problem in Haskell? Is it because you can't reassign a variable after you initially assign it a value?
You actually can simulate closures in Haskell, but not the way you might think. First, I will define a closure type:
data Closure i o = Respond (i -> (o, Closure i o ))
This defines a type that at each "step" takes a value of type i which is used to compute a response of type o.
So, let's define a "closure" that accepts empty inputs and answers with integers, i.e.:
incrementer :: Closure () Int
This closure's behavior will vary from request to request. I'll keep it simple and make it so that it responds with 0 to the first response and then increments its response for each successive request:
incrementer = go 0 where
go n = Respond $ \() -> (n, go (n + 1))
We can then repeatedly query the closure, which yields a result and a new closure:
query :: i -> Closure i o -> (o, Closure i o)
query i (Respond f) = f i
Notice that the second half of the above type resembles a common pattern in Haskell, which is the State monad:
newtype State s a = State { runState :: s -> (a, s) }
It can be imported from Control.Monad.State. So we can wrap query in this State monad:
query :: i -> State (Closure i o) o
query i = state $ \(Respond f) -> f i
... and now we have a generic way to query any closure using the State monad:
someQuery :: State (Closure () Int) (Int, Int)
someQuery = do
n1 <- query ()
n2 <- query ()
return (n1, n2)
Let's pass it our closure and see what happens:
>>> evalState someQuery incrementer
(0, 1)
Let's write a different closure that returns some arbitrary pattern:
weirdClosure :: Closure () Int
weirdClosure = Respond (\() -> (42, Respond (\() -> (666, weirdClosure))))
... and test it:
>>> evalState someQuery weirdClosure
(42, 666)
Now, writing closures by hand seems pretty awkward. Wouldn't it be nice if we could use do notation to write the closure? Well, we can! We only have to make one change to our closure type:
data Closure i o r = Done r | Respond (i -> (o, Closure i o r))
Now we can define a Monad instance (from Control.Monad) for Closure i o:
instance Monad (Closure i o) where
return = Done
(Done r) >>= f = f r
(Respond k) >>= f = Respond $ \i -> let (o, c) = k i in (o, c >>= f)
And we can write a convenience function which corresponds to servicing a single request:
answer :: (i -> o) -> Closure i o ()
answer f = Respond $ \i -> (f i, Done ())
... which we can use to rewrite all our old closures:
incrementer :: Closure () Int ()
incrementer = forM_ [1..] $ \n -> answer (\() -> n)
weirdClosure :: Closure () Int r
weirdClosure = forever $ do
answer (\() -> 42)
answer (\() -> 666)
Now we just change our query function to:
query :: i -> StateT (Closure i o r) (Either r) o
query i = StateT $ \x -> case x of
Respond f -> Right (f i)
Done r -> Left r
... and use it to write queries:
someQuery :: StateT (Closure () Int ()) (Either ()) (Int, Int)
someQuery = do
n1 <- query ()
n2 <- query ()
return (n1, n2)
Now test it!
>>> evalStateT someQuery incrementer
Right (1, 2)
>>> evalStateT someQuery weirdClosure
Right (42, 666)
>>> evalStateT someQuery (return ())
Left ()
However, I still don't consider that a truly elegant approach, so I'm going to conclude by shamelessly plugging my Proxy type in my pipes as a much general and more structured way of writing closures and their consumers. The Server type represents a generalized closure and the Client represents a generalized consumer of a closure.
The closure just 'adds' additional variables to function, so there is nothing more you can do with them than you can with 'normal' ones, that is, certainly not modify the state.
Read more:
Closures (in Haskell)
As others have said, Haskell does not allow the "state" in a closure to be altered. This prevents you from doing anything that might break function purity.

Resources