How to preserve information when failing? - haskell

I'm writing some code that uses the StateT monad transformer to keep track of some stateful information (logging and more).
The monad I'm passing to StateT is very simple:
data CheckerError a = Bad {errorMessage :: Log} | Good a
deriving (Eq, Show)
instance Monad CheckerError where
return x = Good x
fail msg = Bad msg
(Bad msg) >>= f = Bad msg
(Good x) >>= f = f x
type CheckerMonad a = StateT CheckerState CheckerError a
It's just a Left and Right variant.
What troubles me is the definition of fail. In my computation I produce a lot of information inside this monad and I'd like to keep this information even when failing.
Currently the only thing I can do is to convert everything to a String and create a Bad instance with the String passed as argument to fail.
What I'd like to do is something like:
fail msg = do
info <- getInfoOutOfTheComputation
return $ Bad info
However everything I tried until now gives type errors, probably because this would mix different monads.
Is there anyway in which I can implement fail in order to preserve the information I need without having to convert all of it into a String?
I cannot believe that the best Haskell can achieve is using show+read to pass all the information as the string to fail.

Your CheckerError monad is very similar to the Either monad. I will use the Either monad (and its monad transformer counterpart ErrorT) in my answer.
There is a subtlety with monad trasformers: order matters. Effects in the "inner" monad have primacy over effects caused by the "outer" layers. Consider these two alternative definitions of CheckerMonad:
import Control.Monad.State
import Control.Monad.Error
type CheckerState = Int -- dummy definitions for convenience
type CheckerError = String
type CheckerMonad a = StateT CheckerState (Either String) a
type CheckerMonad' a = ErrorT String (State CheckerState) a
In CheckerMonad, Either is the inner monad, and this means a failure will wipe the whole state. Notice the type of this run function:
runCM :: CheckerMonad a -> CheckerState -> Either CheckerError (a,CheckerState)
runCM m s = runStateT m s
You either fail, or return a result along with the state up to that point.
In CheckerMonad', State is the inner monad. This means the state will be preserved even in case of failures:
runCM' :: CheckerMonad' a -> CheckerState -> (Either CheckerError a,CheckerState)
runCM' m s = runState (runErrorT m) s
A pair is returned, which contains the state up to that point, and either a failure or a result.
It takes a bit of practice to develop an intuition of how to properly order monad transformers. The chart in the Type juggling section of this Wikibook page is a good starting point.
Also, it is better to avoid using fail directly, because it is considered a bit of a wart in the language. Instead, use the specialized functions for throwing errors provided by the error transformer. When working with ErrorT or some other instance of MonadError, use throwError.
sillycomp :: CheckerMonad' Bool
sillycomp = do
modify (+1)
s <- get
if s == 3
then throwError "boo"
else return True
*Main> runCM' sillycomp 2
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.2 ... linking ... done.
(Left "boo",3)
*Main> runCM' sillycomp 3
(Right True,4)
ErrorT is sometimes annoying to use because, unlike Either, it requires an Error constraint on the error type. The Error typeclass forces you to define two error constructors noMsg and strMsg, which may or may not make sense for your type.
You can use EitherT from the either package instead, which lets you use any type whatsoever as the error. When working with EitherT, use the left function to throw errors.

Related

How to understand `MonadUnliftIO`'s requirement of "no stateful monads"?

