无法在Windows上捕获Haskell异常

时间:2018-04-02 05:08:11

标签: windows haskell exception

当我在ghci上输入以下内容时,会引发异常:

Prelude> import Control.Exception
Prelude Control.Exception> readFile "test.txt" `catch` (const $ return "exception caught!" :: SomeException -> IO String)
"*** Exception: test.txt: hGetContents: invalid argument (invalid byte sequence)

我不明白为什么没有抓住异常。我在Windows 7上使用stack ghci命令运行上面的命令。 (“test.txt”文件包含一些以UTF8编码的随机日文字母,但我预计异常应该被捕获)

有人可以解释原因吗?

2 个答案:

答案 0 :(得分:5)

由于readFile返回一个惰性String,因此在使用之前它不会评估文件内容,在这种情况下,当ghci打印它时。您可以通过强制评估其内容来捕获它。

import Control.Exception
import Control.DeepSeq
(readFile "test.txt" >>= evaluate . force) `catch` (const $ return "exception caught!" :: SomeException -> IO String)

答案 1 :(得分:4)

此问题是由惰性IO和Windows的默认语言环境编码引起的。

与您的假设相反,该文件实际上是在 readFile "test.txt"抓住(const $ return "exception caught!" :: SomeException -> IO String)之后读取的。
通过惰性IO,当实际评估结果值
时,文件内容只读。 您遇到的例外情况仅在阅读内容时引起(如下所述)。

强制评估文件使catch函数捕获:

> (print . length =<< readFile "test.txt") `catch` (const $ putStrLn "Exception caught" :: SomeException -> IO ())
Exception caught

在此示例中,应用length函数时实际读取文件,然后由catch函数捕获。

此外,引发异常的原因是test.txt的某些(可能是第一个)字符与句柄的默认字符编码不兼容, 这是日本Windows中的CP932。

尝试在无效的日文字符前插入一些ASCII字符, 然后你会发现打印时真的抛出了异常(实际评估了test.txt的内容):

$ cat .\test.txt
abc介
$ stack exec ghci
> import Control.Exception
> readFile "test.txt" `catch` (const $ return "exception caught!" :: SomeException -> IO String)
"abc\33673*** Exception: test.txt: hGetContents: invalid argument (invalid byte sequence)

如果您能阅读日语,请参阅由我撰写的https://haskell.jp/blog/posts/2017/windows-gotchas.html的第一部分! :)