2013-05-21 8 views
17

は、私は、次のコードを持っている:オンとオフを最適化してコンパイルするときハスケル(2部)ではどのように例外処理が行われますか?

{-# 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 

その動作が異なります。

crabgrass:~/tmp/signserv/src% ghc -fforce-recomp Main.hs && ./Main 
Main: WrongArgumentCount 
crabgrass:~/tmp/signserv/src% ghc -O -fforce-recomp Main.hs && ./Main 
Main: Main.hs:20:9-34: Irrefutable pattern failed for pattern [portStr, cert, pw] 

これはなぜですか?私はそれを知っていますimprecise exceptions can be chosen from arbitrarily;ここでは厳密な例外と不正確な例外の1つを選択しているため、警告は適用されません。

+0

これは私のバグのようです。どのGHCバージョンを使用していますか?私はGHC 7.6.2と同じ動作をします。 – hammar

+0

@hammar少なくとも7.6.1と7.4.1で発生し、#haskellでそれを持ち上げた人は7.0.xを使用していました。 –

+0

@DanielWagnerそれは奇妙です。なぜなら、7.0.2と7.0.4では 'WrongArgumentCount'が得られるからです。 (また6.12.3) –

答えて

14

私はhammarに同意します。これはバグのようです。それはしばらくしてからHEADで修正されたようです。 ghc-7.7.20130312と今日のHEAD ghc-7.7.20130521では、WrongArgumentCountの例外が発生し、他のすべてのコードmainが削除されます(オプティマイザの場合は無効です)。しかし、まだ7.6.3で壊れました。

挙動は7.2シリーズで変更、私は7.0.4から予想WrongArgumentCountを取得し、(最適化)コアをクリアすることを行う:

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と異なる場合WrongArgumentCountを引き上げます。それ以外の場合は、残りの作業を実行してください。 7.2以降では、長さの評価はportStrの解析の背後に移動されると

throwIOので

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]" 

IOアクション、

の順序を尊重することになっています

throwIOIOモナド内で例外を発生させるためにスローするのに優先して使用する必要があります。これは、他のIO操作に対して順序を保証するためです。

このようなことは起こりません。

あなたは、または投げる前に、副作用のIOアクションを実行することによりwhenNOINLINEバリアントを使用して、正しい順序を強制することができますので、インライン化whenはおそらく投げ以外何もしないことを見たとき、それは順序がdoesnのことを決定したようです問題ありません。

(申し訳ありませんが、実際の回答ではありませんが、それをコメントに入れようとしてください)

+1

ありがとうございます。バグ[ここ](http://hackage.haskell.org/trac/ghc/ticket/7924)に提出。 GHC開発者が同意するかどうかを確認します。 –

+0

あなたはおそらくそれがすでに修正されていることを知っているでしょう、私はHEADを試しました、そして、それは期待どおりに動作します。 –

関連する問題