2012-05-05 11 views
9

निम्नलिखित हास्केल कोड में:मैं हास्केल में पढ़ने के अपवाद कैसे प्राप्त करूं?

data Cmd = 
    CmdExit | 
    CmdOther 
    deriving (Read, Show) 

guiString2Cmd s = 
    (return (read s :: Cmd)) `catch` \(e :: SomeException) -> return CmdExit 

अगर मैं कार्य करें:

guiString2Cmd "CmdOther" 

यह सब ठीक काम करता है। हालांकि अगर मैं करता हूं:

guiString2Cmd "some wrong string" 

कोड CmdExit के मूल्यांकन के बजाय कोड क्रैश हो जाता है।

मैं कोड को क्रैश करने के बजाय अपवाद को कैसे संभाल सकता हूं?

+0

का उपयोग पढ़ने एक बेहतर विचार वास्तव में हो सकती है ... – mbrodersen

+1

हाँ, सबसे अच्छा शुद्ध अपवाद को संभालने का तरीका इसे पहले स्थान पर नहीं बनाना है। – dave4420

+1

रिकॉर्ड के लिए, अपवाद ('read' द्वारा फेंकने सहित) को केवल 'नियंत्रण' अपवाद 'में दिए गए कार्यों का उपयोग करके आईओ मोनैड में पकड़ा जा सकता है। मैं और विस्तार से नहीं जाऊंगा क्योंकि 'पढ़ता है' एक बेहतर समाधान है। –

उत्तर

13

reads समारोह है, जो कुल है का उपयोग करें, और एक Maybe के रूप में विफलता के मामले लपेट, इसलिए जैसे:

maybeRead :: Read a => String -> Maybe a 
maybeRead s = case reads s of 
    [(x, "")] -> Just x 
    _   -> Nothing 

maybeRead सुरक्षित पार्स करने के लिए काफी बेहतरीन ज़रिया है।

+4

यह फ़ंक्शन हाल ही में ['Text.Read.readMaybe'] (http://www.haskell.org/ghc/docs/latest/html/libraries/base/Text-Read.html#v:readMaybe) के रूप में उपलब्ध है 'बेस' के संस्करण। 'IO' के मामले में – hammar

2

एक समाधान का उपयोग केवल पढ़ता है।

2

मैं व्यक्तिगत रूप से safe पैकेज से readMay का उपयोग कर की सिफारिश करेंगे:

readMay :: Read a => String -> Maybe a 

तो फिर तुम या तो 'हो सकता है कि एक' परिणाम, उपयोग पर 'शायद' पैटर्न मैचों की, या यहाँ तक कि 'शायद' इकाई का उपयोग कर सकते परिणाम को संभालने के लिए।

1

मौजूद है एक इकाई के अंदर पढ़ने का एक मुहावरा:

> readM "CmdOther" :: IO Cmd 
CmdOther 
> readM "Cmd?Other" :: IO Cmd 
*** Exception: user error (Failed to parse: "Cmd?Other") 

क्योंकि failIO के मामले की जो कि में एक IOError अपवाद फेंकता है:

readM :: (Monad m, Read a) => String -> m a 
readM s | [x] <- [x | (x, "") <- reads s] = return x 
     -- or @[x] <- [x | (x, _) <- reads s] = return [email protected] 
     -- to allow the garbage at the end of parsed string 
     | otherwise = fail $ "Failed to parse: \"" ++ s ++ "\"" 

यह IO इकाई के लिए असुरक्षित है , संभाला जा सकता है:

*Main> (readM "Cmd?Other" :: IO Cmd) `catch` const (return CmdOther) 
CmdOther 

और Maybe इकाई के मामले में सुरक्षित:

> readM "CmdOther" :: Maybe Cmd 
Just CmdOther 
> readM "Cmd?Other" :: Maybe Cmd 
Nothing 

क्योंकि fail इस मामले में const Nothing है।

वैसे भी, अगर आप एक हस्ताक्षर String -> Cmd साथ कुल समारोह guiString2Cmd चाहते आप यह सिर्फ readM तरह लिख सकते हैं:

guiString2Cmd :: String -> Cmd 
guiString2Cmd s | [x] <- [x | (x, "") <- reads s] = x 
       | otherwise = CmdExit 

और उसके बाद:

> guiString2Cmd "CmdOther" 
CmdOther 
> guiString2Cmd "Cmd?Other" 
CmdExit 

थोड़े अधिक सामान्य दृष्टिकोण।

* के लिए प्रकार:

class Failable0 t where 
    fail0 :: t 

readG0 :: (Failable0 t, Read t) => String -> t 
readG0 s | [x] <- [x | (x, "") <- reads s] = x 
     | otherwise = fail0 

तो:

instance Failable0 Cmd where 
    fail0 = CmdExit 

* -> * के लिए प्रकार:

class Failable f where 
    fail :: String -> f a 

class Functor f => Pointed f where 
    pure :: a -> f a 

readG :: (Failable f, Pointed f, Read a) => String -> f a 
readG s | [x] <- [x | (x, "") <- reads s] = pure x 
     | otherwise = fail $ "Failed to parse: \"" ++ s ++ "\"" 
+0

'विफल'' त्रुटि' नहीं है, यह 'IOError' अपवाद फेंकता है। 'असफल' की तुलना करें ओह नहीं! " \ 'पकड़ \' (\ e -> प्रिंट (ई :: IOError)) 'त्रुटि के साथ" ओह नहीं! " \ 'पकड़ \' (\ e -> प्रिंट (ई :: IOError)) ' –

+0

@benmachine सही,' विफल "?" 'पकड़ो' कॉन्स (वापसी "!") '' => '"! "' और 'त्रुटि"? " 'पकड़ो' कॉन्स (वापसी "!") '' => '*** अपवाद:?'। स्पष्टीकरण के लिए धन्यवाद। – JJJ

संबंधित मुद्दे