2013-04-25 8 views
15

जाँच पर विचार करें निम्नलिखित कोड:GADT के असफल exhaustiveness

data (:+:) f g a = Inl (f a) | Inr (g a) 

data A 
data B 

data Foo l where 
    Foo :: Foo A 

data Bar l where 
    Bar :: Bar B 

type Sig = Foo :+: Bar 

fun :: Sig B -> Int 
fun (Inr Bar) = 1 

हालांकि मजाक एक संपूर्ण मैच है, जब -Wall साथ संकलन, GHC एक लापता मामले के बारे में शिकायत। हालांकि, अगर मैं एक निर्माता जोड़ें:

data (:+:) f g a = Inl (f a) | Inr (g a) 

data A 
data B 

data Foo l where 
    Foo :: Foo A 
    Baz :: Foo B 

data Bar l where 
    Bar :: Bar B 

type Sig = Foo :+: Bar 

fun :: Sig B -> Int 
fun (Inr Bar) = 1 
fun (Inl Baz) = 2 

फिर GHC सही ढंग से पता लगाता है कि मजाक कुल है।

मैं अपने काम में इसी तरह के कोड का उपयोग कर रहा हूं, और अगर मैं मामलों को याद करता हूं तो जीएचसी चेतावनी उठाना चाहूंगा, और यदि मैं नहीं करता तो चेतावनियां नहीं बढ़ाऊंगा। जीएचसी पहले कार्यक्रम पर शिकायत क्यों कर रहा है, और नकली कन्स्ट्रक्टर या मामलों को जोड़ने के बिना चेतावनियों के बिना संकलन करने के लिए मुझे पहला नमूना कैसे मिल सकता है?

+3

सबसे अच्छा हिस्सा यह है कि 'मजेदार (इनल फू) = ...' एक प्रकार की त्रुटि कैसे जोड़ती है। मैन, आप बस ब्रेक नहीं पकड़ सकते! (लेकिन '_' कामों का उपयोग करके, निश्चित रूप से) –

उत्तर

13

समस्या वास्तव में सूचना दी है:

