हास्केल में अस्तित्व प्रकार पर स्पष्टता


10

मैं हास्केल में अस्तित्व के प्रकारों को समझने की कोशिश कर रहा हूं और एक पीडीएफ http://www.ii.uni.wroc.pl/~dabi/courses/ZPF15/rlasocha/prezentacja.pdf आया

कृपया अब तक की मेरी समझ को कम करें।

  • अस्तित्वगत प्रकारों में उनकी रुचि के प्रकार नहीं प्रतीत होते हैं, लेकिन उनका मिलान करने वाले पैटर्न कहते हैं कि कुछ प्रकार मौजूद हैं जिन्हें हम नहीं जानते कि यह किस प्रकार का है और जब तक हम टाइप करने योग्य या डेटा का उपयोग नहीं करते हैं।
  • हम उन्हें तब उपयोग करते हैं जब हम प्रकारों को छिपाना चाहते हैं (उदा: विषम सूची के लिए) या हमें वास्तव में पता नहीं है कि कंपोजिट समय पर क्या प्रकार हैं।
  • GADTके निहित प्रदान करके अस्तित्व प्रकार का उपयोग कर कोड के लिए स्पष्ट और बेहतर वाक्य रचना प्रदान foralls '

माय डाउट

  • उपरोक्त पीडीएफ के पृष्ठ 20 में यह नीचे दिए गए कोड के लिए उल्लेख किया गया है कि विशिष्ट बफर की मांग करने के लिए फ़ंक्शन के लिए यह असंभव है। ऐसा क्यों है? जब मैं एक फ़ंक्शन का मसौदा तैयार कर रहा हूं, तो मुझे वास्तव में पता है कि मैं किस तरह के बफर का उपयोग करने वाला हूं, मुझे यह नहीं पता होगा कि मैं उस डेटा को क्या बताऊंगा। क्या गलत है :: Worker MemoryBuffer Intअगर वे वास्तव में बफर पर अमूर्त करना चाहते हैं तो उनके पास एक सम प्रकार हो सकता है data Buffer = MemoryBuffer | NetBuffer | RandomBufferऔर एक प्रकार हो सकता है:: Worker Buffer Int
data Worker x = forall b. Buffer b => Worker {buffer :: b, input :: x}
data MemoryBuffer = MemoryBuffer

memoryWorker = Worker MemoryBuffer (1 :: Int)
memoryWorker :: Worker Int
  • जैसा कि हास्केल सी की तरह एक फुल टाइप एरासुर भाषा है, तो यह रनटाइम पर कैसे पता चलता है कि किसको कॉल करना है। क्या यह कुछ ऐसा है जैसे हम कुछ सूचनाओं को बनाए रखने वाले हैं और एक विशाल वी-टेबल ऑफ़ फ़ंक्शंस में पास होते हैं और रनटाइम के दौरान यह वी-टेबल से पता लगाने वाला है? यदि ऐसा है तो यह किस प्रकार की सूचना स्टोर करने वाला है?

जवाबों:


8

GADT के स्पष्ट और बेहतर वाक्यविन्यास प्रदान करने के लिए निहित फोर्ल्स प्रदान करके अस्तित्वगत प्रकारों का उपयोग कर कोड करें

मुझे लगता है कि सामान्य समझौता है कि जीएडीटी सिंटैक्स बेहतर है। मैं यह नहीं कहूंगा कि यह इसलिए है क्योंकि जीएडीटी अंतर्निहित फ़ॉर्म्स प्रदान करते हैं, बल्कि इसलिए कि मूल सिंटैक्स, ExistentialQuantificationएक्सटेंशन के साथ सक्षम किया गया है, संभावित रूप से भ्रमित / भ्रामक है। यह वाक्यविन्यास, निश्चित रूप से, जैसा दिखता है:

data SomeType = forall a. SomeType a

या एक बाधा के साथ:

data SomeShowableType = forall a. Show a => SomeShowableType a

और मुझे लगता है कि आम सहमति यह है कि forallयहां कीवर्ड का उपयोग पूरी तरह से अलग प्रकार के साथ आसानी से भ्रमित होने की अनुमति देता है:

data AnyType = AnyType (forall a. a)    -- need RankNTypes extension