I've looked over https://www.fpcomplete.com/blog/2017/06/tale-of-two-brackets, though skimming some parts, and I still don't quite understand the core issue "StateT is bad, IO is OK", other than vaguely getting the sense that Haskell allows one to write bad StateT monads (or in the ultimate example in the article, MonadBaseControl instead of StateT, I think).
In the haddocks, the following law must be satisfied:
askUnliftIO >>= (\u -> liftIO (unliftIO u m)) = m
So this appears to be saying that state is not mutated in the monad m when using askUnliftIO. But to my mind, in IO, the entire world can be the state. I could be reading and writing to a text file on disk, for instance.
To quote another article by Michael,
False purity We say WriterT and StateT are pure, and technically they
are. But let's be honest: if you have an application which is entirely
living within a StateT, you're not getting the benefits of restrained
mutation that you want from pure code. May as well call a spade a
spade, and accept that you have a mutable variable.
This makes me think this is indeed the case: with IO we are being honest, with StateT, we are not being honest about mutability ... but that seems another issue than what the law above is trying to show; after all, MonadUnliftIO is assuming IO. I'm having trouble understanding conceptually how IO is more restrictive than something else.
Update 1
After sleeping (some), I am still confused but am gradually getting less so as the day wears on. I worked out the law proof for IO. I realized the presence of id in the README. In particular,
instance MonadUnliftIO IO where
askUnliftIO = return (UnliftIO id)
So askUnliftIO would appear to return an IO (IO a) on an UnliftIO m.
Prelude> fooIO = print 5
Prelude> :t fooIO
fooIO :: IO ()
Prelude> let barIO :: IO(IO ()); barIO = return fooIO
Prelude> :t barIO
barIO :: IO (IO ())
Back to the law, it really appears to be saying that state is not mutated in the monad m when doing a round trip on the transformed monad (askUnliftIO), where the round trip is unLiftIO -> liftIO.
Resuming the example above, barIO :: IO (), so if we do barIO >>= (u -> liftIO (unliftIO u m)), then u :: IO () and unliftIO u == IO (), then liftIO (IO ()) == IO (). **So since everything has basically been applications of id under the hood, we can see that no state was changed, even though we are using IO. Crucially, I think, what is important is that the value in a is never run, nor is any other state modified, as a result of using askUnliftIO. If it did, then like in the case of randomIO :: IO a, we would not be able to get the same value had we not run askUnliftIO on it. (Verification attempt 1 below)
But, it still seems like we could do the same for other Monads, even if they do maintain state. But I also see how, for some monads, we may not be able to do so. Thinking of a contrived example: each time we access the value of type a contained in the stateful monad, some internal state is changed.
Verification attempt 1
> fooIO >> askUnliftIO
5
> fooIOunlift = fooIO >> askUnliftIO
> :t fooIOunlift
fooIOunlift :: IO (UnliftIO IO)
> fooIOunlift
5
Good so far, but confused about why the following occurs:
> fooIOunlift >>= (\u -> unliftIO u)
<interactive>:50:24: error:
* Couldn't match expected type `IO b'
with actual type `IO a0 -> IO a0'
* Probable cause: `unliftIO' is applied to too few arguments
In the expression: unliftIO u
In the second argument of `(>>=)', namely `(\ u -> unliftIO u)'
In the expression: fooIOunlift >>= (\ u -> unliftIO u)
* Relevant bindings include
it :: IO b (bound at <interactive>:50:1)
"StateT is bad, IO is OK"
That's not really the point of the article. The idea is that MonadBaseControl permits some confusing (and often undesirable) behaviors with stateful monad transformers in the presence of concurrency and exceptions.
finally :: StateT s IO a -> StateT s IO a -> StateT s IO a is a great example. If you use the "StateT is attaching a mutable variable of type s onto a monad m" metaphor, then you might expect that the finalizer action gets access to the most recent s value when an exception was thrown.
forkState :: StateT s IO a -> StateT s IO ThreadId is another one. You might expect that the state modifications from the input would be reflected in the original thread.
lol :: StateT Int IO [ThreadId]
lol = do
for [1..10] $ \i -> do
forkState $ modify (+i)
You might expect that lol could be rewritten (modulo performance) as modify (+ sum [1..10]). But that's not right. The implementation of forkState just passes the initial state to the forked thread, and then can never retrieve any state modifications. The easy/common understanding of StateT fails you here.
Instead, you have to adopt a more nuanced view of StateT s m a as "a transformer that provides a thread-local immutable variable of type s which is implicitly threaded through a computation, and it is possible to replace that local variable with a new value of the same type for future steps of the computation." (more or less a verbose english retelling of the s -> m (a, s)) With this understanding, the behavior of finally becomes a bit more clear: it's a local variable, so it does not survive exceptions. Likewise, forkState becomes more clear: it's a thread-local variable, so obviously a change to a different thread won't affect any others.
This is sometimes what you want. But it's usually not how people write code IRL and it often confuses people.
For a long time, the default choice in the ecosystem to do this "lowering" operation was MonadBaseControl, and this had a bunch of downsides: hella confusing types, difficult to implement instances, impossible to derive instances, sometimes confusing behavior. Not a great situation.
MonadUnliftIO restricts things to a simpler set of monad transformers, and is able to provide relatively simple types, derivable instances, and always predictable behavior. The cost is that ExceptT, StateT, etc transformers can't use it.
The underlying principle is: by restricting what is possible, we make it easier to understand what might happen. MonadBaseControl is extremely powerful and general, and quite difficult to use and confusing as a result. MonadUnliftIO is less powerful and general, but it's much easier to use.
So this appears to be saying that state is not mutated in the monad m when using askUnliftIO.
This isn't true - the law is stating that unliftIO shouldn't do anything with the monad transformer aside from lowering it into IO. Here's something that breaks that law:
newtype WithInt a = WithInt (ReaderT Int IO a)
deriving newtype (Functor, Applicative, Monad, MonadIO, MonadReader Int)
instance MonadUnliftIO WithInt where
askUnliftIO = pure (UnliftIO (\(WithInt readerAction) -> runReaderT 0 readerAction))
Let's verify that this breaks the law given: askUnliftIO >>= (\u -> liftIO (unliftIO u m)) = m.
test :: WithInt Int
test = do
int <- ask
print int
pure int
checkLaw :: WithInt ()
checkLaw = do
first <- test
second <- askUnliftIO >>= (\u -> liftIO (unliftIO u test))
when (first /= second) $
putStrLn "Law violation!!!"
The value returned by test and the askUnliftIO ... lowering/lifting are different, so the law is broken. Furthermore, the observed effects are different, which isn't great either.

