cannot catch exception

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

cannot catch exception

Kees Bleijenberg

Hi all,

 

The program reads lots of small Text files. readCDFile handles the encoding. Below is the simplest version of readCDFile.

If I call readCDFile "/home/kees/freeDB/inputError/" "blah" (the file blah does not exist) I get:

Left "MyError: /home/kees/freeDB/inputError/blah: openBinaryFile: does not exist (No such file or directory)". The exception is caught by exceptionHandler

If I call readCDFile "/home/kees/freeDB/inputError/" "67129209" I get freeDB: Cannot decode byte '\xa0': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream. The exception is not caught by exceptionHandler (No “MyError: ” in front). The file 67129209 is indeed bad encoded.

I’am using SomeException. Still, this ‘bad encoding exception’ is not caught. Why?

 

Kees

 

import qualified Data.Text as T

import System.FilePath.Posix

import qualified Data.Text.Encoding as TE

import qualified Data.ByteString.Lazy as B

import Prelude hiding (catch)

import Control.Exception

 

main :: IO ()

main = do

          res <- readCDFile "/home/kees/freeDB/inputError/" "67129209"

          print res

 

readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)

readCDFile baseDir fn = do

  catch ( do

            buffer <- B.readFile (combine baseDir fn)

            let bufferStrict = B.toStrict buffer

            return $ Right $ TE.decodeUtf8 bufferStrict

         ) exceptionHandler

 

exceptionHandler :: SomeException -> IO (Either String T.Text)

exceptionHandler e = do let err = show e

                        return $ Left $ "MyError: " ++ err

 

 


Virusvrij. www.avast.com

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: cannot catch exception

David Fox-12
This fixes it by forcing the evaluation of the decode where it can be caught:

return $ Right $! TE.decodeUtf8 bufferStrict

or 

Right <$> evaluate (TE.decodeUtf8 bufferStrict)



On Mon, Mar 4, 2019 at 3:50 AM Kees Bleijenberg <[hidden email]> wrote:

Hi all,

 

The program reads lots of small Text files. readCDFile handles the encoding. Below is the simplest version of readCDFile.

If I call readCDFile "/home/kees/freeDB/inputError/" "blah" (the file blah does not exist) I get:

Left "MyError: /home/kees/freeDB/inputError/blah: openBinaryFile: does not exist (No such file or directory)". The exception is caught by exceptionHandler

If I call readCDFile "/home/kees/freeDB/inputError/" "67129209" I get freeDB: Cannot decode byte '\xa0': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream. The exception is not caught by exceptionHandler (No “MyError: ” in front). The file 67129209 is indeed bad encoded.

I’am using SomeException. Still, this ‘bad encoding exception’ is not caught. Why?

 

Kees

 

import qualified Data.Text as T

import System.FilePath.Posix

import qualified Data.Text.Encoding as TE

import qualified Data.ByteString.Lazy as B

import Prelude hiding (catch)

import Control.Exception

 

main :: IO ()

main = do

          res <- readCDFile "/home/kees/freeDB/inputError/" "67129209"

          print res

 

readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)

readCDFile baseDir fn = do

  catch ( do

            buffer <- B.readFile (combine baseDir fn)

            let bufferStrict = B.toStrict buffer

            return $ Right $ TE.decodeUtf8 bufferStrict

         ) exceptionHandler

 

exceptionHandler :: SomeException -> IO (Either String T.Text)

exceptionHandler e = do let err = show e

                        return $ Left $ "MyError: " ++ err

 

 


Virusvrij. www.avast.com
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: cannot catch exception

Michael Snoyman
Another approach would be to use the Data.Text.IO.hGetContents function on a file handle that explicitly sets its character encoding to UTF-8. This is what we do in rio:


On Mon, Mar 4, 2019 at 3:36 PM David Fox <[hidden email]> wrote:
This fixes it by forcing the evaluation of the decode where it can be caught:

return $ Right $! TE.decodeUtf8 bufferStrict

or 

Right <$> evaluate (TE.decodeUtf8 bufferStrict)



On Mon, Mar 4, 2019 at 3:50 AM Kees Bleijenberg <[hidden email]> wrote:

Hi all,

 

The program reads lots of small Text files. readCDFile handles the encoding. Below is the simplest version of readCDFile.

If I call readCDFile "/home/kees/freeDB/inputError/" "blah" (the file blah does not exist) I get:

Left "MyError: /home/kees/freeDB/inputError/blah: openBinaryFile: does not exist (No such file or directory)". The exception is caught by exceptionHandler

If I call readCDFile "/home/kees/freeDB/inputError/" "67129209" I get freeDB: Cannot decode byte '\xa0': Data.Text.Internal.Encoding.decodeUtf8: Invalid UTF-8 stream. The exception is not caught by exceptionHandler (No “MyError: ” in front). The file 67129209 is indeed bad encoded.

I’am using SomeException. Still, this ‘bad encoding exception’ is not caught. Why?

 

Kees

 

import qualified Data.Text as T

import System.FilePath.Posix

import qualified Data.Text.Encoding as TE

import qualified Data.ByteString.Lazy as B

import Prelude hiding (catch)

import Control.Exception

 

main :: IO ()

main = do

          res <- readCDFile "/home/kees/freeDB/inputError/" "67129209"

          print res

 

readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)

readCDFile baseDir fn = do

  catch ( do

            buffer <- B.readFile (combine baseDir fn)

            let bufferStrict = B.toStrict buffer

            return $ Right $ TE.decodeUtf8 bufferStrict

         ) exceptionHandler

 

exceptionHandler :: SomeException -> IO (Either String T.Text)

exceptionHandler e = do let err = show e

                        return $ Left $ "MyError: " ++ err

 

 


