आपको जो त्रुटि मिल रही है वह आपको बताती है कि यह किस प्रकार का होना चाहिए; दुर्भाग्यवश, दोनों प्रकार प्रकार चर से संकेतित होते हैं, जो इसे देखना कठिन बनाता है। पहली पंक्ति कहती है कि आपने अभिव्यक्ति प्रकार n
दिया है, लेकिन यह इसे n1
टाइप करना चाहता था। यह जानने के लिए ये क्या हैं, अगले कुछ लाइनों को देखो:
`n1' is a rigid type variable bound by
the type signature for `width' at Dungeon.hs:11:16
यह कहना है कि n1
एक प्रकार चर जिसका मूल्य में जाना जाता है और इस तरह नहीं बदल सकते हैं ("कठोर" है)। चूंकि यह width
के लिए प्रकार हस्ताक्षर से बाध्य है, इसलिए आप जानते हैं कि यह लाइन width :: (Num n) => a -> n
से बाध्य है। दायरे में एक और n
है, इसलिए यह n
का नाम बदलकर n1
(width :: (Num n1) => a -> n1
) कर दिया गया है। इसके बाद, हम
`n' is a rigid type variable bound by
the instance declaration at Dungeon.hs:13:14
है यह आपको कह रहा है कि हास्केल लाइन instance (Num n) => HasArea (Room n) where
से प्रकार n
पाया।रिपोर्ट की जा रही समस्या यह है कि n
, जो width (Room w h) = w
के लिए गणना की गई जीएचसी प्रकार है, n1
जैसा नहीं है, जो कि यह अपेक्षित प्रकार है।
आपको यह समस्या होने का कारण यह है कि width
की आपकी परिभाषा अपेक्षा से कम बहुलक है। width
का प्रकार हस्ताक्षर (HasArea a, Num n1) => a -> n1
है, जिसका अर्थ है कि प्रत्येक प्रकार के लिए जो HasArea
का उदाहरण है, आप प्रकार की संख्या के साथ इसकी चौड़ाई का प्रतिनिधित्व कर सकते हैं। हालांकि, आपकी आवृत्ति परिभाषा में, लाइन width (Room w h) = w
का अर्थ है कि width
में Num n => Room n -> n
है। ध्यान दें कि यह पर्याप्त रूप से polymorphic नहीं है: जबकि Room n
HasArea
का एक उदाहरण है, (Num n, Num n1) => Room n -> n1
टाइप करने के लिए width
की आवश्यकता होगी। यह सामान्य n
को सामान्य n1
के साथ एकीकृत करने में असमर्थता है जो आपकी प्रकार की त्रुटि उत्पन्न कर रहा है।
इसे ठीक करने के कुछ तरीके हैं। एक दृष्टिकोण (और शायद सबसे अच्छा तरीका), जिसे आप sepp2k's answer में देख सकते हैं HasArea
को * -> *
प्रकार का एक प्रकार चर लेना है; इसका मतलब है कि a
एक प्रकार के होने के बजाय, a Int
या a n
जैसी चीजें हैं। Maybe
और []
* -> *
के प्रकार के प्रकार हैं। (सामान्य प्रकार जैसे Int
या Maybe Double
में *
है।) यह शायद सबसे अच्छा शर्त है।
आप जो एक क्षेत्र (जैसे, data Space = Space (Maybe Character)
, जहां width
हमेशा 1
है) तरह *
के कुछ प्रकार है, तथापि, वह काम नहीं करेंगे। width
, आप प्रकार वर्ग खुद को पैरामीटर के रूप चौड़ाई के प्रकार के पारित
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
data Room n = Room n n deriving Show
class Num n => HasArea a n where
width :: a -> n
instance Num n => HasArea (Room n) n where
width (Room w h) = w
अब, इसलिए: एक और तरीका है (जो Haskell98/Haskell2010 के लिए कुछ एक्सटेंशन की आवश्यकता है) HasArea
एक बहु पैरामीटर प्रकार वर्ग बनाने के लिए है (HasArea a n, Num n) => a -> n
प्रकार है। हालांकि, इसका एक संभावित नकारात्मक पक्ष यह है कि आप instance HasArea Foo Int
और instance HasArea Foo Double
घोषित कर सकते हैं, जो समस्याग्रस्त हो सकता है। यदि ऐसा है, तो इस समस्या को हल करने के लिए, आप कार्यात्मक निर्भरताओं का उपयोग कर सकते हैं या परिवारों को टाइप कर सकते हैं। कार्यात्मक निर्भरता आपको यह निर्दिष्ट करने की अनुमति देती है कि एक प्रकार दिया गया है, अन्य प्रकार विशिष्ट रूप से निर्धारित हैं, जैसे कि आपके पास सामान्य कार्य था। उन का उपयोग करना कोड
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}
data Room n = Room n n deriving Show
class Num n => HasArea a n | a -> n where
width :: a -> n
instance Num n => HasArea (Room n) n where
width (Room w h) = w
थोड़ी जानकारी देता है GHC कि अगर यह a
अनुमान लगा सकते हैं, तो यह भी n
अनुमान लगा सकते हैं, वहाँ के बाद से केवल एक n
हर a
के लिए देता है। यह ऊपर चर्चा की गई घटनाओं के प्रकार को रोकता है।
प्रकार परिवारों अधिक अलग हैं:
{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, TypeFamilies #-}
data Room n = Room n n deriving Show
class Num (Area a) => HasArea a where
type Area a :: *
width :: a -> Area a
instance Num n => HasArea (Room n) where
type Area (Room n) = n
width (Room w h) = w
यह कहते हैं एक width
समारोह होने के अलावा में, HasArea
वर्ग भी एक Area
प्रकार (या प्रकार कार्य है कि आप इसके बारे में सोचने के लिए चाहते हैं, तो उस तरफ)। प्रत्येक HasArea a
के लिए, आप निर्दिष्ट करते हैं कि Area a
किस प्रकार है (जो सुपरक्लस बाधा के लिए धन्यवाद, Num
का उदाहरण होना चाहिए), और तब उस प्रकार का उपयोग अपनी तरह की संख्या के रूप में करें।
इस तरह की त्रुटियों को कैसे डिबग करना है?ईमानदारी से, मेरी सबसे अच्छी सलाह है "अभ्यास, अभ्यास, अभ्यास।" समय के साथ, आप यह पता लगाने के लिए और अधिक उपयोग करेंगे (ए) त्रुटियां क्या कह रही हैं, और (बी) शायद गलत क्या हुआ। यादृच्छिक रूप से सामान बदलना सीखना एक तरीका है। सलाह देने का सबसे बड़ा टुकड़ा, हालांकि, Couldn't match expected type `Foo' against inferred type `Bar'
लाइनों पर ध्यान देना है। ये आपको बताते हैं कि कंपाइलर की गणना किस प्रकार की गई है (Bar
) और अपेक्षित (Foo
) इस प्रकार के लिए, और यदि आप सटीक रूप से यह पता लगा सकते हैं कि कौन से प्रकार हैं, तो यह पता लगाने में आपकी सहायता करता है कि त्रुटि कहां है।
वाह, आपने वास्तव में पार्क से बाहर खटखटाया। मैं इन सटीक विषयों पर जा रहा था क्योंकि मैंने तुरंत इसे कई प्रकार के प्रकारों के लिए उपयोग करने की क्षमता की कमी देखी। इतना ही नहीं, मैंने मल्टी पैरा टाइपक्लास को याद किया जो कि उनमें से सबसे आसान है। धन्यवाद। –
+1 मुझे लगता है कि मल्टीपार्मेटर टाइपक्लास + फंडप्स यहां सबसे सरल दृष्टिकोण है। –
+1 शानदार जवाब! – asm