Use of Error typeclass - haskell

What is the use of Error typeclass:
class Error a where
noMsg :: a
strMsg :: String -> a
There is also another typeclass named MonadError which makes sense in monadic computation. But where is Error used ? I haven't seen the usage of noMsg and strMsg yet anywhere.

For historical reasons, the Monad m typeclass includes fail :: String -> m a. For Either e to implement such a method, we must have a way to turn a String into an e; the Error typeclass was invented to allow this via strMsg. The addition of noMsg is an additional convenience.

Related

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

How to preserve information when failing?

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.

Non type-variable argument in the constraint: MonadError Failure m

I have defined a custom error type:
data Failure = NetworkError Message |
UserIsTooStupid Message |
InvalidOperation Message |
UnexpectedError Message
type Message = String
I am trying to use MonadError with my error type:
loadJSON :: (Aeson.FromJSON v, MonadIO m, MonadError Failure m) => URI -> m v
loadJSON uri = do
body <- liftIO $ getResponseBody =<< simpleHTTP (getRequest uri)
case Aeson.decode body of
Just json -> return json
Nothing -> throwError $ SerialisationError "Couldn't deserialise from JSON"
type URI = String
In other words, this function can return any monad which satisfies both MonadIO and MonadError, but the only type of error it can throw is Failure.
This fails to compile, with the error message:
Non type-variable argument in the constraint: MonadError Failure m
(Use -XFlexibleContexts to permit this)
In the type signature for `loadJSON':
loadJSON :: (Aeson.FromJSON v, MonadIO m, MonadError Failure m) =>
URI -> m v
GHC wants me to turn on the FlexibleContexts language extension to make this code work. What does FlexibleContexts do, and is it really necessary in my case? I prefer not to turn on language extensions willy-nilly without knowing whether I need them.
The function compiles fine if I leave off the type signature, but I prefer not to do that.
Haskell 98 doesn't allow constraints that looks like MonadError Failure m, they have to look like MonadError a m. The ability to have constraints like that was added to GHC however, which is what that extension does. I understand being wary of language extensions, but FlexibleContexts is pretty harmless.
I believe at the time Haskell 98 came out, the type theory to use constraints like that hadn't been developed, but since then it has. The extension turns on some extra code in the type checker which uses that theory. If you google around a little you might be able to find a paper on how it works.

Extensible Haskell Type Classes

I am reading a paper on dependently-typed programming and came across the following quote:
"[...] in contrast to Haskell's type classes, the data type [...] is closed", in the sense that one cannot add new types to the universe without extending the data type.
My newbie question is: in what sense are Haskell type classes open? How are they extensible? Also, what are the type-theoretical consequences of having this property (open vs closed)?
Thank you!
Type classes are open, because you can make arbitrary type an instance of it. When you create type class you specify interface, but not the types which belong to it. Then in any code which includes typeclass definition you can make your type instance of it providing necessary functions from interface using instance TypeClass type of syntax.
Given a type class like:
class Monoid m where
mempty :: m
mappend :: m -> m -> m
... it is (basically) implemented under the hood as a dictionary type:
data Monoid m = Monoid
{ mempty :: m
, mappend :: m -> m -> m
}
Instances like:
instance Monoid [a] where
mempty = []
mappend = (++)
... get translated to dictionaries:
listIsAMonoid :: Monoid [a]
listIsAMonoid = Monoid
{ mempty = []
, mappend = (++)
}
... and the compiler consults above dictionary whenever you use lists in their capacity as Monoids.
This brings us to your questions:
in what sense are Haskell type classes open? How are they extensible?
They are open in the same sense that polymorphic values are open. We have some polymorphic data type:
data Monoid m = ...
... and we can instantiate the polymorphic m type variable to any type where we can provide suitable values for the mempty and mappend fields.
Type classes are "open" because they can always have more types added to them "after the fact" by adding more instance declarations. This can even be done in "client" code that merely uses the module containing the type class.
The key point is that I can write code that operates on values with some type-class constraint, and that same code with no modification can be used on types that weren't in existence when I wrote the type class.
Concrete data types in Haskell are "closed" in that this cannot happen. If I write code that operates on members a specific data type (even if it's polymorphic), then there's no way you can use that code to operate on new kinds of thing I hadn't thought of unless you're able to modify the type (which then probably requires modifying all the places where it is used).

Satisfying monad laws without a type constructor

Given e.g. a type like
data Tree a = Branch (Tree a) (Tree a)
| Leaf a
I can easily write instances for Functor, Applicative, Monad, etc.
But if the "contained" type is predetermined, e.g.
data StringTree = Branch StringTree StringTree
| Leaf String
I lose the ability to write these instances.
If I were to write functions for my StringTree type
stringTreeReturn :: String -> StringTree
stringTreeBind :: String -> (String -> StringTree) -> StringTree
stringTreeFail :: String -> StringTree
-- etc.
that satisfied the monad laws, could I still say that StringTree is a monad?
Tree a isn't a monad, either generally or for any particular a, Tree itself is a monad. A monad isn't a type, it's a correspondence between any type and a "monadic version" that type. For example, Integer is the type of integers, and Maybe Integer is the type of integers in the Maybe monad.
Consequently, StringTree, which is a type, can't be a monad. It's just not the same kind of thing. You can try to imagine it as the type of strings in a monad, but your functions stringTreeReturn, etc, don't match the types of their monadic correspondents. Look at the type of >>= in the Maybe monad:
Maybe a -> (a -> Maybe b) -> Maybe b
The second argument is a function from some a to any type in the Maybe monad (Maybe b). stringTreeBind has the type:
String -> (String -> StringTree) -> StringTree
The second argument can only be a function from String to the monadic version of String, rather than to the monadic version of any type.
Consequently, you can't do everything you can do to values in an arbitrary monadic type to StringTree values, which is why it can't be made an instance. Even if you could somehow get it treated as a monad, things would start going wrong when generic monadic code expects to be able to use generic monadic operations in ways that don't make sense for StringTree.
Ultimately, if you're thinking of it as "like" a monad because it's String in a container that can behave similarly to monadic containers, the easiest thing to do is simply make it a generic container of any type (Tree a). If you need have auxiliary functionality that depends specifically on it being a tree of strings, then you can write that code as operating only on Tree String values, and it will happily co-exist along with code that works generically on Tree a.
No. You're looking at the difference between a type and a kind. Simplistically, a kind is the way that Haskell classifies types, so it's a level of abstraction above types. ghci can help.
:type stringReturn
stringReturn :: String -> StringTree
:type Functor
<interactive>:1:1: Not in scope: data constructor `Functor'
So right off the bat, we can see that a function, which has a type, is an entirely different thing than a type, which has a kind.
We can also ask ghci about kinds.
:kind Functor
Functor (* -> *) -> Constraint
:kind StringTree
StringTree :: *
:kind Tree
Tree :: * -> *
Kinds use * for variables in their notation. We can see from the interaction above that Functor expects a type that is parameterized over one argument. We can also see that StringTree doesn't take any parameters, and Tree takes one.
That's a long way of expressing and unpacking your question, but hopefully it shows the difference between types and kinds.
No, that wouldn't be a monad. Think about it, can you write a monad m so only m String is ever possible?

Resources