How do exceptions work in Haskell (part two)? -
i have following code:
{-# 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 = 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 alas, doesn't come -- latest haskell platform, let's not rely on readmaybe :: read => string -> maybe readmaybe s = case reads s of [(x, "")] -> x _ -> nothing
its behavior differs when compiled optimizations on , off:
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 pattern [portstr, cert, pw]
why this? aware imprecise exceptions can chosen arbitrarily; here choosing 1 precise , 1 imprecise exception, caveat should not apply.
i agree hammar, looks bug. , seems fixed in head since time. older ghc-7.7.20130312
today's head ghc-7.7.20130521
, wrongargumentcount
exception raised , other code of main
removed (bully optimiser). still broken in 7.6.3, however.
the behaviour changed 7.2 series, expected wrongargumentcount
7.0.4, , (optimised) core makes clear:
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 }
when length of empty list different 3, raise wrongargumentcount
, otherwise try rest.
with 7.2 , later, evaluation of length moved behind parsing of 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 ->
where
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]"
since throwio
supposed respect ordering of io
actions,
the
throwio
variant should used in preference throw raise exception withinio
monad because guarantees ordering respect otherio
operations, whereas throw not.
that should not happen.
you can force correct ordering using noinline
variant of when
, or performing effectful io
action before throwing, seems when inliner sees when
nothing except possibly throwing, decides order doesn't matter.
(sorry, not real answer, try fit in comment ;)
Comments
Post a Comment