Control.Exception.Safe, why do ExceptT and Either behave so differently?

I'm trying to use Control.Exception.Safe with Control.Monad.Except.
throwString "Foo" :: Except String a
-- error, no instance for `MonadTrow Identity`
Ok, so apparently Except throws its error into its underlying monad in the transformer stack?
But why is that? Isn't Except basically designed to handle exceptions? Why this weird behavior? Why not the equivalent of Left "Foo"
EDIT:
Okay to further illustrate my problem:
I thought ExceptT e m a was to Either e a what ReaderT a m b is to a -> b. Control.Monad.Except.throwError, and catchError work exactly like Control.Exception.Safe.throw, and catch do with Either e a.
However they suddenly work different when applied to Except e a.
What do I do, when I want to use the behaviour of Either e a that is supplied by Control.Exception.Safe but in the context of monad transformers?
My context is that I do "Write yourself a Scheme in 48 hours" and wanted to generalize errors (with MonadThrow), so that I can do some IO stuff with it.
EDIT2:
Example:
data CountError = CountError deriving (Show, Except)
x :: String -> ExceptT CountError (Writer [String]) Int
x str = do { lift $ writer (length "str", return str); }
Now this count characters and collects the strings in the writer. This could be extended however much you want. The error could signal "wrong character in string", or "too many characters", or whatever.
y :: MonadThrow m => m a
y = throw CountError
This is a very general exception, which I could use for composition with any other kind of exception, except for ExceptT:
y >> x
-- No instance for MonadThrow Identity
-- But what I want is (Left CountError, [])
Ok, so apparently Except throws its error into its underlying monad in the transformer stack?
As I said in the comment: Except doesn't "throw it's error into the underlying monad", that's just what the MonadThrow instances is doing.
But why is that?
The instance of MonadThrow can not throw a String exception into ExceptT e for all types e and rather than have an instance just for ExceptT String it appears the author lifted to throw an exception on the next higher monad.
Isn't Except basically designed to handle exceptions?
Indeed Except is designed to allow for failure in exceptional cases.
Being pedantic, I'd call it an alternative to exceptions. A monad plumbing an alternative notion of return (an error case) and calling itself "Except" doesn't actually mean any of the typical exception options, such as a low level stack unwinding, is in use.
Why this weird behavior?
Because of the MonadThrow instance, which is re-exported from Control.Monad.Throw:
-- | Throws exceptions into the base monad.
instance MonadThrow m => MonadThrow (ExceptT e m) where
throwM = lift . throwM
Why not the equivalent of Left "Foo"
Because then the instance would have to be for ExceptT String instead of ExceptT e. Or, that is why I think the author of exceptions (Edward Kmett) decided on this design.
Instead, consider using Control.Monad.Except.throwError which does what it sounds like you want.
What do I do, when I want to use the behaviour of Either e a that is supplied by Control.Exception.Safe but in the context of monad transformers?
What "behavior of Either e a are you talking about? How is what you are looking for different from throwError? As far as I can tell, you are looking for an unnecessary extra layer of abstraction.
This is a bit of an old question but I think there is room to improve on this answer as I recently ran into this topic at work. Let's see, I believe that your expectation of having ExceptT behave similar to Either makes sense, but unfortunately the author of MonadThrow chose a different stance and decided that "passing" the decision on how to "throw" a failure to the underlying monad (or transformer) was the right way to go. Without attempting to speculate why decision was made, I agree that this behavior defeats the purpose of using a "failable" transformer such as 'MaybeT' or 'ExceptT' as an instance of an error class like MonadThrow, which is to give "Maybe" or "Either" like semantics to a different monad.
For this reason I have donned my flame vest and took a stab at Control.Monad.Failable , which would do exactly what you (and I) would expect, which is to return something like Left e where e is an instance of Exception.
Control.Monad.Failable

