ANNOUNCE: new installment of failure framework

We'd like to announce the next installment of the Failure Framework. Based on feedback, our main goals in this release is to reduce the number of external dependencies and avoid complications with monad transformer libraries at the core of the framework. We have made the following changes: * Failure is not tied directly to monads anymore. The main typeclass is Failure, which provides the failure function. MonadFailure, ApplicativeFailure and FunctorFailure are provided for convenience. * The Failure typeclass is now located in the failure package, which has no dependencies. All code dealing with transformers and mtl has been factored into control-monad-failure and control-monad-failure-mtl, respectively. In addition, we are simultaneously releasing the following packages: * safe-failure provides safe versions of dangerous, non total functions, such as head, by returning failures. It depends exclusively on failure. * attempt provides a concrete data type for handling extensible exceptions as failures. It depends exclusively on failure. * control-monad-attempt provides a monad transformer for attempt using the transformers library. We do not provide currently an mtl version of this package, but can provide one if there is demand. * control-monad-exception, explicitly typed, checked exceptions with monadic stack traces. Below are the links to the packages just released. Enjoy! http://hackage.haskell.org/package/failure-0.0.0 http://hackage.haskell.org/package/control-monad-failure-0.6.0 http://hackage.haskell.org/package/control-monad-failure-mtl-0.6.0 http://hackage.haskell.org/package/safe-failure-0.4.0 http://hackage.haskell.org/package/attempt-0.2.0 http://hackage.haskell.org/package/control-monad-attempt-0.0.0 http://hackage.haskell.org/package/control-monad-exception-0.8.0 http://hackage.haskell.org/package/control-monad-exception-mtl-0.8.0 http://hackage.haskell.org/package/control-monad-exception-monadsfd-0.8.0 http://hackage.haskell.org/package/control-monad-exception-monadstf-0.8.0 Michael Snoyman, Pepe Iborra, Nicolas Pouillard

Michael, Although I like the idea of improving the way that failures are handled in Haskell, I am having trouble seeing any reason to use your framework. If a function is always assumed to succeed given certain pre-conditions, and somewhere along the lines my code discovers that one of these had been violated, then I throw an exception in order to communicate to myself the manner in which I screwed up. If a function might either succeed or fail for a very specific reason, then I use a Maybe because the caller will know exactly what problem is being signaled by Nothing. If a function might fail for one of many reasons and the caller might care about learning more about the problem, then I use an Either so that I can report the details of the problem. In each of the latter two cases, I can already use monads to handle the errors in a relatively convenient manner. In the first case I usually want the program to die right away and let me know where I screwed up, but if for some reason I wanted to continue even given arbitrary unanticipated problems in a particular computation the I use an exception handler. Given that all of the scenarios that I encounter are already handled by the functionality the standard libraries, it is not clear to me what your framework actually offers. I am not writing this to shoot your framework down, but rather to voice my thoughts aloud in order to hear your response to them, since if there is a use scenario that I am missing in which your framework would be ideal then I would be interested in hearing about it. Cheers, Greg On Dec 6, 2009, at 8:58 PM, Michael Snoyman wrote:
We'd like to announce the next installment of the Failure Framework. Based on feedback, our main goals in this release is to reduce the number of external dependencies and avoid complications with monad transformer libraries at the core of the framework. We have made the following changes:
* Failure is not tied directly to monads anymore. The main typeclass is Failure, which provides the failure function. MonadFailure, ApplicativeFailure and FunctorFailure are provided for convenience. * The Failure typeclass is now located in the failure package, which has no dependencies. All code dealing with transformers and mtl has been factored into control-monad-failure and control-monad-failure-mtl, respectively.
In addition, we are simultaneously releasing the following packages: * safe-failure provides safe versions of dangerous, non total functions, such as head, by returning failures. It depends exclusively on failure. * attempt provides a concrete data type for handling extensible exceptions as failures. It depends exclusively on failure. * control-monad-attempt provides a monad transformer for attempt using the transformers library. We do not provide currently an mtl version of this package, but can provide one if there is demand. * control-monad-exception, explicitly typed, checked exceptions with monadic stack traces.
Below are the links to the packages just released. Enjoy!
http://hackage.haskell.org/package/failure-0.0.0 http://hackage.haskell.org/package/control-monad-failure-0.6.0 http://hackage.haskell.org/package/control-monad-failure-mtl-0.6.0 http://hackage.haskell.org/package/safe-failure-0.4.0 http://hackage.haskell.org/package/attempt-0.2.0 http://hackage.haskell.org/package/control-monad-attempt-0.0.0 http://hackage.haskell.org/package/control-monad-exception-0.8.0 http://hackage.haskell.org/package/control-monad-exception-mtl-0.8.0 http://hackage.haskell.org/package/control-monad-exception-monadsfd-0.8.0 http://hackage.haskell.org/package/control-monad-exception-monadstf-0.8.0
Michael Snoyman, Pepe Iborra, Nicolas Pouillard _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Tue, Dec 8, 2009 at 11:51 AM, Gregory Crosswhite < gcross@phys.washington.edu> wrote:
Michael,
Although I like the idea of improving the way that failures are handled in Haskell, I am having trouble seeing any reason to use your framework.
If a function is always assumed to succeed given certain pre-conditions, and somewhere along the lines my code discovers that one of these had been violated, then I throw an exception in order to communicate to myself the manner in which I screwed up.
If a function might either succeed or fail for a very specific reason, then I use a Maybe because the caller will know exactly what problem is being signaled by Nothing.
If a function might fail for one of many reasons and the caller might care about learning more about the problem, then I use an Either so that I can report the details of the problem.
In each of the latter two cases, I can already use monads to handle the errors in a relatively convenient manner. In the first case I usually want the program to die right away and let me know where I screwed up, but if for some reason I wanted to continue even given arbitrary unanticipated problems in a particular computation the I use an exception handler.
Given that all of the scenarios that I encounter are already handled by the functionality the standard libraries, it is not clear to me what your framework actually offers.
I am not writing this to shoot your framework down, but rather to voice my thoughts aloud in order to hear your response to them, since if there is a use scenario that I am missing in which your framework would be ideal then I would be interested in hearing about it.
The failure wiki page addresses exactly why Maybe and Either are inadequate solutions in a number of circumstances. Maybe does not allow any information to be attached; that may be fine when you directly call a function, but what if you call a function, which calls another one, and so on and so forth? You would then have two choices:
* Ultimately just receive a Nothing and not know why. * At each step of the why, check if it's a Nothing, and then produce some appropriate message to describe it. If you choose option 2, you're admitting that Maybe was not sufficient for your uses any. Regarding Either, there are a number of issues: * There *is* not Monad instance in the base library. Orphan instances lead to major issues, such as not being able to import two modules at the same time because each declares a Monad Either instance. * With Either, you are limited to a single error type (unless you use existential types). * There is no easy way to chain together different types of Eithers (see below). For example, let's say I want to write some code to authenticate a user via OpenID (see the authenticate package). It has to do at least two things: * Download pages by HTTP * Parse the resulting HTML page. I would like to ideally do the following: authenticate = do page <- getPage url parsed <- parseHtml page checkResult parsed In other words, easily chain things together, and simply let the error types propogate. If the given functions had these signatures: getPage :: (MonadFailure HttpException m, MonadIO m) => String -> m String parseHtml :: Failure ParseHtmlException m => String -> m HtmlTree checkResult :: Failure AuthenticationException m => HtmlTree -> m Identifier Then authenticate would simply subsume all these error types, making it explicit what a client of the libraries needs to be aware of. If clients instead want to look at it as a simple success/failure, I would recommend using the attempt package. If they want to deal with each failure type separately, they could use control-monad-exception. I hope that clears up why this package exists. It was not born of nothing; it is meant to solve real problems in an elegant manner. If you have any questions, please let me know. Michael

