2011-12-16 15 views
15

में एक हो सकता है कि मूल्य निकाला जा रहा है निम्नलिखित को देखते हुए:आईओ

> (liftM2 fromMaybe) (ioError $ userError "OOPS") (return $ Just "ok") 

GHCi मुझे

*** Exception: user error (OOPS) 
बेशक

देता है, fromMaybe सही ढंग से काम कर रहा है:

> (liftM2 fromMaybe) (return $ "not me") (return $ Just "ok") 
"ok" 

लेकिन ऐसा लगता है कि आईओ ऑपरेशन किया जा रहा है और फिर त्याग दिया गया है:

> (liftM2 fromMaybe) (putStrLn "computing.." >> "discarded") (return $ Just "ok") 
computing.. 
"ok" 

ऐसा क्यों हो रहा है? आईओ मोनड लेजर बनाने का कोई तरीका है?

विशेष रूप

, value :: IO (Maybe a) दिया एक (स्वच्छ, संक्षिप्त) जिस तरह से

result <- (liftM2 fromMaybe) err value 

कहने के लिए क्या है और यह परिणाम या एक IOError तदनुसार फेंक खोल दिया है?

उत्तर

12

मुझे नहीं पता कि IO लेज़रियर सही दिशा है। आप जो करना चाहते हैं वह सबसे पहले Maybe पर मिलता है, फिर इसे खत्म करें। यह कई मायनों लिखा जा सकता है, यहाँ एक ही विकल्प है:

test :: IO (Maybe a) -> IO a 
test = (>>= maybe (ioError $ userError "oops") return) 
10

आप-अंकन करने के लिए liftM2 से अनुवाद करते हैं, तो यह स्पष्ट क्यों अपने कोड में विफल रहता है है:

do x <- ioError $ userError "OOPS" 
    y <- return $ Just "ok" 
    return $ fromMaybe x y 

यह पहली लाइन अतीत जाना कभी नहीं होगा , क्योंकि यह बिना शर्त अपवाद फेंक रहा है।

Anthony's suggestion तरीके से कार्य करेंगे, लेकिन अगर आप फेंका विशिष्ट अपवाद के बारे में परवाह नहीं है, आप भी पैटर्न मिलान का उपयोग कर सकते हैं:

do Just result <- value 

तो पैटर्न से मेल नहीं खाता, इस, fail फोन करेगा जो IO मोनड के मामले में अपवाद फेंकता है।

> Just x <- return Nothing 
*** Exception: user error (Pattern match failure in do expression at <interactive>:1:0-5) 
5

एक (स्वच्छ, संक्षिप्त) जिस तरह से करने के लिए ... खोल [यह] परिणाम या एक IOError तदनुसार फेंक क्या?

मैं आपको फेंकने वाली त्रुटियों पर भरोसा करने से बचने की सलाह देता हूं। इसके बजाय, "त्रुटि" को स्पष्ट रूप से संभाल लें:

maybeM :: Monad m => m b -> (a -> m b) -> m (Maybe a) -> m b 
maybeM err f value = do 
    x <- value 
    case x of 
    Just y -> f y 
    Nothing -> err 

-- This can be written simply as: 
maybeM err f value = do 
    x <- value 
    maybe err f x 

-- or even shorter! This is starting to look like Anthony's answer :) 
maybeM err f value = value >>= maybe err f 

फ़ंक्शन के इनपुट और प्रकार स्वयं के लिए बोलना चाहिए। आप इसे Nothing केस, या Just मामले के अंदर मूल्य पर प्रदर्शन करने के लिए एक फ़ंक्शन करने के लिए एक क्रिया देकर इसका उपयोग करते हैं।अपने विशेष आदानों के लिए यह विचार करेंगे की तरह:

maybeM (ioError $ userError "OOPS") return (return $ Just "ok") 

तो अगर आप बिल्कुल, फिर "परिणाम खोल या फेंक एक IOError संक्षिप्त तरीके से" होगा करना होगा:

-- compare to fromJust, a function to be avoided 
fromJustIO :: IO (Maybe a) -> IO a 
fromJustIO = maybeM (ioError $ userError "OOPS") return 

सूचना कैसे इसके लिए प्रकार हस्ताक्षर व्यावहारिक रूप से Maybe a -> a है, जो magicMonadUnwrap :: Monad m => m a -> a का सार है, जो कुछ लाल झंडे को बंद कर देना चाहिए। हालांकि, आप इस अत्याचार को सरल तरीके से उपयोग कर सकते हैं:

result <- fromJustIO value 

फिर भी, मैं यहां अपवादों के उपयोग को दृढ़ता से हतोत्साहित करता हूं। maybeM का उपयोग करके और विफलता की स्थिति में निष्पादित करने के लिए आईओ क्रिया प्रदान करके, बस विस्फोट से अधिक ग़लत तरीके से त्रुटियों को संभालने का प्रयास करें।

+0

चिंता के लिए धन्यवाद, लेकिन यह थोड़ा निराधार है। मैं कई दूसरे-स्तरीय कार्यों में त्रुटियों को फेंक रहा हूं कि प्रत्येक कुछ कॉन्फ़िगरेशन को पकड़ने के लिए आईओओ का थोड़ा सा हिस्सा करता है। प्रथम-स्तरीय कॉन्फ़िगरेशन फ़ंक्शन उन सभी को "पकड़" के साथ प्रयास करता है और किसी भी त्रुटि को अच्छी तरह से स्वरूपित करता है। यह मुझे सभी दूसरी-स्तरीय कार्यों के माध्यम से "हैंडलरर" फ़ंक्शन को थ्रेड करने की आवश्यकता के बिना एक ही स्थान पर मेरी त्रुटि को संभालने की अनुमति देता है। ऐसे परिदृश्य में, त्रुटियां अभी भी एक बुरा विचार हैं? – So8res

+4

So8res: व्यक्तिगत रूप से मेरे पास दूसरे-स्तरीय फ़ंक्शंस 'हो सकता है' मान उत्पन्न करते हैं, और फिर प्रथम-स्तरीय कॉन्फ़िगरेशन फ़ंक्शन या तो उन्हें 'अनुक्रम' या '<$> 'और' <*>' जैसे कुछ के साथ एक साथ जोड़ सकता है, या प्रत्येक को संभाला जा सकता है वांछित के रूप में अलग से संभावित त्रुटि। यह स्वाद का विषय है, लेकिन मेरी राय में, हास्केल में त्रुटियां लगभग हमेशा एक बुरा विचार होती हैं, क्योंकि हमारे पास शक्तिशाली अमूर्तताएं हैं जो हमें 'शायद' लिखने देती हैं। फेंक/पकड़ नियंत्रण प्रवाह तंत्र एफएस शैली से मेल नहीं खाता है जो हास्केल प्रोत्साहित करता है। –

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