2011-12-16 18 views
11

प्रकार वर्गों के साथ चारों ओर खेलने के काम नहीं करता मैं प्रतीत होने वालाTypeclass उदाहरण

class Pair p a | p -> a where 
    one :: p -> a 
    two :: p -> a 

यह काम करने के लिए ठीक है, उदा लगता है के साथ आया था

instance Pair [a] a where 
    one [x,_] = x 
    two [_,y] = y 

हालांकि मैं tuples के लिए परेशानी में भाग लेता हूं। हालांकि निम्नलिखित परिभाषा संकलित ...

instance Pair (a,a) a where 
    one p = fst p 
    two p = snd p 

... मैं इसे इस्तेमाल नहीं कर सकते जैसा कि मैंने उम्मीद:

main = print $ two (3, 4) 

No instance for (Pair (t, t1) a) 
    arising from a use of `two' at src\Main.hs:593:15-23 
Possible fix: add an instance declaration for (Pair (t, t1) a) 
In the second argument of `($)', namely `two (3, 4)' 
In the expression: print $ two (3, 4) 
In the definition of `main': main = print $ two (3, 4) 

वहाँ उदाहरण सही ढंग से परिभाषित करने के लिए एक तरीका है? या मुझे newtype रैपर का सहारा लेना है?

उत्तर

18

आपका उदाहरण वास्तव में ठीक काम करता है। निरीक्षण करें:

main = print $ two (3 :: Int, 4 :: Int) 

यह अपेक्षा के अनुसार काम करता है। तो फिर यह एनोटेशन प्रकार के बिना क्यों काम नहीं करता है? खैर, ट्यूपल के प्रकार पर विचार करें: (3, 4) :: (Num t, Num t1) => (t, t1)। चूंकि संख्यात्मक अक्षर बहुरूप हैं, के लिए उन्हें एक ही प्रकार के होने की आवश्यकता नहीं है। उदाहरण (a, a) के लिए परिभाषित किया गया है, लेकिन उस उदाहरण का अस्तित्व जीएचसी को प्रकारों को एकीकृत करने के लिए नहीं बताएगा (विभिन्न अच्छे कारणों से)। जब तक जीएचसी अन्य माध्यमों से कटौती नहीं कर सकता है कि दो प्रकार समान हैं, तो यह आपके द्वारा इच्छित उदाहरण का चयन नहीं करेगा, भले ही दो प्रकार बराबर हो।

अपनी समस्या का समाधान करने के लिए, आप बस ऊपर बताए गए प्रकार एनोटेशन जोड़ सकते हैं। यदि तर्क कहीं और से आ रहे हैं तो यह आमतौर पर अनावश्यक होता है क्योंकि वे पहले से ही एक ही प्रकार के होने के लिए जाने जाते हैं, लेकिन यदि आप संख्यात्मक अक्षर का उपयोग करना चाहते हैं तो यह बेकार हो जाता है।

एक वैकल्पिक समाधान यह ध्यान रखना है कि उदाहरण के चयन के कारण (a, a) का उदाहरण होने का अर्थ है कि आप (a, b) जैसे उदाहरण भी लिख सकते हैं, भले ही आप चाहें। इसलिए हम इस तरह, प्रकार वर्ग का उपयोग कर एकीकरण के लिए मजबूर करने, एक सा धोखा कर सकते हैं:

instance (a ~ b) => Pair (a,b) a where 

कि ~ संदर्भ के लिए TypeFamilies विस्तार की जरूरत है, मुझे लगता है। यह क्या होता है उदाहरण को किसी भी टुपल पर पहले मिलान करने की अनुमति देता है, क्योंकि इंस्टेंस चयन संदर्भ को अनदेखा करता है। उदाहरण चुनने के बाद, a ~ b संदर्भ समानता टाइप करता है, जो अलग-अलग हैं, लेकिन यदि वे अलग हैं तो एक त्रुटि उत्पन्न करेंगे - लेकिन अधिक महत्वपूर्ण बात यह है कि यदि संभव हो तो प्रकार चर को एकीकृत करेगा। इसका उपयोग करके, main की आपकी परिभाषा एनोटेशन के बिना काम करती है।

+0

धन्यवाद, बहुत रोचक! – Landei

6

समस्या यह है कि एक शाब्दिक संख्या में एक पॉलिमॉर्फिक प्रकार होता है। यह टाइपशेकर के लिए स्पष्ट नहीं है कि दोनों अक्षरों में एक ही प्रकार होना चाहिए (Int)। यदि आप ऐसा कुछ उपयोग करते हैं जो आपके tuples के लिए polymorphic नहीं है, तो आपके कोड को काम करना चाहिए। इन उदाहरणों पर विचार करें:

*Main> two (3,4) 

<interactive>:1:1: 
    No instance for (Pair (t0, t1) a0) 
     arising from a use of `two' 
    Possible fix: add an instance declaration for (Pair (t0, t1) a0) 
    In the expression: two (3, 4) 
    In an equation for `it': it = two (3, 4) 
*Main> let f = id :: Int -> Int -- Force a monomorphic type 
*Main> two (f 3,f 4) 
4 
*Main> two ('a','b') 
'b' 
*Main> two ("foo","bar") 
"bar" 
*Main> two (('a':),('b':)) "cde" 
"bcde" 
*Main>