2013-05-21 12 views
17

Aşağıdaki kod var:Haskell'de istisnalar nasıl çalışıyor (ikinci bölüm)?

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] 

neden şudur:

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

Onun davranış ve kapalı optimizasyonlar ile derlenmiş farklılık? Ben imprecise exceptions can be chosen from arbitrarily; ama burada bir tek ve kesin olmayan istisnadan birini seçiyoruz, böylece uyarı geçerli olmamalıdır.

+0

Bu bana bir hata gibi görünüyor. Hangi GHC sürümünü kullanıyorsunuz? Aynı davranışı GHC 7.6.2 ile görüyorum. – hammar

+0

@hammar Burada en az 7.6.1 ve 7.4.1'de oluyor ve onu #haskell'e getiren kişi 7.0.x kullanıyordu. –

+0

@DanielWagner Bu garip, çünkü 7.0.2 ve 7.0.4'te, WrongArgumentCount'u alıyorum. (Ayrıca 6.12.3) –

cevap

14

Hammar'a katılıyorum, bu bir hataya benziyor. Ve bir süreden beri HEAD'de sabit görünüyor. Eski bir ghc-7.7.20130312 ve bugünün KAFA ghc-7.7.20130521 ile WrongArgumentCount istisnası kaldırıldı ve diğer tüm kod main kaldırıldı (iyimser için kabadayı). Yine de 7.6.3'te kırılmış.

davranış 7.2 serisi ile değiştirilir, I 7.0.4 den WrongArgumentCount beklenen ve (optimize edilmiş), çekirdek açık hale getirir olsun:

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 
    } 

boş liste uzunluğu 3 farklı olduğunda WrongArgumentCount'u kaldırın, aksi halde geri kalanını yapmaya çalışın. 7.2 ve üstü ile

, uzunluğu değerlendirilmesi portStr ayrıştırma arkasında taşınır: throwIO yana

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 eylemlerin sıralamasını dikkate gerekiyordu

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

,

throwIO varyantı does not atmak oysa, diğer IO operasyonları ile ilgili olarak sipariş garanti ediyor çünkü IO monad içinde bir istisna yükseltmek atmak için tercih kullanılmalıdır. olmamalı

.

Siz veya atmadan önce bir effectful IO eylemi gerçekleştirerek when bir NOINLINE varyantı kullanarak doğru sıralamayı zorlayabilir, nedenle inliner when muhtemelen atma dışında bir şey yapmaz görür, bunun sırası gelmez olduğuna karar verir gibi görünüyor önemli değil

(Maalesef, gerçek bir yanıt değil, ancak bunu bir yoruma ekleyin;)

+1

Teşekkürler. Bir hata attı [burada] (http://hackage.haskell.org/trac/ghc/ticket/7924); GHC devlerinin aynı fikirde olup olmadığını göreceğiz. –

+0

Muhtemelen bunun zaten sabit olduğunu öğreneceksiniz, sadece KAFA çalıştım ve beklendiği gibi çalışıyor. –