Why can I call a monadic function without supplying a monad?

I thought I had a good handle on Haskell Monads until I realized this very simple piece of code made no sense to me (this is from the haskell wiki about the State monad):
playGame :: String -> State GameState GameValue
playGame [] = do
(_, score) <- get
return score
What confuses me is, why is the code allowed to call "get", when the only argument supplied is a string? It seems almost like it is pulling the value out of thin air.
A better way for me to ask the question may be, how would one rewrite this function using >>= and lambda's instead of do notation? I'm unable to figure it out myself.
Desugaring this into do notation would look like
playGame [] =
get >>= \ (_, score) ->
return score
We could also just write this with fmap
playGame [] = fmap (\(_, score) -> score) get
playGame [] = fmap snd get
Now the trick is to realize that get is a value like any other with the type
State s s
What get will return won't be determined until we feed our computation to runState or similar where we provide an explicit starting value for our state.
If we simplify this further and get rid of the state monad we'd have
playGame :: String -> (GameState -> (GameState, GameValue))
playGame [] = \gamestate -> (gamestate, snd gamestate)
The state monad is just wrapping around all of this manual passing of GameState but you can think of get as accessing the value that our "function" was passed.
A monad is a "thing" which takes a context (we call it m) and which "produces" a value, while still respecting the monad laws. We can think of this in terms of being "inside" and "outside" of the monad. The monad laws tell us how to deal with a "round trip" -- going outside and then coming back inside. In particular, the laws tell us that m (m a) is essentially the same type as (m a).
The point is that a monad is a generalization of this round-tripping thing. join squashes (m (m a))'s into (m a)'s, and (>>=) pulls a value out of the monad and applies a function into the monad. Put another way, it applies a function (f :: a -> m b) to the a in (m a) -- which yields an (m (m b)), and then squashes that via join to get our (m b).
So what does this have to do with 'get' and objects?
Well, do notation sets us up so that the result of a computation is in our monad. And (<-) lets us pull a value out of a monad, so that we can bind it to a function, while still nominally being inside of the monad. So, for example:
doStuff = do
a <- get
b <- get
return $ (a + b)
Notice that a and b are pure. They are "outside" of the get, because we actually peeked inside it. But now that we have a value outside of the monad, we need to do something with it (+) and then stick it back in the monad.
This is just a little bit of suggestive notation, but it might be nice if we could do:
doStuff = do
a <- get
b <- get
(a + b) -> (\x -> return x)
to really emphasize the back and forth of it. When you finish a monad action, you must be on the right column in that table, because when the action is done, 'join' will get called to flatten the layers. (At least, conceptually)
Oh, right, objects. Well, obviously, an OO language basically lives and breathes in an IO monad of some kind. But we can actually break it down some more. When you run something along the lines of:
x = foo.bar.baz.bin()
you are basically running a monad transformer stack, which takes an IO context, which produces a foo context, which produces a bar context, which produces a baz context, which produces a bin context. And then the runtime system "calls" join on this thing as many times as needed. Notice how well this idea meshes with "call stacks". And indeed, this is why it is called a "monad transformer stack" on the haskell side. It is a stack of monadic contexts.

MonadPlus definition for Haskell IO

