2017-11-08 12 views
9

ठीक करता है इस कोड पर विचार करें:एक अप्रयुक्त उदाहरण जोड़ना एक प्रकार की त्रुटि

{-# LANGUAGE FlexibleContexts #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE UndecidableInstances #-} 

module Foo where 

class Foo a 

class SomeClass a 
instance {-# OVERLAPPABLE #-} (Foo a) => SomeClass a 

bar :: (SomeClass a) => a -> Int 
bar = const 0 

foo :: (SomeClass a) => a -> Int 
foo t = let x = bar t in x 

यहाँ, foo कॉल bar, और उसके संदर्भ में SomeClass बाधा का उपयोग कर ऐसा करने के लिए सक्षम होना चाहिए। इसके बजाय, GHC मान लिया गया यह इतना Foo a => SomeClass a उदाहरण का उपयोग करते हुए कार्य करना होगा:

Foo.hs:16:17: 
    Could not deduce (Foo a) arising from a use of ‘bar’ 
    from the context (SomeClass a) 
     bound by the type signature for foo :: SomeClass a => a -> Int 
     at Foo.hs:15:8-32 
    Possible fix: 
     add (Foo a) to the context of 
     the inferred type of x :: Int 
     or the type signature for foo :: SomeClass a => a -> Int 
    In the expression: bar t 
    In an equation for ‘x’: x = bar t 
    In the expression: let x = bar t in x 

वहाँ दो इसे ठीक करने के तरीके हैं:

  1. foo में करने के लिए लाइन instance SomeClass Int जोड़, bar t
  2. को let x = bar t in x बदलते मेरी कार्यक्रम

यहाँ क्या चल रहा है? यह समस्या क्यों हो रही है, और ये क्यों काम करते हैं?


यह उदाहरण, मेरी वास्तविक समस्या से सरल है। बहु भाषा परिवर्तन (arxiv.org/pdf/1707.04600) के लिए क्यूबिक्स ढांचे पर मेरे काम के दौरान मुझे इसका सामना करना पड़ा।

मेरी वास्तविक समस्या में एक बाधा InjF f IdentL FunctionExpL ("एफ एक ऐसी भाषा है जहां पहचानकर्ताओं को फ़ंक्शन कॉल में फ़ंक्शन को इंगित करने के लिए उपयोग किया जा सकता है) शामिल है। मैं एक (overlappable) उदाहरण (FunctionIdent :<: f) => InjF f IdentL FunctionExpL, जो typechecker पर छीन लेता है, मुझे एक नकली Could not deduce FunctionIdent :<: f त्रुटि दे रही है।

यह त्रुटि बनी रहती है जब भी वहाँ एक विशिष्ट Foo के लिए एक उदाहरण InjF Foo IdentL FunctionExpL दायरे में है, इसलिए leftaroundabout का जवाब है, जो अनुमान लगाती है कि अन्य उदाहरण इस समस्या को ठीक करना चाहिए, पूरी कहानी नहीं है।

+2

'{- # ओवरलैप्लेबल # -}' और '{- # LANGUAGE फ्लेक्सिबल कॉन्टैक्स # -} 'कुछ भी प्रभावित नहीं करते हैं। संकलन प्राप्त करने का एक और तरीका: 'चलो' बाध्यकारी में 'x :: Int' जोड़ें। – Alec

+1

शायद सबसे बढ़िया बात यह है कि मॉड्यूल में all_ पर _no उदाहरण नहीं होने पर यह टाइपशेक भी होता है ... – leftaroundabout

उत्तर

3

इसका कारण यह है कि संकलक x जितना संभव हो उतना सामान्य बनाने की कोशिश करता है: यह (SomeClass a) => Int होना चाहिए (ध्यान दें कि यह एक अस्पष्ट प्रकार होगा यदि आपने इसे स्वयं लिखा है)। इस तरह के अजीब स्थानीय प्रकार को रोकने का एक तरीका -XMonoLocalBinds सक्षम करना है, लेकिन मैं वास्तव में इसकी अनुशंसा नहीं करता।

अब, संकलक typechecking पर चला जाता है। उस समय, वहाँ दायरे में ठीक एक instance SomeClass है, अर्थात् कैच-ऑल (Foo a) => SomeClass a, इसलिए वहाँ कोई अस्पष्टता नहीं है। (सिद्धांत रूप में, हास्केल पूरी तरह से अस्पष्टता उदाहरण संकल्प में मनाही है; OVERLAPPABLE इस बाधित लेकिन जब एक की जरूरत है, जैसे आप एक अतिरिक्त instance SomeClass Int है जब वहाँ वास्तव में यह केवल कार्रवाई में कूदता है।) इसलिए, संकलक तुरंत कि उदाहरण के लिए प्रतिबद्ध है और इस तरह के लिए समाप्त c की टाइप-जांच। यह उन परिस्थितियों के लिए जरूरी है जहां आप वास्तव में एक वर्ग की बाधा को एक उदाहरण की बाधा से प्रतिस्थापित करना चाहते हैं। यह दिए गए उदाहरण में बेकार लग सकता है, लेकिन यह वास्तव में महत्वपूर्ण है कि आप प्रपत्र

instance Bar a => SomeClass (Maybe a) 

... जो काफी अपने कोड की तुलना में अधिक उचित है, क्योंकि है कि एक सुपर क्लास के रूप में व्यक्त नहीं किया जा सकता है के उदाहरण है जब बाधा, और बिना किसी ओवरलैप के पूरी तरह ठीक है। संकलक बाधा उन स्थितियों में Bar a करने के लिए नीचे के समाधान को कम नहीं किया है, तो यह वास्तव में Maybe प्रकार नीचे हल नहीं कर सकता था।

संलयन: ओवरलैपिंग उदाहरणों से बचें; यदि संभव हो तो सुपरक्लास घोषणाओं द्वारा एक्सप्रेस क्लास रिलेशनशिप, अन्यथा बाधाओं को एक जीएडीटी में सुधारें (जो अजीब है लेकिन आपको सटीक नियंत्रण देता है जहां बाधा का उपयोग किया जा रहा है)।

+0

1) आपका क्या मतलब है (Foo a => SomeClass a) स्कोप में एकमात्र उदाहरण है? घोषणा में (SomeClass ए) बाधा के बारे में क्या? –

+0

2) इसे सरल बनाने के लिए तुरंत कुछ क्लास (शायद ए) बाधा को सरल बनाने की आवश्यकता क्यों है? घोषित संदर्भ पर पहले से ही यह देखने के बाद अंत तक उस रिज़ॉल्यूशन चरण को क्यों नहीं रोक सकता? –

+0

3) यह मेरे द्वारा दिए गए सरलीकृत उदाहरण की व्याख्या करने में मदद करता है, लेकिन यह वास्तविक उदाहरण के लिए कम हो जाता है। मैं असली पोस्ट देने के लिए अपनी पोस्ट संपादित करूंगा। –

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