एक बेहतर वाक्यविन्यास ने एक अलग existsकीवर्ड का उपयोग किया होगा , इसलिए आप लिखेंगे:

data SomeType = SomeType (exists a. a)   -- not valid GHC syntax

GADT सिंटैक्स, जो अंतर्निहित या स्पष्ट रूप से उपयोग किया जाता है forall, इन प्रकारों में अधिक समान है, और समझने में आसान लगता है। एक स्पष्ट के साथ भी forall, निम्नलिखित परिभाषा इस विचार के पार हो जाती है कि आप किसी भी प्रकार का मान ले सकते हैं aऔर इसे एक मोनोमोर्फ के अंदर डाल सकते हैं SomeType':

data SomeType' where
    SomeType' :: forall a. (a -> SomeType')   -- parentheses optional

और उस प्रकार के अंतर को देखना और समझना आसान है:

data AnyType' where
    AnyType' :: (forall a. a) -> AnyType'

अस्तित्वगत प्रकारों में उनकी रुचि के प्रकार नहीं प्रतीत होते हैं, लेकिन उनका मिलान करने वाले पैटर्न कहते हैं कि कुछ प्रकार मौजूद हैं जिन्हें हम नहीं जानते कि यह किस प्रकार का है और जब तक हम टाइप करने योग्य या डेटा का उपयोग नहीं करते हैं।

हम उन्हें तब उपयोग करते हैं जब हम प्रकारों को छिपाना चाहते हैं (उदा: विषम सूची के लिए) या हमें वास्तव में पता नहीं है कि कंपोजिट समय पर क्या प्रकार हैं।

मुझे लगता है कि ये बहुत दूर नहीं हैं, हालांकि आपको अस्तित्व के प्रकारों का उपयोग Typeableया उपयोग करने की आवश्यकता नहीं है Data। मुझे लगता है कि यह कहना अधिक सटीक होगा कि अस्तित्वगत प्रकार एक अनिर्दिष्ट प्रकार के आसपास एक अच्छी तरह से टाइप किया हुआ "बॉक्स" प्रदान करता है। बॉक्स एक अर्थ में प्रकार को "छिपा" करता है, जो आपको ऐसे बक्से की एक विषम सूची बनाने की अनुमति देता है, जिसमें शामिल प्रकारों की अनदेखी होती है। यह पता चला है कि SomeType'ऊपर की तरह एक अप्रतिबंधित अस्तित्व, बहुत बेकार है, लेकिन एक विवश प्रकार:

data SomeShowableType' where
    SomeShowableType' :: forall a. (Show a) => a -> SomeShowableType'

आपको "बॉक्स" के अंदर झाँकने के लिए पैटर्न मिलान करने की अनुमति देता है और प्रकार श्रेणी की सुविधाएँ उपलब्ध कराता है:

