2013-04-17 6 views
12

मैं जानता हूँ कि इस कोड को थोड़ा पागल है, लेकिन किसी को समझा सकते हैं कि ऐसा क्यों isList [42] रिटर्न TrueisList2 [42] जबकि प्रिंट False, और कैसे इसे रोकने के लिए? मैं कुछ अधिक अस्पष्ट जीएचसी प्रकार एक्सटेंशन की बेहतर समझ प्राप्त करना चाहता हूं, और मैंने सोचा कि यह पता लगाने के लिए एक दिलचस्प उदाहरण होगा।हास्केल ओवरलैपिंग/बेतुका उदाहरण

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 
{-# LANGUAGE IncoherentInstances #-} 

class IsList a where 
    isList :: a -> Bool 

instance IsList a where 
    isList x = False 

instance IsList [a] where 
    isList x = True 

isList2 = isList 

main = 
    print (isList 42) >> 
    print (isList2 42) >> 
    print (isList [42]) >> 
    print (isList2 [42]) 
+5

क्योंकि आपका प्रोग्राम असंगत है। वास्तव में, आपने * क्या उम्मीद की *? –

+1

मुझे उम्मीद थी कि आउटपुट 'ट्रू ट्रू' होगा, न कि 'ट्रू फाल्स'। आप आउटपुट को 'सच गलत' क्यों होने की उम्मीद करते हैं? अनौपचारिक कार्यक्रम 'ट्रू ट्रू' क्यों नहीं लौटाएगा? क्या आप कह रहे हैं कि आउटपुट के लिए कोई कारण नहीं है, और नतीजा अनिर्धारित है, और वास्तव में यह वास्तव में 'ट्रू ट्रू' वापस कर सकता है? – Clinton

+1

संभावित डुप्लिकेट [इंकोइन्टेंट इंस्टेंस कैसे काम करता है?] (Http://stackoverflow.com/questions/8371499/how-does-incoherentinstances-work) –

उत्तर

15

यह वास्तव में काफी सरल है। के GHCi पूछना क्या isList2 के प्रकार है दो:

∀x. x ⊢ :t isList2 
isList2 :: a -> Bool 

यह [a] उदाहरण से मेल नहीं खाता (यहां तक ​​कि यह हो सकता है, हालांकि, एकीकरण के माध्यम से), लेकिन यह तुरंत a उदाहरण से मेल नहीं करता है। इसलिए, जीएचसी a उदाहरण का चयन करता है, इसलिए isList2False देता है।

यह व्यवहार ठीक है IncoherentInstances का अर्थ है। असल में, यह इसका एक अच्छा प्रदर्शन है।


उल्लासपूर्वक, अगर आप बस IncoherentInstances अक्षम करें, हम बिल्कुल विपरीत प्रभाव मिलता है, और GHCi अब यह कहते हैं:

∀x. x ⊢ :t isList2 
isList2 :: [Integer] -> Bool 

यह इसलिए होता है क्योंकि isList2 एक शीर्ष स्तर बंधन समारोह सिंटेक्स के उपयोग से परिभाषित नहीं है , और इस प्रकार ड्रेडेड मोनोमोर्फिज्म प्रतिबंध के अधीन है। इसलिए यह उस उदाहरण के लिए विशिष्ट हो जाता है जिसका वास्तव में इसका उपयोग किया जाता है।

∀x. x ⊢ :t isList2 
isList2 :: IsList a => a -> Bool 
∀x. x ⊢ isList2 'a' 
False 
∀x. x ⊢ isList2 "a" 
True 
∀x. x ⊢ isList2 undefined 

<interactive>:19:1: 
    Overlapping instances for IsList a0 arising from a use of `isList2' 

कौन सा उम्मीद अतिव्यापी व्यवहार है, उदाहरण के उपयोग और शिकायतों के आधार पर करता है, तो पसंद अस्पष्ट है चुना के साथ:

IncoherentInstances अक्षम करने के रूप में जोड़ा जा रहा है NoMonomorphismRestriction रूप में अच्छी तरह से, हम इस के बजाय मिलता है।


प्रश्न के संपादन के संबंध में, मुझे विश्वास नहीं है कि वांछित परिणाम बिना एनोटेशन के संभव है।

पहला विकल्प isList2 एक प्रकार का हस्ताक्षर देना है, जो IncoherentInstances को बहुत जल्दी उदाहरण चुनने से रोकता है।

isList2 :: (IsList a) => a -> Bool 
isList2 = isList 

आप शायद एक तर्क के लिए लागू किया जा रहा है बिना कहीं और isList उल्लेख किया है (यहां तक ​​कि परोक्ष रूप से) भी ऐसा ही करने की आवश्यकता होगी।

दूसरा विकल्प संख्यात्मक अक्षरों को असंबद्ध करना और IncoherentInstances अक्षम करना है।

main = 
    print (isList (42 :: Integer)) >> 
    print (isList2 (42 :: Integer)) >> 
    print (isList [42]) >> 
    print (isList2 [42]) 

इस मामले में, वहाँ पर्याप्त जानकारी एक सबसे विशिष्ट उदाहरण लेने के लिए है, तो OverlappingInstances अपनी बात करता है।

+0

मैंने सवाल संपादित किया है। क्या आप उपरोक्त को संकलित करने और 'झूठी झूठी सच्ची सत्य' वापस लौटने के लिए कैसे प्राप्त कर सकते हैं? – Clinton

+0

@ क्लिंटन: ऐसा करने के लिए कोई अच्छा * तरीका नहीं है, मुझे नहीं लगता। मेरे उत्तर में संपादन देखें। –

+0

@ क्लिंटन मैं थोड़ा आगे जाऊंगा और कहूंगा कि ऐसा करने का कोई अच्छा तरीका नहीं हो सकता है। जब टाइपक्लास की बात आती है तो जीएचसी को खुली दुनिया की धारणा का पालन करना होगा, और किसी निश्चित टाइपक्लास की कमी के आधार पर कभी निर्णय नहीं लेना चाहिए। 'गलत सूची' के लिए 'झूठी' वापसी के लिए आपको वास्तव में उस धारणा का उल्लंघन करने की आवश्यकता है। जैसा कि आपको लगता है कि वहां मौजूद नहीं है 'उदाहरण संख्या [ए] जहां ...' क्योंकि इस प्रकार के टाइपक्लास का अस्तित्व 'गलत' से जवाब बदल देगा "यह आपके द्वारा उठाए जाने वाले उदाहरण पर निर्भर करता है", जो कि नहीं है 'बूल' प्रकार का वैध मान। – semicolon

2

निम्नलिखित codeIncoherentInstances की आवश्यकता के बिना काम कर देता है:

{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE OverlappingInstances #-} 

class IsList a where 
    isList :: a -> Bool 

instance IsList a where 
    isList x = False 

instance IsList [a] where 
    isList x = True 

isList2 :: (IsList a) => a -> Bool 
isList2 = isList 

main = do 
    print (isList (42 :: Int)) 
    print (isList [42 :: Int]) 
    print (isList2 (42 :: Int)) 
    print (isList2 [42 :: Int]) 

मैं IncoherentInstances का उपयोग नहीं करने की सलाह देते हैं, यह मुसीबत का एक बहुत कुछ पैदा करने के लिए, जैसा कि आप चुपचाप काफी आसानी से संदर्भ के आधार पर अलग अलग भार के कॉल कर सकते हैं लगता है ।

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