Catching error / making library functions monadic (in failure)
Dear Hask'lers, I'm working on a graph generator that involves a lot of random selection out of a list of vertices. Basically, there are functions that look a little like this: select vs = randomRM (0,length vs - 1) >>= return . (vs !!) where randomRM is a lot like Random.randomRIO, except that it is not in the IO monad, but rather in any monad, i.e. class Monad m => RandomM m where randomM :: m a randomRM :: (a,a) -> m a instance RandomM IO where randomM = randomIO randomRM = randomRIO The problem is, obviously, that when the list of vertices (vs) is empty, "select vs" will result in an error. The Prelude defines (!!) as: xs !! n | n < 0 = error "Prelude.!!: negative index" [] !! _ = error "Prelude.!!: index too large" (x:_) !! 0 = x (_:xs) !! n = xs !! (n-1) The function 'error' is implemented (at least in GHC) using Control.Exception.throw. Unfortunately, 'catch' does not seem to work. From ghci: Prelude> catch (return $ [] !! 0) (const $ putStrLn "foo" >> return 42) *** Exception: Prelude.(!!): index too large Is there any way to catch errors in functions in libraries (like the Prelude)? This is made even more necessary by the fact that the default implementation for 'fail' in a monad is 'error'. I would already be happy if I could make all applications of error change into applications of fail, as defined in my monad. Preferably, though, I would not even need a failure mechanism in my own monad, but rather have an ErrorMonad (or something similar) and just have class Monad m => ErrorMonad error m | m -> error where onError :: m a -> (error -> a) -> a For now, I simply reimplement the functions I need that give errors. Regards, Philip
Hi Philip, You might want to take a look at the Safe library, which does pretty close to what you request. http://www-users.cs.york.ac.uk/~ndm/safe/ (or cabal install safe) I would happily accept a patch adding *Fail variants that failed in some appropriate Monad if that is what you want. Thanks Neil
-----Original Message----- From: haskell-bounces@haskell.org [mailto:haskell-bounces@haskell.org] On Behalf Of Philip K.F. Hölzenspies Sent: 08 October 2008 3:38 pm To: haskell@haskell.org Subject: [Haskell] Catching error / making library functions monadic (in failure)
Dear Hask'lers,
I'm working on a graph generator that involves a lot of random selection out of a list of vertices. Basically, there are functions that look a little like this:
select vs = randomRM (0,length vs - 1) >>= return . (vs !!)
where randomRM is a lot like Random.randomRIO, except that it is not in the IO monad, but rather in any monad, i.e.
class Monad m => RandomM m where randomM :: m a randomRM :: (a,a) -> m a
instance RandomM IO where randomM = randomIO randomRM = randomRIO
The problem is, obviously, that when the list of vertices (vs) is empty, "select vs" will result in an error. The Prelude defines (!!) as:
xs !! n | n < 0 = error "Prelude.!!: negative index" [] !! _ = error "Prelude.!!: index too large" (x:_) !! 0 = x (_:xs) !! n = xs !! (n-1)
The function 'error' is implemented (at least in GHC) using Control.Exception.throw. Unfortunately, 'catch' does not seem to work. From ghci:
Prelude> catch (return $ [] !! 0) (const $ putStrLn "foo" >> return 42) *** Exception: Prelude.(!!): index too large
Is there any way to catch errors in functions in libraries (like the Prelude)? This is made even more necessary by the fact that the default implementation for 'fail' in a monad is 'error'. I would already be happy if I could make all applications of error change into applications of fail, as defined in my monad. Preferably, though, I would not even need a failure mechanism in my own monad, but rather have an ErrorMonad (or something similar) and just have
class Monad m => ErrorMonad error m | m -> error where onError :: m a -> (error -> a) -> a
For now, I simply reimplement the functions I need that give errors.
Regards, Philip _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
============================================================================== Please access the attached hyperlink for an important electronic communications disclaimer: http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html ==============================================================================
On Wednesday 08 October 2008 16:42:16 Mitchell, Neil wrote:
You might want to take a look at the Safe library, which does pretty close to what you request.
http://www-users.cs.york.ac.uk/~ndm/safe/
(or cabal install safe)
I would happily accept a patch adding *Fail variants that failed in some appropriate Monad if that is what you want.
Dear Mitchell, This is what I want, but only for those functions. I use quite a few functions that produce errors (also from gtk2hs). These functions have been programmed using "error." Would these functions have been programmed with "abort," all would be honkey-dory. That is, unfortunately, not the case, so I'm still looking for a way to catch the existing errors thrown. In the smallest scenario: some_catch_function (error "foo") (error "bar") should result in an error "bar" Regards, Philip
On Wed, 2008-10-08 at 16:58 +0200, Philip K.F. Hölzenspies wrote:
Is there any way to catch errors in functions in libraries (like the Prelude)?
Yes. Use Control.Exception.catch The catch in the Prelude is only for catching IO errors. It cannot catch errors thrown from pure code. Note that you can only catch exceptions in IO.
I use quite a few functions that produce errors (also from gtk2hs). These functions have been programmed using "error." Would these functions have been programmed with "abort," all would be honkey-dory.
Which gtk2hs functions that you're using use error? It would be interesting to know which ones are a problem. I thought gtk2hs mostly throws exceptions in IO (which can be caught in IO) except for some rare cases which would always be programming errors. If you can report them we can fix them. Duncan
On Wed, Oct 8, 2008 at 9:58 AM, Philip K.F. Hölzenspies <p.k.f.holzenspies@utwente.nl> wrote:
some_catch_function (error "foo") (error "bar")
should result in an error "bar"
It's a good thing we've already got a function for that!
Prelude.catch (error "foo") (error "bar") *** Exception: foo
Control.Exception.catch (error "foo") (error "bar") *** Exception: bar
-Antoine
Hi Philip, Philip K.F. Hölzenspies wrote:
some_catch_function (error "foo") (error "bar")
should result in an error "bar"
Take a look at the isBottom function which is defined in module Test.QuickCheck.Batch; it might be of value to you: isBottom :: a -> Bool isBottom a = unsafePerformIO (do a' <- try (Exception.evaluate a) case a' of Left _ -> return True Right _ -> return False) Regards, Martijn.
Dear all, Thank you very much for your reactions. Neil told me I should have posted this in haskell-cafe, so sorry for the inconvenience. Since my problem has since been solved, I figured I would send this "thanks all, it's solve" e-mail to the list, to close the issue. The magic answer turned out to be Control.Exception.evaluate as opposed to return. This was the problem: catch (return $ [] !! 0) (error "foo") (which I had oversimplified by omitting the return) gave *** Exception: Prelude.(!!): index too large while catch (evaluate $ [] !! 0) (error "foo") gave *** Exception: bar even when unsafePerformIO was applied to it. Thank you all, but especially the people that suggested this: Martijn & Koen Regards, Philip
Hello, Op woensdag 08-10-2008 om 15:42 uur [tijdzone +0100], schreef Mitchell, Neil:
I think takeDef should be tailDef, in this page. Greetings. -- marcot Página: http://marcotmarcot.iaaeee.org/ Blog: http://marcotmarcot.blogspot.com/ Correio: marcot@riseup.net XMPP: marcot@jabber.org IRC: marcot@irc.freenode.net Telefone: 25151920 Celular: 98116720 Endereço: Rua Turfa, 639/701 Prado 30410-370 Belo Horizonte/MG Brasil
participants (6)
-
Antoine Latter -
Duncan Coutts -
Marco Túlio Gontijo e Silva -
Martijn van Steenbergen -
Mitchell, Neil -
Philip K.F. Hölzenspies