2013-08-26 11 views
9

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

{-# LANGUAGE MultiParamTypeClasses #-} 
{-# LANGUAGE FlexibleInstances  #-} 

data MyError = MyError String deriving (Eq, Show) 

data MyList = MyList [Double] deriving (Eq, Show) 
data NamedList = NamedList String MyList deriving (Eq, Show) 

class MyNum a b ret where 
    myAdd  :: a -> b -> Either MyError ret 
    myLessThan :: a -> b -> Either MyError Bool 

instance MyNum MyList Double MyList where 
    myAdd (MyList xs) x = Right $ MyList $ map (+x) xs 
    myLessThan (MyList xs) x = Right $ all (< x) xs 

instance MyNum NamedList Double NamedList where 
    myAdd (NamedList n l) x = fmap (NamedList n) $ myAdd l x 
    myLessThan (NamedList n l) x = myLessThan l x 

यदि मैं यह संकलित करने के लिए प्रयास करते हैं, मैं त्रुटि

No instance for (MyNum MyList Double ret0) 
    arising from a use of `myLessThan' 
The type variable `ret0' is ambiguous 
Possible fix: add a type signature that fixes these type variable(s) 
Note: there is a potential instance available: 
    instance MyNum MyList Double MyList 
    -- Defined at testing_instances.hs:13:10 
Possible fix: 
    add an instance declaration for (MyNum MyList Double ret0) 
In the expression: myLessThan l x 
In an equation for `myLessThan': 
    myLessThan (NamedList n l) x = myLessThan l x 
In the instance declaration for `MyNum NamedList Double NamedList' 

मिलता क्योंकि संकलक को समझ नहीं सकता जो MyNum का विशिष्ट उदाहरण MyList के लिए उपयोग करने के लिए। यह myAdd के लिए काम करता है क्योंकि MyNum के लिए वापसी प्रकार आसानी से प्राप्त किया गया है, लेकिन यह myLessThan के लिए इसे समझ नहीं सकता है। मैं इस टाइपक्लास का उपयोग करना चाहता हूं ताकि मैं आसानी से ठीक से जुड़ा हुआ त्रुटि संभाल सकूं, और क्योंकि मेरा वास्तविक कोड +, -, *,/<, < =,>, और> =, और मैं चाहता हूं MyNum Double MyList MyList, MyNum MyList MyList MyList, और NamedList के लिए समान उदाहरण के लिए एक उदाहरण बनाने के लिए। जब तक ऐसा करने का कोई आसान तरीका न हो, ऐसा इसलिए है कि मेरे पास पॉलिमॉर्फिक कम्यूटेटिव ऑपरेटर हो सकते हैं।

हालांकि, मैं यह नहीं समझ सकता कि दूसरे उदाहरण के लिए myLessThan में किस प्रकार का हस्ताक्षर जोड़ना है ताकि यह पता चल सके कि किस उदाहरण का उपयोग करना है। मुझे पता है कि अंकगणित और तुलना ऑपरेटर को दो अलग-अलग प्रकार के वर्गों में विभाजित करना एक समाधान होगा, लेकिन यदि संभव हो तो मैं ऐसा करने से बचाना चाहूंगा।

उत्तर

11

आप functional dependencies का उपयोग यह निर्दिष्ट करने के लिए कर सकते हैं कि "ret विशिष्ट रूप से a और b द्वारा निर्धारित किया गया है"।

... 
{-# LANGUAGE FunctionalDependencies #-} 
... 
class MyNum a b ret | a b -> ret where 
... 

यह typechecker की सुविधा देता है पता है कि यह सही उदाहरण परिभाषा चुन सकते हैं, केवल a और में तर्क से b जानते हुए भी अपने:

myLessThan (NamedList n l) x = myLessThan l x 

संकलक अब शिकायत करता है, तो आप एक अतिरिक्त परिभाषित एक ही a और b लेकिन एक अलग ret साथ उदाहरण के लिए, इस तरह के रूप

instance MyNum MyList Double SomeOtherType where 
+0

यह मेरे लिए हास्केल में एक पूर्व अपरिचित निर्माण है, और वास्तव में मुझे जो चाहिए, धन्यवाद! – bheklilr

+2

@bheklilr खुश मैं मदद कर सकता था। आप टाइपफमिलियों के बारे में भी जानना चाहेंगे, जो कि कुछ तरीकों से और अधिक शक्तिशाली काम करना आसान है। – jberryman

4

जैसा कि जेबेरमैन ने नोट किया, आप TypeFamilies का उपयोग कर सकते हैं।

-{-# LANGUAGE FlexibleInstances  #-} 
+{-# LANGUAGE TypeFamilies #-} 

-class MyNum a b ret where 
- myAdd  :: a -> b -> Either MyError ret 
+class MyNum a b where 
+ type Ret a b 
+ myAdd  :: a -> b -> Either MyError (Ret a b) 

-instance MyNum MyList Double MyList where 
+instance MyNum MyList Double where 
+ type Ret MyList Double = MyList 

-instance MyNum NamedList Double NamedList where 
+instance MyNum NamedList Double where 
+ type Ret NamedList Double = NamedList 

मैं सिर्फ associated typeRet के वर्ग पैरामीटर से ret प्रकार चले गए: और यह कैसे है।
यह TypeFamily है - यह कहने के लिए कि कक्षा पैरामीटर a और b से Ret पर कार्य है।

+0

मुझे यह पसंद है कि यह 'MyNum' कक्षा से तीसरे स्पष्ट प्रकार पैरामीटर को हटा देता है। क्या किसी के पास कोई जानकारी है जिस पर कोई बेहतर प्रदर्शन करता है? मुझे थोड़ा और अव्यवस्थित कोड नहीं लगता है अगर इसका मतलब है कि यह तेजी से चलता है, या यदि परिवार परिवार अधिक कुशल हैं, तो मैं उस समाधान का उपयोग करूंगा। – bheklilr

+1

जहां तक ​​मुझे पता है, दोनों समाधानों के बराबर प्रदर्शन होगा।आप संकलित कोर की जांच कर सकते हैं कि कोई अंतर है या नहीं - लेकिन इस मामले में मैं उम्मीद नहीं करता कि वहां एक होना चाहिए। – ocharles

+0

@ocharles मुझे मौका मिलने पर मैं इसे प्रोफाइल करने का प्रयास करूंगा, और मैं बाद में अपने परिणामों के साथ एक अद्यतन पोस्ट करने का प्रयास करूंगा – bheklilr

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