Exception 异常在Haskell中是如何工作的(第二部分)?
我有以下代码:Exception 异常在Haskell中是如何工作的(第二部分)?,exception,haskell,Exception,Haskell,我有以下代码: {-# LANGUAGE DeriveDataTypeable #-} import Prelude hiding (catch) import Control.Exception (throwIO, Exception) import Control.Monad (when) import Data.Maybe import Data.Word (Word16) import Data.Typeable (Typeable) import System.Environment
{-# LANGUAGE DeriveDataTypeable #-}
import Prelude hiding (catch)
import Control.Exception (throwIO, Exception)
import Control.Monad (when)
import Data.Maybe
import Data.Word (Word16)
import Data.Typeable (Typeable)
import System.Environment (getArgs)
data ArgumentParserException = WrongArgumentCount | InvalidPortNumber
deriving (Show, Typeable)
instance Exception ArgumentParserException
data Arguments = Arguments Word16 FilePath String
main = do
args <- return []
when (length args /= 3) (throwIO WrongArgumentCount)
let [portStr, cert, pw] = args
let portInt = readMaybe portStr :: Maybe Integer
when (portInt == Nothing) (throwIO InvalidPortNumber)
let portNum = fromJust portInt
when (portNum < 0 || portNum > 65535) (throwIO InvalidPortNumber)
return $ Arguments (fromInteger portNum) cert pw
-- Newer 'base' has Text.Read.readMaybe but alas, that doesn't come with
-- the latest Haskell platform, so let's not rely on it
readMaybe :: Read a => String -> Maybe a
readMaybe s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
为什么会这样?我知道,;但是这里我们从一个精确的和一个不精确的异常中选择,所以警告不应该适用。我同意哈马尔的观点,这看起来像一个bug。而且它似乎从一段时间以来就固定在脑海里了。对于较旧的
ghc-7.7.20130312
以及今天的头ghc-7.7.20130521
,将引发ErrorArgumentCount
异常,并删除main
的所有其他代码(优化器的bully)。然而,仍然在7.6.3中被打破
7.2系列的行为发生了变化,我从7.0.4中获得了预期的ErrorArgumentCount
,并且(优化的)核心明确了这一点:
Main.main1 =
\ (s_a11H :: GHC.Prim.State# GHC.Prim.RealWorld) ->
case GHC.List.$wlen
@ GHC.Base.String (GHC.Types.[] @ GHC.Base.String) 0
of _ {
__DEFAULT ->
case GHC.Prim.raiseIO#
@ GHC.Exception.SomeException @ () Main.main7 s_a11H
of _ { (# new_s_a11K, _ #) ->
Main.main2 new_s_a11K
};
3 -> Main.main2 s_a11H
}
当空列表的长度不同于3时,请提高ErrorArgumentCount
,否则尝试执行其余操作
对于7.2及更高版本,长度的计算移到分析portStr
之后:
Main.main1 =
\ (eta_Xw :: GHC.Prim.State# GHC.Prim.RealWorld) ->
case Main.main7 of _ {
[] -> case Data.Maybe.fromJust1 of wild1_00 { };
: ds_dTy ds1_dTz ->
case ds_dTy of _ { (x_aOz, ds2_dTA) ->
case ds2_dTA of _ {
[] ->
case ds1_dTz of _ {
[] ->
case GHC.List.$wlen
@ [GHC.Types.Char] (GHC.Types.[] @ [GHC.Types.Char]) 0
of _ {
__DEFAULT ->
case GHC.Prim.raiseIO#
@ GHC.Exception.SomeException @ () Main.main6 eta_Xw
of wild4_00 {
};
3 ->
在哪里
因为应该尊重IO
操作的顺序
throwIO
变量应优先用于throw,以在IO
monad中引发异常,因为它保证了相对于其他IO
操作的排序,而throw不保证
这不应该发生
您可以通过使用when
的NOINLINE
变体,或者在抛出之前执行有效的IO
操作,强制执行正确的顺序,因此,当内联线看到when
除了可能抛出之外什么都不做时,它似乎认为顺序无关紧要
(很抱歉,这不是一个真正的答案,但请尝试在评论中加入这一点;)我觉得这似乎是一个bug。您正在使用哪个GHC版本?我在GHC 7.6.2中看到了同样的行为。@hammar它至少发生在7.6.1和7.4.1中,在#haskell中提出它的人使用的是7.0.x。@DanielWagner这很奇怪,因为在7.0.2和7.0.4中,我得到了
错误的argumentcount
。(也是6.12.3)@DanielFischer Hm,那么我的记忆可能有问题。无论如何,我知道它既不是7.4.1也不是7.6.1,因为我必须更改他发给我的阴谋集团文件,以放松对基地的依赖我已经可以减少了,谢谢。提出了一个错误;我们将看看GHC开发人员是否同意。您可能会了解到它已经被修复了,我刚刚尝试了HEAD,并且按照预期工作。
Main.main1 =
\ (eta_Xw :: GHC.Prim.State# GHC.Prim.RealWorld) ->
case Main.main7 of _ {
[] -> case Data.Maybe.fromJust1 of wild1_00 { };
: ds_dTy ds1_dTz ->
case ds_dTy of _ { (x_aOz, ds2_dTA) ->
case ds2_dTA of _ {
[] ->
case ds1_dTz of _ {
[] ->
case GHC.List.$wlen
@ [GHC.Types.Char] (GHC.Types.[] @ [GHC.Types.Char]) 0
of _ {
__DEFAULT ->
case GHC.Prim.raiseIO#
@ GHC.Exception.SomeException @ () Main.main6 eta_Xw
of wild4_00 {
};
3 ->
Main.main7 =
Text.ParserCombinators.ReadP.run
@ GHC.Integer.Type.Integer Main.main8 Main.main3
Main.main8 =
GHC.Read.$fReadInteger5
GHC.Read.$fReadInteger_$sconvertInt
Text.ParserCombinators.ReadPrec.minPrec
@ GHC.Integer.Type.Integer
(Text.ParserCombinators.ReadP.$fMonadP_$creturn
@ GHC.Integer.Type.Integer)
Main.main3 = case lvl_r1YS of wild_00 { }
lvl_r1YS =
Control.Exception.Base.irrefutPatError
@ ([GHC.Types.Char], [GHC.Types.Char], [GHC.Types.Char])
"Except.hs:21:9-34|[portStr, cert, pw]"