Virusvrij. www.avast.com
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: cannot catch exception

Kees Bleijenberg
In reply to this post by David Fox-12

David,

 

I tried your first suggestion $!. Nothing changed.

When I tried ‘Right <$> evaluate (TE.decodeUtf8 bufferStrict)’ success. handleException catches the exception.

I don’t understand why. Maybe the documentation for the evaluate function below has to do with it:

There is a subtle difference between evaluate x and return $! x, analogous to the difference between throwIO and throw. If the lazy value x throws an exception, return $! x will fail to return an IO action and will throw an exception instead. evaluate x, on the other hand, always produces an IO action; that action will throw an exception upon execution iff x throws an exception upon evaluation.

I don’t fully understand this, but evaluate works. Thanks!

 

Kees

 

readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)

readCDFile baseDir fn = do

  catch ( do

            buffer <- B.readFile (combine baseDir fn)  --reads strict the whole file

            let bufferStrict = B.toStrict buffer

return $ Right $! TE.decodeUtf8 bufferStrict    -- this doesn’t work  

Right <$> evaluate (TE.decodeUtf8 bufferStrict) –- this does   

liftM Right $ evaluate (TE.decodeUtf8 bufferStrict) – this works too  

         ) exceptionHandler

 

 

Van: David Fox [mailto:[hidden email]]

This fixes it by forcing the evaluation of the decode where it can be caught:

 

return $ Right $! TE.decodeUtf8 bufferStrict

 

or 

 

Right <$> evaluate (TE.decodeUtf8 bufferStrict)

 

<snip>


Virusvrij. www.avast.com

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: cannot catch exception

Brandon Allbery
The problem is non-strict evaluation aka "laziness". "return" doesn't force evaluation of the pure expression you give to it (actual I/O involving its value generally would, but return just puts a wrapper around it), so its evaluation is forced later outside of your code to catch it, when the value is actually examined.

In extreme cases you end up using deepseq's rnf to force full evaluation, but here it's enough to force evaluation to WHNF with ($!) before handing the result off to return. With a lazy ByteString you might need rnf, since ($!) would only force part of the structure of the list of chunks but you would need to force all of the chunks' contents to trigger the decode exception.

On Mon, Mar 4, 2019 at 3:27 PM Kees Bleijenberg <[hidden email]> wrote:

David,

 

I tried your first suggestion $!. Nothing changed.

When I tried ‘Right <$> evaluate (TE.decodeUtf8 bufferStrict)’ success. handleException catches the exception.

I don’t understand why. Maybe the documentation for the evaluate function below has to do with it:

There is a subtle difference between evaluate x and return $! x, analogous to the difference between throwIO and throw. If the lazy value x throws an exception, return $! x will fail to return an IO action and will throw an exception instead. evaluate x, on the other hand, always produces an IO action; that action will throw an exception upon execution iff x throws an exception upon evaluation.

I don’t fully understand this, but evaluate works. Thanks!

 

Kees

 

readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)

readCDFile baseDir fn = do

  catch ( do

            buffer <- B.readFile (combine baseDir fn)  --reads strict the whole file

            let bufferStrict = B.toStrict buffer

return $ Right $! TE.decodeUtf8 bufferStrict    -- this doesn’t work  

Right <$> evaluate (TE.decodeUtf8 bufferStrict) –- this does   

liftM Right $ evaluate (TE.decodeUtf8 bufferStrict) – this works too  

         ) exceptionHandler

 

 

Van: David Fox [mailto:[hidden email]]

This fixes it by forcing the evaluation of the decode where it can be caught:

 

return $ Right $! TE.decodeUtf8 bufferStrict

 

or 

 

Right <$> evaluate (TE.decodeUtf8 bufferStrict)

 

<snip>


Virusvrij. www.avast.com
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.


--
brandon s allbery kf8nh

_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.
Reply | Threaded
Open this post in threaded view
|

Re: cannot catch exception

Viktor Dukhovni
In reply to this post by Kees Bleijenberg
On Mon, Mar 04, 2019 at 09:26:41PM +0100, Kees Bleijenberg wrote:

> readCDFile :: FilePath -> FilePath -> IO (Either String T.Text)
> readCDFile baseDir fn = do
>   catch ( do
>             buffer <- B.readFile (combine baseDir fn)  --reads strict the whole file
>             let bufferStrict = B.toStrict buffer
>             return $ Right $! TE.decodeUtf8 bufferStrict        -- this doesn’t work
>             Right <$> evaluate (TE.decodeUtf8 bufferStrict)     –- this does
>             liftM Right $ evaluate (TE.decodeUtf8 bufferStrict) -- this works too
>          ) exceptionHandler

Take a close look at the three increasingly strict examples below:

    ghci> do { x <- return $ Right $ undefined ; putStrLn "delayed..."; case x of { Right _ -> return 1; _ -> return 0 } }
    delayed...
    1

    ghci> do { x <- return $ Right $! undefined; putStrLn "delayed..."; case x of { Right _ -> return 1; _ -> return 0 } }
    delayed...
    *** Exception: Prelude.undefined
    CallStack (from HasCallStack):
      error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err
      undefined, called at <interactive>:8:29 in interactive:Ghci3

    ghci> do { x <- return $! Right $! undefined ; putStrLn "delayed..."; case x of { Right _ -> return 1; _ -> return 0 } }
    *** Exception: Prelude.undefined
    CallStack (from HasCallStack):
      error, called at libraries/base/GHC/Err.hs:78:14 in base:GHC.Err
      undefined, called at <interactive>:9:30 in interactive:Ghci3

While "Right $! x" is strict in x, "return $ Right $! x" is not!
You need "return $! Right $! x" to make that happen.

--
        Viktor.
_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.