2010-02-16 7 views
6

आप catches के लिए उदाहरण देखते हैं:क्या हास्केल में कस्टम गार्ड तंत्र परिभाषित किया जा सकता है?

f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex), 
        Handler (\ (ex :: IOException) -> handleIO ex)] 

ऐसा लगता है कि catches तरह पैटर्न (दो अपवाद टाइप) पर मैच के लिए एक कस्टम तंत्र परिभाषित किया गया है। क्या मैं गलत हूं, या इसे सामान्यीकृत किया जा सकता है ताकि किसी को उस फ़ंक्शन को परिभाषित किया जा सके जो लैम्ब्डा फ़ंक्शंस को एक निश्चित पैटर्न से मेल कर सके?

संपादित करें: नीचे एफवाईआई कैच के लिए जीएचसी स्रोत है। अगर कोई इस काम पर कुछ प्रकाश डाल सकता है तो यह बहुत अच्छा होगा।

catches :: IO a -> [Handler a] -> IO a 
catches io handlers = io `catch` catchesHandler handlers 

catchesHandler :: [Handler a] -> SomeException -> IO a 
catchesHandler handlers e = foldr tryHandler (throw e) handlers 
    where tryHandler (Handler handler) res 
       = case fromException e of 
       Just e' -> handler e' 
       Nothing -> res 

उत्तर

5

यह Scoped Type Variables काम पर जीएचसी विस्तार है। अधिक जानने के लिए लिंक का पालन करें।

असल में, आप इस प्रकार के बारे में एक दावा परिभाषित करते हैं जिसे मिलान करने से पहले पटर द्वारा पूरा किया जाना चाहिए। तो, हाँ, यह गार्ड के समान है, लेकिन पूरी तरह से नहीं।

यह विशेष उदाहरण कैसे काम करता है? sources of "base" library में डुबकी पता लगाने के लिए कि:

class (Show e) => Exception e where 
    toException :: e -> SomeException 
    fromException :: SomeException -> Maybe e 

data SomeException = forall e . Exception e => SomeException e 

instance Exception IOException where 
    toException = IOException 
    fromException (IOException e) = Just e 
    fromException _ = Nothing 

instance Exception ArithException where 
    toException = ArithException 
    fromException (ArithException e) = Just e 
    fromException _ = Nothing 

हम देखते हैं कि IOException और ArithException typeclass Exception को लागू विभिन्न प्रकार हैं। हम यह भी देखते हैं कि toException/fromException एक रैपिंग/unwrapping तंत्र एक प्रकार IOException, ArithException के मूल्यों से/के प्रकार Exception के मूल्यों में परिवर्तित करने की अनुमति देता है कि, आदि

तो, हम लिखा है सकता है:

f = expr `catches` [Handler handleArith, 
        Handler handleIO] 

handleArith :: ArithException -> IO() 
handleArith ex = .... 

handleIO :: IOException -> IO() 
handleIO ex = .... 

मान लीजिए कि IOException होता है। जब catchesHandler हैंडलर सूची के पहले तत्व को संसाधित करता है, तो यह tryHandler पर कॉल करता है, जो fromException पर कॉल करता है। tryHandler की परिभाषा से यह fromException का रिटर्न प्रकार handleArith के तर्क के समान होना चाहिए। दूसरी ओर, e प्रकार अपवाद है, अर्थात् - (IOException ...)। instance Exception IOException ... इसे तुरंत कि परिणाम Nothing है इस प्रकार से

fromException :: (IOException ...) -> Maybe ArithException 

, तो यह हैंडलर को छोड़ दिया जाता है: तो, प्रकार इस तरह से बाहर खेलने (यह एक वैध हास्केल नहीं है, लेकिन मुझे आशा है कि आप मेरी बात समझ) । उसी कारण से निम्नलिखित हैंडलर को बुलाया जाएगा, क्योंकि fromException(Just (IOException ...)) वापस आ जाएगा।

तो, आपने handleArith और handleIO के प्रकार हस्ताक्षरों का उपयोग यह निर्दिष्ट करने के लिए किया है कि उनमें से प्रत्येक को कब कॉल किया जाएगा, और fromException/toException यह सुनिश्चित करता है कि यह इस तरह से हुआ।

यदि आप चाहते हैं, तो आप स्कैन किए गए प्रकार चर का उपयोग करके f की परिभाषा के अंदर handleIO और handleArith के प्रकारों को भी बाधित कर सकते हैं। तर्कसंगत रूप से, यह आपको बेहतर पठनीयता प्रदान कर सकता है।

अंतिमकरण, स्कॉप्ड प्रकार वेरिएबल्स यहां प्राथमिक खिलाड़ी नहीं हैं। वे सिर्फ सुविधा के लिए उपयोग किया जाता है। इस तरह की चाल खेलने के लिए मुख्य मशीनरी fromException/toException और दोस्तों है। स्कोप्ड टाइप वैरिएबल आपको सिंटैक्स रखने की इजाजत देता है जो गार्ड पैटर्न के करीब मिलकर मिलता है।

+0

स्कॉप्ड प्रकार चर शामिल हैं? मुझे कैच के स्रोत में काम पर यह तंत्र नहीं दिख रहा है। – me2

+0

अपवाद/अपवाद ट्रिकरी से समझाया गया – ADEpt

1
case() of 
()| foo expr1 -> handleFooCase 
    | bar expr2 -> handleBarCase 
    | otherwise -> blah