
I'm enjoying writing code that uses the Error monad to provide errors, which I can catch and rethrow to add context. Kind of like getting a stack trace with any context I want every time an error happens. In most cases I use monad transformers, so the actual monad type would be something like "ErrorT String (State Int) a" But much of my code that handles errors doesn't need to know the entire context. It uses throwError, but otherwise doesn't care anything else about the type of the monadic computation. I.e., it needs to "know" that it's inside a monadic computation of a typeclass MonadError. So I discovered that I could declare a function like this: x :: MonadError String m => Float -> m Float x y = if y == 0 then throwError "zero" else return y My awareness of class constraints is vague, so as I worked on this problem I knew in a fuzzy way it was going to look something like that, but I had to experiment. Also, because I put "String" in the class constraint, I need to turn on FlexibleContexts. So my question is, how would I do it without making "String" explicit? If I put x:: MonadError e m => Float -> m Float x y = if y == 0 then throwError "zero" else return y I get errors saying "couldn't match expected type e against inferred type [Char]" and something about functional dependencies I fiddled with it a bit but couldn't make it work.

The use of throwError :: e -> m a on a String type implies that e is String, but you have declared that e is more general. Here is a version that type checks: x :: (Error e, MonadError e m) => Float -> m Float x y = if y == 0 then throwError . strMsg $ "zero" else return y strMsg is part of the Error class, and will allow you to represent these errors more generally. Nick On Saturday, August 25, 2012 12:30:23 AM Dennis Raddle wrote:
I'm enjoying writing code that uses the Error monad to provide errors, which I can catch and rethrow to add context. Kind of like getting a stack trace with any context I want every time an error happens.
In most cases I use monad transformers, so the actual monad type would be something like "ErrorT String (State Int) a"
But much of my code that handles errors doesn't need to know the entire context. It uses throwError, but otherwise doesn't care anything else about the type of the monadic computation. I.e., it needs to "know" that it's inside a monadic computation of a typeclass MonadError.
So I discovered that I could declare a function like this:
x :: MonadError String m => Float -> m Float x y = if y == 0 then throwError "zero" else return y
My awareness of class constraints is vague, so as I worked on this problem I knew in a fuzzy way it was going to look something like that, but I had to experiment.
Also, because I put "String" in the class constraint, I need to turn on FlexibleContexts.
So my question is, how would I do it without making "String" explicit?
If I put
x:: MonadError e m => Float -> m Float x y = if y == 0 then throwError "zero" else return y
I get errors saying "couldn't match expected type e against inferred type [Char]" and something about functional dependencies
I fiddled with it a bit but couldn't make it work.
participants (2)
-
Dennis Raddle
-
Nick Vanderweit