2012-06-04 8 views
5

मैं अपने मुफ़्त मोनादों के चारों ओर अपने सिर को लपेटने की कोशिश कर रहा हूं; एक सीखने सहायता के रूप में, मैं निम्नलिखित Free प्रकार के लिए एक Show उदाहरण लिखने के लिए प्रबंधित किया है:क्या मैं एक मुक्त मोनाड के लिए इस शो इंस्टेंस में UndecidableInstances के उपयोग को समाप्त कर सकता हूं?

{-# LANGUAGE FlexibleContexts, UndecidableInstances #-} 

-- Free monad datatype 
data Free f a = Return a | Roll (f (Free f a)) 

instance Functor f => Monad (Free f) where 
    return = Return 
    Return a >>= f = f a 
    Roll ffa >>= f = Roll $ fmap (>>= f) ffa 

-- Show instance for Free; requires FlexibleContexts and 
-- UndecidableInstances 
instance (Show (f (Free f a)), Show a) => Show (Free f a) where 
    show (Return x) = "Return (" ++ show x ++ ")" 
    show (Roll ffx) = "Roll (" ++ show ffx ++ ")" 


-- Identity functor with Show instance 
newtype Identity a = Id a deriving (Eq, Ord) 

instance Show a => Show (Identity a) where 
    show (Id x) = "Id (" ++ show x ++ ")" 

instance Functor (Identity) where 
    fmap f (Id x)= Id (f x) 


-- Example computation in the Free monad 
example1 :: Free Identity String 
example1 = do x <- return "Hello" 
       y <- return "World" 
       return (x ++ " " ++ y) 

UndecidableInstances के उपयोग मुझे परेशान कुछ हद तक; क्या इसके बिना करने का कोई तरीका है? Google की सभी कमाई this blog post by Edward Kmett है, जो मूल रूप से वही Show क्लास परिभाषा है जो मैं करता हूं।

+3

'अपरिहार्य इंस्टेंस' वास्तव में चिंताजनक नहीं है। असल में यह सब करता है संकलक 'मुझे विश्वास करो, उदाहरण पीछा समाप्त हो जाएगा'। यदि आपको यह गलत लगता है, तो संदर्भ स्टैक अभी भी कंपाइलर को अनंत लूप में फंसने से रोक देगा। –

उत्तर

11

आप वास्तव में Show के लिए UndecidableInstance आवश्यकता यहाँ समाप्त कर सकते हैं, हालांकि आप Read या Eq के लिए एक ही बात नहीं कर सकते।

चाल आपके मज़ेदार की सामग्री को उस चीज़ के साथ प्रतिस्थापित करना है जो आप सीधे दिखा सकते हैं, लेकिन आप किसी और को इसके बारे में नहीं बताते हैं। नतीजतन, हम सिर्फ करने के लिए हमारे निर्यात को सीमित कर देंगे:

{-# LANGUAGE FlexibleContexts #-} 

module Free (Free(..)) where 

और बातों के लिए कोई डेटा प्रकार बाहर टकरा हम केवल show कर सकते हैं।

newtype Showable = Showable (Int -> ShowS) 

showable :: Show a => a -> Showable 
showable a = Showable $ \d -> showsPrec d a 

instance Show Showable where 
    showsPrec d (Showable f) = f d 

अब, अगर हम कभी नहीं के बारे में किसी को भी Showable बताओ, Show (f Showable) के लिए ही उदाहरणों उदाहरणों कि a को तर्क में बहुरूपी थे, एक शो उदाहरण के लिए ऊपर ज्यादा से ज्यादा विवश हो जाएगा। यह तब तक तर्कसंगत है जब तक कि अंतिम उपयोगकर्ता अन्य एक्सटेंशन का उपयोग करके सक्रिय रूप से आपके कोड को विचलित करने की कोशिश नहीं कर रहा है। कार्यात्मक निर्भरताओं और/या ओवरलैपिंग/अपरिहार्य उदाहरणों के अतिरिक्त कुछ परेशानी संभव है, लेकिन केवल चीजें जो इरादे को विचलित करती हैं, ऐसा कुछ भी नहीं जो आपको क्रैश कर सकता है।

जिस तरह से हम एक निर्णायक Show उदाहरण बना सकते हैं।

data Free f a = Pure a | Free (f (Free f a)) 

instance (Functor f, Show (f Showable), Show a) => Show (Free f a) where 
    showsPrec d (Pure a) = showParen (d > 10) $ showString "Pure " . showsPrec 10 a 
    showsPrec d (Free as) = showParen (d > 10) $ showString "Free " . showsPrec 10 (fmap showable as) 

कार्यान्वयन यहाँ दी FlexibleContexts की आवश्यकता को समाप्त नहीं करता, लेकिन आप वह भी समाप्त कर सकते हैं - यदि आप वास्तव में हास्केल 98 संगतता के लिए जरूरत महसूस - अतिरिक्त कक्षा परतों के एक जोड़े लिख कर।

मैं इस चाल का उपयोग कुछ पैकेजों में करता हूं - जिसमें मेरे ad पैकेज शामिल हैं - अनावश्यक उदाहरणों की आवश्यकता को कम करने के लिए।

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

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