I was just writing a quick bit of code, and I wanted to use the guard function in the IO Monad. However, there is no definition of MonadPlus for IO which means that we cannot use guard in IO land. I have seen an example of using the MabyeT transformer to use guard in the Maybe Monad and then lifting all of the IO actions but I do not really want to do that if I do not have to.
Some example of what I want might be:
handleFlags :: [Flag] -> IO ()
handleFlags flags = do
when (Help `elem` flags) (putStrLn "Usage: program_name options...")
guard (Help `elem` flags)
... do stuff ...
return ()
I was wondering if there was a nice way to get a guard function (or something similar) in the IO Monad through a declaration for MonadPlus or otherwise. Or perhaps I am doing it wrong; is there a better way to write that help message in the function above? Thanks.
(P.S. I could use if-then-else statements but it seems to defeat the point somehow. Not to mention that for a lot of options it will result in a huge amount of nesting.)
Consider the definition of MonadPlus:
class Monad m => MonadPlus m where
mzero :: m a
mplus :: m a -> m a -> m a
How would you implement mzero for IO? A value of type IO a represents an IO computation that returns something of type a, so mzero would have to be an IO computation returning something of any possible type. Clearly, there's no way to conjure up a value for some arbitrary type, and unlike Maybe there's no "empty" constructor we can use, so mzero would necessarily represent an IO computation that never returns.
How do you write an IO computation that never returns? Either go into an infinite loop or throw a runtime error, basically. The former is of dubious utility, so the latter is what you're stuck with.
In short, to write an instance of MonadPlus for IO what you'd do is this: Have mzero throw a runtime exception, and have mplus evaluate its first argument while catching any exceptions thrown by mzero. If no exceptions are raised, return the result. If an exception is raised, evaluate mplus's second argument instead while ignoring exceptions.
That said, runtime exceptions are often considered undesirable, so I'd hesitate before going down that path. If you do want to do it that way (and don't mind increasing the chance that your program may crash at runtime) you'll find everything you need to implement the above in Control.Exception.
In practice, I'd probably either use the monad transformer approach if I wanted a lot of guarding on the result of evaluating monadic expressions, or if most of the conditionals depend on pure values provided as function arguments (which the flags in your example are) use the pattern guards as in #Anthony's answer.
I do this sort of thing with guards.
handleFlags :: [Flag] -> IO ()
handleFlags flags
| Help `elem` flags = putStrLn "Usage: program_name options..."
| otherwise = return ()
There're functions precisely made for this: in Control.Monad, the functions when and its counterpart unless.
Anthony's answer can be rewritten as such:
handleFlags :: [Flag] -> IO ()
handleFlags flags =
when (Help `elem` flags) $ putStrLn "Usage: program_name options..."
specifications:
when :: (Applicative m) => Bool -> m () -> m ()
unless bool = when (not bool)
Link to docs on hackage.haskell.org
If more is needed, here's a link to another package, specifically monad-oriented and with several more utilities: Control.Monad.IfElse

Haskell: Why do the Maybe and Either types behave differently when used as Monads?

I'm trying to get my head around error handling in Haskell. I've found the article "8 ways to report errors in Haskell" but I'm confused as to why Maybe and Either behave differently.
For example:
import Control.Monad.Error
myDiv :: (Monad m) => Float -> Float -> m Float
myDiv x 0 = fail "My divison by zero"
myDiv x y = return (x / y)
testMyDiv1 :: Float -> Float -> String
testMyDiv1 x y =
case myDiv x y of
Left e -> e
Right r -> show r
testMyDiv2 :: Float -> Float -> String
testMyDiv2 x y =
case myDiv x y of
Nothing -> "An error"
Just r -> show r
Calling testMyDiv2 1 0 gives a result of "An error", but calling testMyDiv1 1 0 gives:
"*** Exception: My divison by zero
(Note the lack of closing quote, indicating this isn't a string but an exception).
What gives?
The short answer is that the Monad class in Haskell adds the fail operation to the original mathematical idea of monads, which makes it somewhat controversial how to make the Either type into a (Haskell) Monad, because there are many ways to do it.
There are several implementations floating around that do different things. The 3 basic approaches that I'm aware of are:
fail = Left. This seems to be what most people expect, but it actually can't be done in strict Haskell 98. The instance would have to be declared as instance Monad (Either String), which is not legal under H98 because it mentions a particular type for one of Eithers parameters (in GHC, the FlexibleInstances extension would cause the compiler to accept it).
Ignore fail, using the default implementation which just calls error. This is what's happening in your example. This version has the advantage of being H98 compliant, but the disadvantage of being rather surprising to the user (with the surprise coming at runtime).
The fail implementation calls some other class to convert a String into whatever type. This is done in MTL's Control.Monad.Error module, which declares instance Error e => Monad (Either e). In this implementation, fail msg = Left (strMsg msg). This one is again legal H98, and again occasionally surprising to users because it introduces another type class. In contrast to the last example though, the surprise comes at compile time.
I'm guessing you're using monads-fd.
$ ghci t.hs -hide-package mtl
*Main Data.List> testMyDiv1 1 0
"*** Exception: My divison by zero
*Main Data.List> :i Either
...
instance Monad (Either e) -- Defined in Control.Monad.Trans.Error
...
Looking in the transformers package, which is where monads-fd gets the instance, we see:
instance Monad (Either e) where
return = Right
Left l >>= _ = Left l
Right r >>= k = k r
So, no definition for Fail what-so-ever. In general, fail is discouraged as it isn't always guaranteed to fail cleanly in a monad (many people would like to see fail removed from the Monad class).
EDIT: I should add that it certainly isn't clear fail was intentioned to be left as the default error call. A ping to haskell-cafe or the maintainer might be worth while.
EDIT2: The mtl instance has been moved to base, this move includes removing the definition of fail = Left and discussion as to why that decision was made. Presumably, they want people to use ErrorT more when monads fail, thus reserving fail for something more catastrophic situations like bad pattern matches (ex: Just x <- e where e -->* m Nothing).

Resources