Warning: Pattern match(es) are non-exhaustive 
     In an equation for `fun': Patterns not matched: Inl _ 

कौन सा सच है। आप Inr कन्स्ट्रक्टर के लिए एक केस प्रदान करते हैं, लेकिन Inl कन्स्ट्रक्टर नहीं।

क्या आप उम्मीद कर रहे हैं कि वहाँ Inl निर्माता का उपयोग करता है प्रकार Sig B के एक मूल्य प्रदान करने के लिए कोई रास्ता नहीं है के बाद से (यह प्रकार Foo B का एक तर्क की आवश्यकता होगी, लेकिन Foo के लिए केवल निर्माता प्रकार Foo A की है) है, कि ghc नोटिस करेगा कि आपको Inl कन्स्ट्रक्टर को संभालने की आवश्यकता नहीं है।

समस्या यह है कि नीचे के कारण हर प्रकार का निवास होता है। प्रकार Sig B के मान हैं जो Inl कन्स्ट्रक्टर का उपयोग करते हैं; यहां तक ​​कि गैर-निचले मान भी हैं। उन्हें में नीचे होना चाहिए, लेकिन वे स्वयं नीचे नहीं हैं। इसलिए कार्यक्रम के लिए fun पर कॉल का मूल्यांकन करना संभव है जो मिलान करने में विफल रहता है; यही वह है जो ghc के बारे में चेतावनी दे रहा है।

तो ठीक करने के लिए है कि आप कुछ इस तरह के fun को बदलने की जरूरत:

fun :: Sig B -> Int 
fun (Inr Bar) = 1 
fun (Inl foo) = error "whoops" 

लेकिन अब निश्चित रूप से आप बाद में Baz :: Foo B जोड़ने अगर यह समारोह होने के लिए इंतजार कर रहे एक टाइम बम है। Ghc के लिए के बारे में चेतावनी देना अच्छा होगा, लेकिन ऐसा करने का एकमात्र तरीका पैटर्न पैटर्न के वर्तमान सेट के मुकाबले पैटर्न foo है। दुर्भाग्यवश कोई वैध पैटर्न नहीं है जिसे आप वहां रख सकते हैं! foo टाइप Foo B के रूप में जाना जाता है, जो केवल नीचे स्थित है, और आप नीचे के लिए एक पैटर्न नहीं लिख सकते हैं।

लेकिन आप इसे उस फ़ंक्शन में पास कर सकते हैं जो पॉलिमॉर्फिक प्रकार Foo a के तर्क को स्वीकार करता है। वह फ़ंक्शन तब सभी मौजूदा-मौजूदा Foo रचनाकारों के विरुद्ध मिल सकता है, ताकि यदि आप बाद में एक जोड़ते हैं तो आपको चेतावनी मिलेगी।कुछ इस तरह:

fun :: Sig B -> Int 
fun (Inr Bar) = 1 
fun (Inl foo) = errorFoo foo 
    where 
     errorFoo :: Foo a -> b 
     errorFoo Foo = error "whoops" 
अब आप ठीक से fun में :+: के सभी निर्माताओं संभाला है

, "असंभव" मामले बस त्रुटियों अगर यह कभी वास्तव में होता है और अगर तुम कभी Baz :: Foo B जोड़ने आप एक के बारे में एक चेतावनी मिलती है errorFoo में गैर-संपूर्ण पैटर्न, जो कम से कम आपको fun पर देखने के लिए निर्देशित कर रहा है क्योंकि इसे संलग्न where में परिभाषित किया गया है।

नकारात्मक पक्ष पर, जब आप Foo (प्रकार Foo A के और अधिक कहते हैं) आप errorFoo के लिए और अधिक मामलों जोड़ना होगा, और कहा कि unfun हो सकता है (हालांकि आसान और यांत्रिक) यदि आप बहुत सारे मिल गया है से संबंधित नहीं कंस्ट्रक्टर्स जोड़ने इस पैटर्न को लागू करने वाले कार्यों का।

+1

एक शर्म की बात है। वास्तविक कोड में,: +: ऑपरेटर का एक संस्करण सैकड़ों रचनाकारों को कुल मिलाकर डेटाटाइप के दर्जनों को जोड़कर घिरा हुआ है। मुझे लगता है कि मुझे इसे चूसना होगा और मेरे आवरण में सुरक्षा की आवश्यकता होगी, और उम्मीद है कि जीएचसी का कुछ भविष्य संस्करण एक समाधान प्रदान करेगा। –

+0

@JamesKoppel यह देखना मुश्किल है कि यह क्या कर सकता है। जीएडीसी गलत तरीके से टाइप किए गए कन्स्ट्रक्टरों को रद्द करने में सही ढंग से सक्षम है, जब आपके दूसरे उदाहरण में दिखाए गए अनुसार जीएडीटी पर पैटर्न मिलते हैं। यह * जीएडीटी वैल्यू * के साथ मिल रहा है जो कि मुद्दा है, और वहां जीएचसी के पास वास्तव में यह जानने का कोई सामान्य तरीका नहीं है कि 'इनल' नहीं होना चाहिए। क्या होगा यदि 'फू एल' को किसी अन्य मॉड्यूल में एक अमूर्त प्रकार के रूप में परिभाषित किया गया था, जिसने रचनाकारों को निर्यात नहीं किया था? फिर जीएचसी के पास अनुमान लगाने का कोई तरीका नहीं होगा कि किस प्रकार 'एल'' एफयू एल वैध है, यह सिर्फ यह जांच रहा है कि ': +: 'के सभी मामलों को संभाला जाता है। – Ben

+0

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

7

मैं आप इस बताने के लिए माफी चाहता हूँ, लेकिन अपना पहला उदाहरण काफी के रूप में संपूर्ण रूप में आपको लगता है कि यह है नहीं है:

∀x. x ⊢ fun (Inl (undefined :: Foo B)) 
*** Exception: Test.hs:48:1-17: Non-exhaustive patterns in function fun 

कष्टप्रद, हाँ, लेकिन उनमें टूट जाता है। ⊥ यही कारण है कि हम अच्छी चीजें नहीं कर सकते हैं। [

+1

मुझे अपरिभाषित चीजों के लिए मामलों को प्रदान करने में खुशी होगी, जब तक कि मैं वास्तव में सिग्नल बी के नए प्रोडक्शन को परिभाषित करता हूं, तब भी मुझे चेतावनी मिलती है। क्या आप ऐसा करने के किसी भी तरीके से सोच सकते हैं उस? –

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