इस प्रश्न के उत्तर के लिए धन्यवाद मैंने एक प्रकार को इस प्रकार परिभाषित किया है:

data Chain = forall a. Integral a => Chain [[a]] [a] a a

यदि आप चाहें तो मुझे प्रत्येक फ़ील्ड, या तर्क के लिए गेटर फ़ंक्शन लिखना होगा। यहाँ मेरा पहला प्रयास है:

getSimplices (Chain simplices _ _ _) = simplices

लेकिन जब मैं ghc संकलित करने का प्रयास करता हूं तो निम्न त्रुटि देता है:

Chain.hs:10:40: error:
• Couldn't match expected type ‘t’ with actual type ‘[[a]]’
    because type variable ‘a’ would escape its scope
  This (rigid, skolem) type variable is bound by
    a pattern with constructor:
      Chain :: forall a. Integral a => [[a]] -> [a] -> a -> a -> Chain,
    in an equation for ‘getSimplices’
    at Chain.hs:10:15-35
• In the expression: simplices
  In an equation for ‘getSimplices’:
      getSimplices (Chain simplices _ _ _) = simplices
• Relevant bindings include
    simplices :: [[a]] (bound at Chain.hs:10:21)
    getSimplices :: Chain -> t (bound at Chain.hs:10:1)

मैंने इसे इस तरह ठीक किया:

getSimplices (Chain simplices _ _ _) = map (map fromIntegral) simplices

यहां तक ​​​​कि अगर किसी प्रकार का जीएचसी जादू इसे गेट्टर के लिए अश्लील रूप से धीमा होने से रोकता है, तो मुझे लगता है कि इस तरह से कुछ ठीक करना सिर्फ अत्याचारी है। क्या इस तरह के प्रकारों के लिए गेटर्स को परिभाषित करने का कोई बेहतर तरीका है?

2
Eben Kadile 31 अक्टूबर 2017, 00:35

2 जवाब

सबसे बढ़िया उत्तर

आपके अनुसार getSimplices किस प्रकार का होना चाहिए? "स्पष्ट" विकल्प है

getSimplices :: Integral a => Chain -> [[a]]

लेकिन यह आपके कार्यान्वयन के साथ काम नहीं करता है, क्योंकि getSimplices के कॉलर को a चुनने के लिए मिलता है, और इस बात की कोई गारंटी नहीं है कि Chain में संग्रहीत मान उसी प्रकार के हैं जो कॉल करने वाला चाहता है, क्योंकि आपने वह जानकारी फेंक दी थी। विचार करना:

let c = Chain [[1 :: Int]] [2] 3 4
in (getSimplices c) :: [[Integer]]

यह आपके दो प्रकार के हस्ताक्षरों द्वारा स्पष्ट रूप से अनुमत है जो किसी भी इंटीग्रल प्रकार के लिए काम करने का वादा करते हैं, लेकिन स्पष्ट रूप से कुछ रूपांतरण के बिना काम नहीं कर सकते हैं: Int को किसी तरह Integers में बदलना होगा।

जैसा कि टिप्पणियां कहती हैं, यह बल्कि असामान्य है। चेन में टाइप पैरामीटर जोड़ना बहुत आसान होगा, ताकि यह उस प्रकार को ट्रैक कर सके जिसे आपने इसे बनाने के लिए उपयोग किया था, और इसके आउटपुट को उस प्रकार तक भी सीमित कर दिया था:

data Chain a = Chain [[a]] [a] a a

getSimplices :: Chain a -> [[a]]
getSimplices (Chain xs _ _ _) = xs
7
Will Ness 31 अक्टूबर 2017, 01:52

एक अस्तित्वगत प्रकार का निर्माता आवश्यक रूप से a के बारे में "भूल जाता है":

Chain :: Integral a => [[a]] -> [[a]] -> a -> a -> Chain

ध्यान दें कि कैसे परिणामी प्रकार अब a पर निर्भर नहीं करता है।

इसका एक परिणाम यह है कि, जब हम Chain पर पैटर्न मैच करते हैं, तो हम इस बारे में कोई धारणा नहीं बना सकते हैं कि a क्या है। आखिर निर्माण करते समय हम कुछ भी चुन सकते थे। a के बारे में हमारे पास एकमात्र ज्ञान यह है कि यह एक अभिन्न प्रकार होना चाहिए। इसलिए, हम केवल Integral टाइप क्लास के तरीकों का उपयोग करके एक्सेस कर सकते हैं।

सामान्य नियम यह है कि, जब हम Chain पर पैटर्न मैच करते हैं, तो हमें एक प्रकार का मान लौटाना होगा जो a पर निर्भर नहीं है। एक गेट्टर लाइक

getter (Chain _ _ x _) = x

उस नियम का उल्लंघन करें। आखिर वह किस प्रकार का होगा?

getter :: Chain -> ???

पक्का नहीं

getter :: Chain -> a

इसके बजाय इसका मतलब यह होगा कि हम Chain से अपनी इच्छानुसार कोई भी प्रकार निकाल सकते हैं। यह वास्तविक रूप से काम नहीं कर सकता है: हम यह चुनने के लिए स्वतंत्र नहीं हो सकते कि किस प्रकार को रखना है, और फिर यह चुनने के लिए भी स्वतंत्र हो सकते हैं कि किस प्रकार को निकालना है।

हालांकि, हम Integral का फायदा उठाने के लिए क्या कर सकते हैं:

getter :: Chain -> Integer
getter (Chain _ _ x _) = fromIntegral x

Integer a पर निर्भर नहीं है, इसलिए यह ठीक है।

8
chi 31 अक्टूबर 2017, 00:52