showIt :: SomeShowableType' -> String
showIt (SomeShowableType' x) = show x

ध्यान दें कि यह किसी भी प्रकार के वर्ग के लिए काम करता है, न कि केवल Typeableया Data

स्लाइड डेक के पेज 20 के बारे में आपके भ्रम के संबंध में, लेखक कह रहा है कि यह एक फ़ंक्शन के लिए असंभव है जो किसी विशेष उदाहरण की मांग करने के लिए एक अस्तित्व लेता है । आप एक विशेष प्रकार का उपयोग करके एक फ़ंक्शन लिख सकते हैं , जैसे :WorkerWorkerBufferWorkerBufferMemoryBuffer

class Buffer b where
  output :: String -> b -> IO ()
data Worker x = forall b. Buffer b => Worker {buffer :: b, input :: x}
data MemoryBuffer = MemoryBuffer
instance Buffer MemoryBuffer

memoryWorker = Worker MemoryBuffer (1 :: Int)
memoryWorker :: Worker Int

लेकिन यदि आप एक फ़ंक्शन लिखते हैं जो एक Workerतर्क के रूप में लेता है , तो यह केवल सामान्य Bufferप्रकार की क्लास सुविधाओं (जैसे, फ़ंक्शन output) का उपयोग कर सकता है:

doWork :: Worker Int -> IO ()
doWork (Worker b x) = output (show x) b

यह मांग करने की कोशिश नहीं कर bसकता कि पैटर्न मिलान के माध्यम से भी एक विशेष प्रकार के बफर बनें:

doWorkBroken :: Worker Int -> IO ()
doWorkBroken (Worker b x) = case b of
  MemoryBuffer -> error "try this"       -- type error
  _            -> error "try that"

अंत में, अस्तित्वगत प्रकारों के बारे में रनटाइम जानकारी शामिल किए गए टाइपकास्ट के लिए निहित "शब्दकोश" तर्कों के माध्यम से उपलब्ध कराई गई है। Workerप्रकार ऊपर बफर और इनपुट के लिए खेतों होने के अलावा, भी एक अदृश्य निहित क्षेत्र के लिए अंक कि है Bufferशब्दकोश (कुछ v-मेज की तरह है, हालांकि यह शायद ही बहुत बड़ी है, यह सिर्फ उचित करने के लिए एक सूचक होता है के रूप में outputसमारोह)।

आंतरिक रूप से, टाइप क्लास Bufferको फ़ंक्शन फ़ील्ड्स के साथ डेटा प्रकार के रूप में दर्शाया जाता है, और उदाहरण इस प्रकार के "शब्दकोशों" हैं:

data Buffer' b = Buffer' { output' :: String -> b -> IO () }

dBuffer_MemoryBuffer :: Buffer' MemoryBuffer
dBuffer_MemoryBuffer = Buffer' { output' = undefined }

अस्तित्वगत प्रकार में इस शब्दकोश के लिए एक छिपा हुआ क्षेत्र है:

data Worker' x = forall b. Worker' { dBuffer :: Buffer' b, buffer' :: b, input' :: x }

और एक ऐसा कार्य जो doWorkअस्तित्वगत Worker'मूल्यों पर कार्य करता है जैसे कि कार्यान्वित किया जाता है:

doWork' :: Worker' Int -> IO ()
doWork' (Worker' dBuf b x) = output' dBuf (show x) b

केवल एक फ़ंक्शन के साथ एक प्रकार के वर्ग के लिए, शब्दकोश वास्तव में एक न्यूटाइप के लिए अनुकूलित है, इसलिए इस उदाहरण में, अस्तित्वगत Workerप्रकार में एक छिपी फ़ील्ड शामिल है जिसमें outputबफर के लिए फ़ंक्शन के लिए फ़ंक्शन पॉइंटर शामिल है , और यह केवल रनटाइम जानकारी की आवश्यकता है द्वारा doWork


क्या अस्तित्व 1 डेटा घोषणाओं के लिए रैंक 1 के समान हैं? अस्तित्व किसी भी ओओपी भाषा की तरह हास्केल में आभासी कार्यों से निपटने का तरीका है?
पवन कुमार

1
मुझे शायद AnyTypeरैंक -2 प्रकार नहीं कहना चाहिए था ; यह सिर्फ भ्रामक है, और मैंने इसे हटा दिया है। कंस्ट्रक्टर AnyTypeएक रैंक -2 फ़ंक्शन की तरह काम करता है, और कंस्ट्रक्टर SomeTypeएक रैंक -1 फ़ंक्शन (बस अधिकांश गैर- मूल प्रकार की तरह) कार्य करता है, लेकिन यह बहुत उपयोगी लक्षण वर्णन नहीं है। यदि कुछ भी है, तो इन प्रकारों को दिलचस्प बनाता है कि वे रैंक 0 हैं (यानी, एक प्रकार के चर पर मात्रा निर्धारित नहीं है और इसलिए स्वयं मोनोमोर्फिक) भले ही वे "मात्रात्मक" प्रकार के हों।
केए बुहर

1
अस्तित्वगत प्रकारों के बजाय टाइप कक्षाएं (और विशेष रूप से उनके विधि कार्य), संभवतः आभासी कार्यों के बराबर सबसे प्रत्यक्ष हास्केल हैं। एक तकनीकी अर्थ में, ओओपी भाषाओं के वर्ग और वस्तुओं को अस्तित्वगत प्रकार और मूल्यों के रूप में देखा जा सकता है, लेकिन व्यावहारिक रूप से, ओस्को "पॉलीमॉर्फ़िज्म" की शैली को पॉसिफ़ोरिज़्म की शैली को अस्तित्व में लाने के लिए मौजूद है, जैसे कि योग के प्रकार। प्रकार कक्षाएं, और / या पैरामीट्रिक बहुरूपता।
केए बुहर

4

उपरोक्त पीडीएफ के पृष्ठ 20 में यह नीचे दिए गए कोड के लिए उल्लेख किया गया है कि विशिष्ट बफर की मांग करने के लिए फ़ंक्शन के लिए यह असंभव है। ऐसा क्यों है?

क्योंकि Worker, जैसा कि परिभाषित किया गया है, केवल एक तर्क लेता है, "इनपुट" फ़ील्ड (प्रकार चर x) का प्रकार । जैसे Worker Intएक प्रकार है। इसके bबजाय टाइप चर , का पैरामीटर नहीं है Worker, लेकिन एक प्रकार का "स्थानीय चर" है, इसलिए बोलने के लिए। इसे पास नहीं किया जा सकता है Worker Int String- जो एक प्रकार की त्रुटि को ट्रिगर करेगा।

यदि हम इसके बजाय परिभाषित करते हैं:

data Worker x b = Worker {buffer :: b, input :: x}

तब Worker Int Stringकाम करेगा, लेकिन अब प्रकार अस्तित्व में नहीं है - हमें अब बफर प्रकार भी पास करना होगा।

जैसा कि हास्केल सी की तरह एक फुल टाइप एरासुर भाषा है, तो यह रनटाइम पर कैसे पता चलता है कि किसको कॉल करना है। क्या यह कुछ ऐसा है जैसे हम कुछ सूचनाओं को बनाए रखने वाले हैं और एक विशाल वी-टेबल ऑफ़ फ़ंक्शंस में पास होते हैं और रनटाइम के दौरान यह वी-टेबल से पता लगाने वाला है? यदि ऐसा है तो यह किस प्रकार की सूचना स्टोर करने वाला है?

यह लगभग सही है। संक्षेप में, हर बार जब आप कंस्ट्रक्टर लागू करते हैं Worker, तो जीएचसी bके तर्कों से प्रकार को प्रभावित करता है Worker, और फिर एक उदाहरण के लिए खोज करता है Buffer b। यदि ऐसा पाया जाता है, तो GHC ऑब्जेक्ट में उदाहरण के लिए एक अतिरिक्त पॉइंटर शामिल करता है। अपने सरलतम रूप में, यह "पॉइंटर टू वीटेबल" से बहुत अलग नहीं है जो ओओपी में प्रत्येक ऑब्जेक्ट में जोड़ा जाता है जब वर्चुअल फ़ंक्शन मौजूद होते हैं।

सामान्य मामले में, यह बहुत अधिक जटिल हो सकता है, हालांकि। कंपाइलर एक अलग प्रतिनिधित्व का उपयोग कर सकते हैं और एक एकल के बजाय अधिक संकेत जोड़ सकते हैं (जैसे, सीधे सभी उदाहरण विधियों में संकेत जोड़ते हैं), अगर वह कोड को गति देता है। इसके अलावा, कभी-कभी कंपाइलर को एक बाधा को संतुष्ट करने के लिए कई उदाहरणों का उपयोग करने की आवश्यकता होती है। उदाहरण के लिए, अगर हमें उदाहरण के लिए स्टोर करने की आवश्यकता है Eq [Int]... तो एक नहीं बल्कि दो हैं: Intसूचियों के लिए एक और दो, और दोनों को संयुक्त करने की आवश्यकता है (रन समय में, अनुकूलन को छोड़कर)।

यह अनुमान लगाना कठिन है कि प्रत्येक मामले में जीएचसी क्या करता है: यह एक टन अनुकूलन पर निर्भर करता है जो ट्रिगर हो सकता है या नहीं।

आप "शब्दकोश आधारित" प्रकारों के कार्यान्वयन के लिए googling की कोशिश कर सकते हैं ताकि यह पता चल सके कि क्या चल रहा है। आप जीएचसी को आंतरिक अनुकूलित कोर के साथ प्रिंट करने -ddump-simplऔर निर्माण किए गए, संग्रहीत, और पास किए गए शब्दकोशों का निरीक्षण करने के लिए भी कह सकते हैं । मुझे आपको चेतावनी देना है: कोर बल्कि निम्न स्तर है, और पहली बार में पढ़ना मुश्किल हो सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.