On Dec 8, 2009, at 1:47 PM, Michael Snoyman wrote:
For example, let's say I want to write some code to authenticate a user via OpenID (see the authenticate package). It has to do at least two things:
* Download pages by HTTP * Parse the resulting HTML page.
I would like to ideally do the following:
authenticate = do page <- getPage url parsed <- parseHtml page checkResult parsed
In other words, easily chain things together, and simply let the error types propogate. If the given functions had these signatures:
getPage :: (MonadFailure HttpException m, MonadIO m) => String -> m String parseHtml :: Failure ParseHtmlException m => String -> m HtmlTree checkResult :: Failure AuthenticationException m => HtmlTree -> m Identifier
Then authenticate would simply subsume all these error types, making it explicit what a client of the libraries needs to be aware of.
Let me highlight this point. The Maybe, Either,Exception diversity can be a curse instead of a blessing when combining libraries which return errors in different ways. The main goal of the failure framework is to provide an abstract notion of failure, so that libraries can offer interfaces which fail in an abstract way, and the client of the libraries can make the choice of how to manage the failures. Using a similar example (from [1]), consider a program to download a web page and parse it: 1. Network.URI.parseURI returns (Maybe URI). 2. Network.HTTP.simpleHTTP returns (IO (Result Request)), which is basically a broken version of (IO (Either ConnError Request)). 3. Parsec returns (Either ParseError a) So there's no hope that I can write anything like: *> do uri <- parseURI uriStr *> doc <- evenSimplerHTTP uri *> parsed <- parse grammar uriStr doc The Failure package contains functions that help when dealing with this problem, so that we can write something very close:
do uri <- try <$> parseURI uriStr doc <- try <$> evenSimplerHTTP uri let parsed = try $ parse grammar uriStr doc
But more importantly, the abstract notion of Failure enables library authors to write code that will easily combine with other failable code. Thanks, pepe [1] - http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-erro...
participants (3)
-
Gregory Crosswhite
-
José Iborra
-
Michael Snoyman