भरोसेमंद रूप से टाइप क्यों नहीं किया जाता?


161

मैंने कई स्रोतों को देखा है कि "हास्केल धीरे-धीरे एक भरोसेमंद भाषा बनती जा रही है"। निहितार्थ यह लगता है कि अधिक से अधिक भाषा एक्सटेंशन के साथ, हास्केल उस सामान्य दिशा में बह रहा है, लेकिन अभी तक नहीं है।

मूल रूप से दो बातें हैं जो मैं जानना चाहूंगा। पहला, काफी सरल रूप से, "एक भरोसेमंद रूप से टाइप की जाने वाली भाषा" होने का वास्तव में क्या मतलब है ? (उम्मीद है कि इसके बारे में बहुत तकनीकी होने के बिना।)

दूसरा सवाल है ... क्या खामी है? मेरा मतलब है, लोग जानते हैं कि हम इस तरह से आगे बढ़ रहे हैं, इसलिए इसका कुछ लाभ होना चाहिए। और फिर भी, हम अभी तक वहां नहीं हैं, इसलिए सभी लोगों को रोकने के लिए कुछ नकारात्मक पहलू होना चाहिए। मुझे यह आभास हो जाता है कि समस्या जटिलता में वृद्धि है। लेकिन, वास्तव में यह समझना नहीं है कि निर्भर टाइपिंग क्या है, मुझे यकीन नहीं है।

मुझे क्या पता है कि हर बार जब मैं एक भरोसेमंद टाइप की गई प्रोग्रामिंग भाषा के बारे में पढ़ना शुरू करता हूं, तो पाठ पूरी तरह से समझ से बाहर है ... शायद यही समस्या है। (?)


10
सीधे शब्दों में कहें, आप ऐसे प्रकार लिख सकते हैं जो शब्दों (गणनाओं) पर निर्भर करते हैं। यह आपके प्रोग्राम के प्रत्येक पहलू के प्रकारों को निर्दिष्ट करने के लिए पर्याप्त है, और इसलिए इसका मतलब है कि टाइप सिस्टम पूर्ण प्रोग्राम विनिर्देश के लिए सक्षम है। समस्या यह है कि क्योंकि प्रकार गणना पर निर्भर करते हैं, इसलिए टाइपिंग चेकिंग (सामान्य रूप से असंभव) करना बहुत मुश्किल है।
GMANNICKG

27
@GManNickG: टाइप जाँच पूरी तरह से संभव है। प्रकार का अनुमान एक और मामला है, लेकिन फिर जीएचसी के विभिन्न एक्सटेंशन लंबे समय से इस विचार को छोड़ देते हैं कि सभी प्रकारों का अनुमान लगाना संभव है।
सीए मैक्कैन

7
अगर मैं सही ढंग से समझता हूं, तो यह दोष यह है कि आश्रित टाइपिंग सही करना (जैसे, एक तरह से जो उपयोग करने योग्य और अच्छी तरह से स्थापित है) कठिन है , और हम नहीं जानते कि यह अभी तक कितना है।
20

1
@CAMcCann: हाँ, मेरी गलती है।
GManNickG

4
मुझे नहीं लगता कि किसी ने भी एक बड़ा व्यावहारिक दोष बताया है: यह लिखना कि आपके सभी कोड सही हैं, बहुत ही अजीब तरह से थकाऊ है। क्योंकि आप स्वचालित रूप से टाइप इंफ़ेक्शन नहीं कर सकते हैं ("हेला शक्तिशाली" लॉजिक में प्रमेय से संबंधित), आपको प्रूफ के रूप में अपने प्रोग्राम के लिए एनोटेशन लिखना होगा। यह स्पष्ट रूप से थोड़ी देर के बाद कष्टप्रद और कठिन हो जाता है, विशेष रूप से अधिक विस्तृत विचित्र जादू के लिए जो लोग आमतौर पर हास्केल में करते हैं। इन दिनों हम जो सबसे नज़दीक आ रहे हैं, वह ऐसी भाषाएँ हैं जो हमारे लिए ऐसा करती हैं या हमें प्राइमेटिक्स का एक अच्छा सेट देती हैं।
क्रिस्टोफर मिकीन्स्की

जवाबों:


21

आश्रित टाइपिंग वास्तव में सिर्फ मूल्य और प्रकार के स्तरों का एकीकरण है, इसलिए आप प्रकारों पर मानों को परिमार्जित कर सकते हैं (हास्केल में प्रकार की कक्षाओं और पैरामीट्रिक बहुरूपता के साथ पहले से ही संभव है) और आप मानों पर परिमार्जन प्रकारों (नहीं, सख्ती से बोलना, अभी तक संभव हैस्केल में , हालांकि DataKindsबहुत करीब हो जाता है)।

संपादित करें: जाहिर है, इस बिंदु से आगे, मैं गलत था (देखें @ pigworker की टिप्पणी)। मैं इसे मिथकों के एक रिकॉर्ड के रूप में संरक्षित कर चुका हूँ, जिसे मैंने खिलाया है। : पी


मैंने जो सुना है, उससे पूर्ण निर्भर टाइपिंग में जाने के साथ मुद्दा यह है कि यह प्रकार और मूल्य स्तरों के बीच चरण प्रतिबंध को तोड़ देगा जो हास्केल को मिटाए गए प्रकारों के साथ कुशल मशीन कोड में संकलित करने की अनुमति देता है। तकनीक के हमारे मौजूदा स्तर के साथ, एक भरोसेमंद टाइप की गई भाषा को किसी बिंदु पर दुभाषिया के माध्यम से जाना चाहिए (या तो तुरंत, या निर्भरता से टाइप किए गए बायटेकोड या समान होने के बाद)।

यह अनिवार्य रूप से एक मौलिक प्रतिबंध नहीं है, लेकिन मैं व्यक्तिगत रूप से किसी भी मौजूदा शोध से अवगत नहीं हूं जो इस संबंध में आशाजनक लगता है लेकिन यह पहले से ही जीएचसी में नहीं आया है। अगर किसी और को अधिक पता है, तो मुझे सही होने में खुशी होगी।


46
आप जो कहते हैं वह लगभग पूरी तरह से झूठ है। मैं आपको पूरी तरह से दोष नहीं दे रहा हूं: यह मानक मिथकों को तथ्य के रूप में दोहराता है। एडविन ब्रैडी की भाषा, इदरिस, टाइप इरेज़र करती है (क्योंकि कोई रन-टाइम व्यवहार प्रकारों पर निर्भर नहीं करता है) और एक काफी मानक लैम्ब्डा-उठा हुआ सुपरकम्बिनेटर एन्कोडिंग उत्पन्न करता है जिसमें से स्टॉक जी-मशीन तकनीकों का उपयोग करके कोड उत्पन्न होता है।
सुअर का बच्चा

3
एक साइड नोट के रूप में, किसी ने हाल ही में मुझे इस पेपर की ओर इशारा किया । मैं जो बता सकता हूं, वह हास्केल को भरोसेमंद रूप से बनाएगा (यानी, टाइप स्तर की भाषा निर्भरता से टाइप की जाएगी), जो जितना करीब होगा उतना ही हमें कभी भी मिल सकता है।
1946 में पथरियन की लौ

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

13
हास्केल पर निर्भर प्रकार के बहुत सारे व्यावहारिक सवाल हैं। एक बार जब हमें निर्भर फ़ंक्शन स्थान का यह प्रतिबंधित रूप मिल गया है, तो हम अभी भी इस सवाल का सामना करते हैं कि किस प्रकार के स्तर पर अनुमति दी गई मूल्य भाषा के टुकड़े को कैसे बढ़ाया जाए, और इसका समीकरण सिद्धांत क्या होना चाहिए (जैसे हम 2 + 2 चाहते हैं 4 हो, और ऐसे)। बहुत सारे फ़िडली मुद्दे (जैसे, नीचे) हैं कि स्क्रैच से निर्भरता से टाइप की जाने वाली भाषाएं डिजाइन से दूर हो जाती हैं।
कबूतर

2
@pigworker क्या कुल मिलाकर हास्केल का स्वच्छ उपसमूह है? यदि ऐसा है, तो क्या हम "भाषा के उस टुकड़े के लिए" का उपयोग नहीं कर सकते हैं जो मूल्य और प्रकार दोनों परतों में मौजूद हो सकता है? यदि नहीं, तो एक उत्पादन करने में क्या लगेगा?
पथरिन की ज्वाला

223

आश्रित टाइप्ड हास्केल, अब?

हास्केल कुछ हद तक, एक भरोसेमंद टाइप की भाषा है। टाइप-लेवल डेटा की एक धारणा है, अब अधिक समझदारी से टाइप करने के लिए धन्यवाद DataKinds, और GADTsटाइप-लेवल डेटा को रन-टाइम प्रतिनिधित्व देने के लिए कुछ साधन ( ) हैं। इसलिए, रन-टाइम सामान के मूल्य प्रभावी रूप से प्रकारों में दिखाई देते हैं , जो कि एक भाषा के लिए निर्भरता से टाइप करने के लिए इसका मतलब है।

सरल डेटाटिप्स हैं स्तर तक प्रचारित किया जाता है, ताकि उनके द्वारा निहित मूल्यों का उपयोग प्रकारों में किया जा सके। इसलिए आर्कटिक उदाहरण

data Nat = Z | S Nat

data Vec :: Nat -> * -> * where
  VNil   :: Vec Z x
  VCons  :: x -> Vec n x -> Vec (S n) x

संभव हो जाता है, और इसके साथ, जैसे परिभाषाएँ

vApply :: Vec n (s -> t) -> Vec n s -> Vec n t
vApply VNil         VNil         = VNil
vApply (VCons f fs) (VCons s ss) = VCons (f s) (vApply fs ss)

जो अच्छा है। ध्यान दें कि लंबाईn उस फ़ंक्शन में एक विशुद्ध रूप से स्थिर चीज़ है, यह सुनिश्चित करते हुए कि इनपुट और आउटपुट वैक्टर की लंबाई समान है, भले ही उस लंबाई के निष्पादन में कोई भूमिका न हो vApply। इसके विपरीत, यह बहुत जटिल काम (यानी, असंभव) समारोह है जो लागू करने के लिए है nएक दिया की प्रतियां x(होगा जो pureकरने के लिए vApplys ' <*>)

vReplicate :: x -> Vec n x

क्योंकि यह जानना महत्वपूर्ण है कि रन-टाइम में कितनी प्रतियां बनानी हैं। एकल दर्ज करें।

data Natty :: Nat -> * where
  Zy :: Natty Z
  Sy :: Natty n -> Natty (S n)

किसी भी प्रकार के प्रचार के लिए, हम अपने मूल्यों के रन-टाइम डुप्लिकेट द्वारा बसाए गए एकल प्रकार के एकल परिवार को बढ़ावा दे सकते हैं। Natty nप्रकार-स्तर की रन-टाइम प्रतियों का प्रकार है n :: Nat। हम अब लिख सकते हैं

vReplicate :: Natty n -> x -> Vec n x
vReplicate Zy     x = VNil
vReplicate (Sy n) x = VCons x (vReplicate n x)

इसलिए आपके पास रन-टाइम मान के लिए एक प्रकार-स्तरीय मान है: रन-टाइम कॉपी का निरीक्षण करना टाइप-स्तर मान के स्थिर ज्ञान को परिष्कृत करता है। भले ही शब्द और प्रकार अलग हो गए हों, हम एक प्रकार के एपॉक्सी राल के रूप में सिंगलटन निर्माण का उपयोग करके चरणबद्ध तरीके से बॉन्ड बनाते हुए एक भरोसेमंद रूप से काम कर सकते हैं। यह प्रकारों में मनमाने ढंग से चलने की अभिव्यक्ति की अनुमति देने से एक लंबा रास्ता है, लेकिन यह कुछ भी नहीं है।

बुरा क्या है? क्या कमी है?

आइए इस तकनीक पर थोड़ा दबाव डालें और देखें कि क्या शुरू होता है। हमें यह अंदाजा हो सकता है कि सिंगल को थोड़ा और अधिक आसानी से मैनेज किया जा सकता है

class Nattily (n :: Nat) where
  natty :: Natty n
instance Nattily Z where
  natty = Zy
instance Nattily n => Nattily (S n) where
  natty = Sy natty

हमें लिखने, कहने,

instance Nattily n => Applicative (Vec n) where
  pure = vReplicate natty
  (<*>) = vApply

यह काम करता है, लेकिन इसका मतलब है कि हमारे मूल Natप्रकार ने तीन प्रतियों को जन्म दिया है: एक प्रकार, एक एकल परिवार और एक एकल वर्ग। हमारे पास स्पष्ट Natty nमूल्यों और Nattily nशब्दकोशों के आदान-प्रदान के लिए एक बल्कि क्लूनी प्रक्रिया है । इसके अलावा,Natty ऐसा नहीं है Nat: हमारे पास रन-टाइम मानों पर निर्भरता के कुछ प्रकार हैं, लेकिन उस प्रकार पर नहीं जिस पर हमने पहले सोचा था। कोई भी पूरी तरह से निर्भर प्रकार की भाषा निर्भर प्रकारों को जटिल नहीं बनाती है!

इस बीच, हालांकि Natप्रचार किया जा सकता है, Vecनहीं। आप अनुक्रमित प्रकार द्वारा अनुक्रमण नहीं कर सकते। भरोसेमंद टाइप की गई भाषाओं पर पूर्णतया कोई प्रतिबंध नहीं है, और मेरे करियर में एक भरोसेमंद टाइप-शो के रूप में, मैंने अपनी बातों में दो-परत अनुक्रमण के उदाहरणों को शामिल करना सीखा है, केवल उन लोगों को पढ़ाने के लिए जिन्होंने एक-परत अनुक्रमण किया है। मुश्किल-लेकिन-संभव नहीं मुझे कार्ड के घर की तरह गुना करने की उम्मीद है। समस्या क्या है? समानता। जब आप कंस्ट्रक्टर्स को स्पष्ट रूप से समान मांगों में एक विशिष्ट रिटर्न प्रकार देते हैं तो जीएडीटी आपके द्वारा प्राप्त बाधाओं का अनुवाद करके काम करता है। इस प्रकार सं।

data Vec (n :: Nat) (x :: *)
  = n ~ Z => VNil
  | forall m. n ~ S m => VCons x (Vec m x)

हमारे प्रत्येक दो समीकरणों में, दोनों पक्ष दयालु हैं Nat

अब वैक्टर पर अनुक्रमित कुछ के लिए एक ही अनुवाद का प्रयास करें।

data InVec :: x -> Vec n x -> * where
  Here :: InVec z (VCons z zs)
  After :: InVec z ys -> InVec z (VCons y ys)

हो जाता है

data InVec (a :: x) (as :: Vec n x)
  = forall m z (zs :: Vec x m). (n ~ S m, as ~ VCons z zs) => Here
  | forall m y z (ys :: Vec x m). (n ~ S m, as ~ VCons y ys) => After (InVec z ys)

और अब हम समतुल्य बाधाओं को as :: Vec n xऔर के बीच बनाते हैंVCons z zs :: Vec (S m) x दोनों पक्षों के जहाँ दोनों पक्ष वाक्यगत रूप से अलग (लेकिन समान रूप से) भिन्न होते हैं। जीएचसी कोर वर्तमान में ऐसी अवधारणा से सुसज्जित नहीं है!

और क्या याद आ रही है? खैर, अधिकांश हस्केल टाइप स्तर से गायब है। जिन शब्दों को आप प्रमोट कर सकते हैं उनकी भाषा में बस चर और गैर-जीएडीटी निर्माता हैं, वास्तव में। एक बार आपके पास होने के बाद, type familyमशीनरी आपको टाइप-लेवल प्रोग्राम लिखने की अनुमति देती है: उनमें से कुछ काफी ऐसे कार्य हो सकते हैं, जिन्हें आप टर्म स्तर पर लिखने पर विचार करेंगे (उदाहरण के लिए, Natइसके अलावा लैस करना, ताकि आप इसके लिए एक अच्छा प्रकार दे सकें Vec) , लेकिन यह सिर्फ एक संयोग है!

एक और बात याद आ रही है, व्यवहार में, एक पुस्तकालय है जो मूल्यों द्वारा सूचकांक प्रकारों के लिए हमारी नई क्षमताओं का उपयोग करता है। इस बहादुर नई दुनिया में क्या करें Functor और Monadबनें? मैं इसके बारे में सोच रहा हूं, लेकिन अभी भी बहुत कुछ करना बाकी है।

प्रकार-स्तरीय कार्यक्रम चलाना

हास्केल, ज्यादातर भरोसेमंद टाइपिंग प्रोग्रामिंग भाषाओं की तरह, दो परिचालन शब्दार्थ हैं। जिस तरह से रन-टाइम सिस्टम प्रोग्राम चलाता है (टाइप एक्ट्रेसेज, टाइप एरास के बाद, अत्यधिक अनुकूलित) और उसके बाद टाइपकार्चर प्रोग्राम (आपके टाइप परिवारों, आपके "टाइप क्लास प्रोलॉग" को ओपन एक्सप्रेशन के साथ) चलाता है। हास्केल के लिए, आप आम तौर पर दोनों को मिलाते नहीं हैं, क्योंकि निष्पादित होने वाले कार्यक्रम विभिन्न भाषाओं में हैं। भरोसेमंद रूप से टाइप की गई भाषाओं में अलग-अलग रन-टाइम और एक ही में प्रोग्राम भाषा के हैं, लेकिन चिंता न करें, रन-टाइम मॉडल अभी भी आपको टाइप एरेस करने देता है और वास्तव में, प्रूफ इरेज़र: यही Coq's है अर्क है तंत्र के लिए स्थिर निष्पादन मॉडल आपको देता है; कम से कम एडविन ब्रैडी का कंपाइलर करता है (हालांकि एडविन अनावश्यक रूप से डुप्लिकेट मानों को मिटाता है, साथ ही प्रकार और सबूत)। चरण भेद वाक्य-रचना श्रेणी का अंतर नहीं हो सकता है किसी भी समय , लेकिन यह जीवित और अच्छी तरह से है।

कुल मिलाकर टाइप की जाने वाली भाषाएं, कुल मिलाकर, टाइपटेकर को लंबे इंतजार से बदतर किसी भी चीज के भय से मुक्त कार्यक्रम चलाने की अनुमति देती हैं। जैसा कि हास्केल अधिक निर्भरता से टाइप करता है, हम इस सवाल का सामना करते हैं कि इसका स्थिर निष्पादन मॉडल क्या होना चाहिए? एक दृष्टिकोण कुल कार्यों के लिए स्थैतिक निष्पादन को प्रतिबंधित करना हो सकता है, जो हमें समान स्वतंत्रता को चलाने की अनुमति देगा, लेकिन हमें डेटा और कोडाटा के बीच अंतर (कम से कम प्रकार के स्तर के लिए) बनाने के लिए मजबूर कर सकता है, ताकि हम बता सकें कि क्या समाप्ति या उत्पादकता लागू करें। लेकिन यह एकमात्र तरीका नहीं है। हम एक बहुत ही कमजोर निष्पादन मॉडल का चयन करने के लिए स्वतंत्र हैं, जो प्रोग्राम चलाने के लिए अनिच्छुक है, कम से कम समीकरण बनाने की लागत से ही गणना होती है। और वास्तव में, यही जीएचसी वास्तव में करता है। GHC कोर के टाइपिंग नियमों का कोई उल्लेख नहीं है चलाने कार्यक्रम, लेकिन केवल समीकरणों के लिए साक्ष्य की जाँच के लिए। कोर में अनुवाद करते समय, जीएचसी की बाधा सॉल्वर आपके प्रकार के स्तर के कार्यक्रमों को चलाने की कोशिश करता है, जिससे साक्ष्य का थोड़ा सा चांदी का निशान पैदा होता है जो किसी दिए गए अभिव्यक्ति को उसके सामान्य रूप के बराबर होता है। यह सबूत-जनरेशन विधि थोड़ी अप्रत्याशित और अनिवार्य रूप से अधूरी है: यह डरावनी दिखने वाली पुनरावृत्ति से लड़ती है, उदाहरण के लिए, और यह शायद बुद्धिमान है। एक बात जिस पर हमें चिंता करने की ज़रूरत नहीं IO है वह है टाइपकैचर में कम्प्यूटेशन का निष्पादन : याद रखें कि टाइप-टेकर को launchMissilesएक ही अर्थ नहीं देना है कि रन-टाइम सिस्टम क्या करता है!

Hindley-मिलनर कल्चर

हिंडले-मिलनर प्रकार प्रणाली दुर्भाग्यपूर्ण सांस्कृतिक दुष्परिणामों के साथ, चार विशिष्ट भेदों के वास्तव में भयानक संयोग को प्राप्त करती है, जो कि कई लोग भेदों के बीच भेद नहीं देख सकते हैं और संयोग को अपरिहार्य मानते हैं! मैं किस बारे में बात कर रहा हूं?

  • शब्द बनाम प्रकार
  • स्पष्ट रूप से लिखित बातें बनाम निहित लिखित बातें
  • रन-टाइम में उपस्थिति बनाम से पहले रन-टाइम विलोपन
  • गैर-निर्भर अमूर्त बनाम निर्भर मात्रा का ठहराव

हम शब्दों को लिखने और टाइप करने के लिए आदी होने के लिए उपयोग कर रहे हैं ... और फिर मिट गए। हम इसी प्रकार के अमूर्त और अनुप्रयोग के साथ प्रकार चर पर मात्रात्मक रूप से और सांख्यिकीय रूप से हो रहे हैं।

इन भेदों को संरेखण से बाहर आने से पहले आपको वेनिला हिंडले-मिलनर से बहुत दूर नहीं जाना है, और यह कोई बुरी बात नहीं है । एक शुरुआत के लिए, हमारे पास और अधिक दिलचस्प प्रकार हो सकते हैं यदि हम उन्हें कुछ स्थानों पर लिखने के लिए तैयार हैं। इस बीच, जब हम अतिभारित कार्यों का उपयोग करते हैं, तो हमें टाइप क्लास डिक्शनरी लिखना नहीं आता है, लेकिन रन-टाइम पर वे डिक्शनरी निश्चित रूप से मौजूद होती हैं (या इनबिल्ट होती हैं)। भरोसेमंद रूप से टाइप की जाने वाली भाषाओं में, हम रन-टाइम पर सिर्फ टाइप्स से ज्यादा मिटा देने की उम्मीद करते हैं, लेकिन (टाइप क्लासेस के साथ) कि कुछ अनुमानित मानों को मिटाया नहीं जाएगा। उदाहरण के लिए, vReplicateसांख्यिक तर्क अक्सर वांछित वेक्टर के प्रकार से अनुमान लगाने योग्य होता है, लेकिन हमें अभी भी इसे रन-टाइम पर जानना होगा।

हमें कौन से भाषा डिज़ाइन विकल्पों की समीक्षा करनी चाहिए क्योंकि ये संयोग अब धारण नहीं करते हैं? उदाहरण के लिए, क्या यह सही है कि हास्केल forall x. tस्पष्ट रूप से एक क्वांटिफायर को इंस्टेंट करने का कोई तरीका प्रदान नहीं करता है ? यदि टाइपराइटर यूनिफ़ाइंग xद्वारा अनुमान नहीं लगा सकता है t, तो हमारे पास यह कहने का कोई अन्य तरीका नहीं है कि क्या xहोना चाहिए।

मोटे तौर पर, हम एक अखंड अवधारणा के रूप में "प्रकार के अनुमान" का इलाज नहीं कर सकते हैं कि हमारे पास सभी या कुछ भी नहीं है। एक शुरुआत के लिए, हमें "सामान्यीकरण" पहलू (मिलनर के "लेट" नियम) को विभाजित करने की आवश्यकता है, जो कि प्रतिबंधित करने पर बहुत अधिक निर्भर करता है कि कौन से प्रकार यह सुनिश्चित करने के लिए मौजूद हैं कि एक बेवकूफ मशीन "विशेषज्ञता" पहलू (मिल्नर) के संस्करण से अनुमान लगा सकती है "नियम) जो आपके बाधा समाधानकर्ता के रूप में प्रभावी है। हम उम्मीद कर सकते हैं कि शीर्ष-स्तरीय प्रकार अनुमान लगाने में कठिन हो जाएंगे, लेकिन आंतरिक प्रकार की जानकारी प्रचारित करने में काफी आसान रहेगी।

हास्केल के लिए अगला कदम

हम देख रहे हैं कि प्रकार और तरह के स्तर बहुत समान हैं (और वे पहले से ही जीएचसी में एक आंतरिक प्रतिनिधित्व साझा करते हैं)। हम उन्हें भी मिला सकते हैं। * :: *यदि हम कर सकते हैं तो यह लेना मजेदार होगा : हमने तार्किक ध्वनिशीलता बहुत पहले खो दी थी, जब हमने नीचे की अनुमति दी थी, लेकिन टाइप साउंडनेस आमतौर पर एक कमजोर आवश्यकता होती है। हमें जांच करनी चाहिए। यदि हमारे पास अलग-अलग प्रकार, प्रकार, आदि के स्तर होने चाहिए, तो हम कम से कम यह सुनिश्चित कर सकते हैं कि सभी प्रकार के स्तर और उससे ऊपर हमेशा प्रचार किया जा सकता है। यह केवल उस प्रकार के बहुरूपता का पुनः उपयोग करने के लिए बहुत अच्छा होगा जो हमारे पास पहले से ही प्रकार के लिए है, बजाय इस तरह के स्तर पर फिर से बहुरूपता का आविष्कार करने के।

हमें विषम समीकरणों की अनुमति देकर बाधाओं की वर्तमान प्रणाली को सरल और सामान्य बनाना चाहिए a ~ bजहां प्रकार aऔर bसमान रूप से समान नहीं हैं (लेकिन बराबर सिद्ध किया जा सकता है)। यह एक पुरानी तकनीक है (मेरी थीसिस में, पिछली शताब्दी में) जो निर्भरता को आसान बनाता है। हम GADTs में अभिव्यक्तियों पर अड़चनें व्यक्त करने में सक्षम होंगे, और इस प्रकार जो प्रचारित किया जा सकता है उस पर प्रतिबंधों को शिथिल करेंगे।

हमें एक आश्रित फ़ंक्शन प्रकार की शुरुआत करके सिंगलटन निर्माण की आवश्यकता को समाप्त करना चाहिए pi x :: s -> t। इस प्रकार के एक फ़ंक्शन को स्पष्ट रूप से उस प्रकार की किसी भी अभिव्यक्ति पर लागू किया जा सकता है sजो टाइप और टर्म लैंग्वेज के चौराहे पर रहता है (इसलिए, चर, कंस्ट्रक्टर, बाद में आने के लिए और अधिक के साथ)। इसी लैम्बडा और एप्लिकेशन को रन-टाइम में मिटाया नहीं जाएगा, इसलिए हम लिख पाएंगे

vReplicate :: pi n :: Nat -> x -> Vec n x
vReplicate Z     x = VNil
vReplicate (S n) x = VCons x (vReplicate n x)

Natद्वारा प्रतिस्थापित किए बिना Natty। डोमेन piकिसी भी प्रकार का प्रचारक हो सकता है, इसलिए यदि GADT को बढ़ावा दिया जा सकता है, तो हम आश्रित क्वांटिफायर अनुक्रम (या "दूरबीन" लिख सकते हैं, जैसा कि डी ब्रूइजन ने उन्हें बुलाया)

pi n :: Nat -> pi xs :: Vec n x -> ...

हमें जो भी लंबाई चाहिए।

इन कदमों का उद्देश्य कमजोर औजारों और क्लॉन्की एनकोडिंग के साथ काम करने के बजाय अधिक सामान्य उपकरणों के साथ सीधे काम करके जटिलता को खत्म करना है। मौजूदा आंशिक खरीद, हास्केल के प्रकारों पर निर्भरता के प्रकारों के लाभों को और अधिक महंगा बनाती है, जो उन्हें होने की आवश्यकता है।

बहुत कठिन?

आश्रित प्रकार बहुत से लोगों को परेशान करते हैं। वे मुझे नर्वस करते हैं, लेकिन मुझे नर्वस होना पसंद है, या कम से कम मुझे वैसे भी नर्वस होना मुश्किल लगता है। लेकिन यह मदद नहीं करता है कि इस विषय के चारों ओर अज्ञानता का एक बहुत कोहरा है। इस तथ्य के कारण कि हम सभी को अभी भी बहुत कुछ सीखना बाकी है। लेकिन कम कट्टरपंथी दृष्टिकोण के समर्थकों को यह सुनिश्चित करने के लिए जाना जाता है कि आश्रित प्रकार के डर को हमेशा बिना यह सुनिश्चित किए कि उनके साथ तथ्य पूर्ण हैं। मैं नाम नहीं बताऊंगा। ये "अनुचित टाइपकास्टिंग", "ट्यूरिंग अधूरा", "कोई चरण भेद नहीं", "कोई प्रकार का क्षरण नहीं", "हर जगह सबूत", आदि, मिथक बने रहते हैं, भले ही वे बकवास हो।

यह निश्चित रूप से ऐसा नहीं है कि भरोसेमंद रूप से टाइप किए गए प्रोग्राम हमेशा सही साबित होने चाहिए। किसी के कार्यक्रमों की बुनियादी स्वच्छता में सुधार कर सकते हैं, एक पूर्ण विनिर्देश के सभी रास्ते में जाने के बिना प्रकार में अतिरिक्त आक्रमणकारियों को लागू करना। इस दिशा में छोटे कदमों के परिणामस्वरूप अक्सर कुछ या कोई अतिरिक्त प्रमाण दायित्वों के साथ बहुत मजबूत गारंटी मिलती है। यह सच नहीं है कि निर्भरता से टाइप किए गए प्रोग्राम अनिवार्य रूप से प्रमाणों से भरे होते हैं , वास्तव में मैं आमतौर पर मेरी परिभाषा में किसी भी प्रमाण की उपस्थिति को क्यू के रूप में लेता हूं ताकि मेरी परिभाषाओं पर सवाल उठाया जा सके

कलात्मकता में किसी भी वृद्धि के साथ, हम बेईमानी के साथ-साथ नई चीजों को भी कहने के लिए स्वतंत्र हो जाते हैं। उदाहरण के लिए, द्विआधारी खोज पेड़ों को परिभाषित करने के लिए बहुत सारे आपराधिक तरीके हैं, लेकिन इसका मतलब यह नहीं है कि एक अच्छा तरीका नहीं है । यह महत्वपूर्ण है कि बुरा अनुभव को बेहतर नहीं माना जा सकता है, भले ही वह इसे स्वीकार करने के लिए अहंकार को जन्म दे। आश्रित परिभाषाओं का डिजाइन एक नया कौशल है जो सीखने में मदद करता है, और हास्केल प्रोग्रामर होने के नाते स्वचालित रूप से आपको एक विशेषज्ञ नहीं बनाता है! और अगर कुछ कार्यक्रम बेईमानी हैं, तो भी आप दूसरों को निष्पक्ष होने की स्वतंत्रता से वंचित क्यों करेंगे?

हास्केल के साथ फिर भी परेशान क्यों?

मैं वास्तव में निर्भर प्रकारों का आनंद लेता हूं, लेकिन मेरे हैकिंग के अधिकांश प्रोजेक्ट अभी भी हास्केल में हैं। क्यों? हास्केल के प्रकार वर्ग हैं। हास्केल में उपयोगी पुस्तकालय हैं। हास्केल में प्रभाव के साथ प्रोग्रामिंग का एक व्यावहारिक (हालांकि आदर्श से बहुत दूर) उपचार है। हास्केल में एक औद्योगिक शक्ति संकलक है। बढ़ती समुदाय और बुनियादी ढाँचे में निर्भरता से टाइप की गई भाषाएँ बहुत पहले की अवस्था में हैं, लेकिन हम वहाँ पहुँचेंगे, जो कि संभव हो सकता है, जैसे कि, उदाहरण के तौर पर, मेटाप्रोग्रामिंग और डेटाटाइप जेनरिक के माध्यम से। लेकिन आपको बस इस बात पर ध्यान देना होगा कि लोग हास्केल के आश्रित प्रकार के कदमों के परिणामस्वरूप क्या कर रहे हैं, यह देखने के लिए कि वर्तमान पीढ़ी को आगे बढ़ाकर बहुत अधिक लाभ प्राप्त करना है।


6
मैं वास्तव में अभी तक DataKinds सामान के बारे में परवाह नहीं है। ज्यादातर इसलिए कि मैं ऐसा कुछ करना चाहता हूं fmap read getLine >>= \n -> vReplicate n 0:। जैसा कि आप ध्यान दें, इससे Nattyदूर एक तरीका है। इसके अलावा, vReplicate एक वास्तविक मेमोरी एरे के लिए अनुवाद योग्य होना चाहिए, कुछ ऐसा newtype SVector n x = SVector (Data.Vector.Vector x), जहां nतरह Nat(या समान) है। शायद "निर्भरता-टाइप किए गए शो-ऑफ" के लिए एक और प्रदर्शन बिंदु?
जॉन एल

7
क्या आप कह सकते हैं कि प्रभाव के साथ प्रोग्रामिंग के एक आदर्श उपचार के लिए आपके पास क्या है?
स्टीवन शॉ

6
महान समीक्षा के लिए धन्यवाद। मैं भरोसेमंद रूप से टाइप किए गए कोड के कुछ उदाहरण देखना पसंद करूंगा, जहां कुछ डेटा प्रोग्राम के बाहर उत्पन्न होता है (उदाहरण के लिए एक फ़ाइल से पढ़ा जाता है), यह जानने के लिए कि इस तरह की सेटिंग में मूल्यों को कैसे बढ़ावा देना चाहिए। मुझे यह महसूस होता है कि सांख्यिकीय रूप से ज्ञात आकारों के साथ सभी उदाहरणों में वैक्टर (सूचियों के रूप में लागू) शामिल हैं।
टिब्बी

4
@pigworker आप एक मिथक के रूप में "कोई चरण भेद" नहीं लेते हैं (अन्य मैं सहमत हूं मिथक हैं)। लेकिन आपने इसे कागजों और वार्ताओं में नहीं देखा है, और इस बीच एक अन्य व्यक्ति जो मुझे सम्मान देता है, "मुझे निर्भर करता है" निर्भर प्रकार का सिद्धांत एक विशिष्ट संकलक से अलग है, क्योंकि हम सार्थक प्रकार की जाँच, संकलन और निष्पादन चरणों को अलग नहीं कर सकते हैं। " (देखें नोव 8 की नवीनतम पोस्ट '8 2012) मेरे अनुभव में "इसे फेकिंग" हम कभी-कभी कम से कम चरण भेद को धुंधला करते हैं, हालांकि इसे मिटाने की आवश्यकता नहीं है। क्या आप विस्तार कर सकते हैं, यहाँ नहीं तो कहीं और, इस मुद्दे पर?
4

4
@sclv मेरे काम ने विशेष रूप से "कोई चरण भेद" मिथक को लक्षित नहीं किया है, लेकिन दूसरों के पास है। मैं जेम्स मैककिना और एडविन ब्रैडी द्वारा शुरू करने के लिए एक अच्छी जगह के रूप में, "एपिग्राम के संकलन में चरण भेद" को अस्वीकार करने की सलाह देता हूं। लेकिन Coq में प्रोग्राम एक्सट्रैक्शन पर अधिक पुराने काम भी देखें। टाइपराइकर द्वारा किए गए खुले शब्दों का मूल्यांकन निष्कर्षण के माध्यम से एमएल से निष्पादन से पूरी तरह से अलग है, और यह स्पष्ट है कि निष्कर्षण प्रकारों और प्रमाणों को स्ट्रिप्स करता है।
सुअर का बच्चा नोव

20

जॉन कि आश्रित प्रकारों के बारे में एक और आम गलत धारणा है: वे तब काम नहीं करते हैं जब डेटा केवल रन-टाइम पर उपलब्ध होता है। यहां बताया गया है कि आप गेटलाइन का उदाहरण कैसे दे सकते हैं:

data Some :: (k -> *) -> * where
  Like :: p x -> Some p

fromInt :: Int -> Some Natty
fromInt 0 = Like Zy
fromInt n = case fromInt (n - 1) of
  Like n -> Like (Sy n)

withZeroes :: (forall n. Vec n Int -> IO a) -> IO a
withZeroes k = do
  Like n <- fmap (fromInt . read) getLine
  k (vReplicate n 0)

*Main> withZeroes print
5
VCons 0 (VCons 0 (VCons 0 (VCons 0 (VCons 0 VNil))))

संपादित करें: Hm, कि सुअर के बच्चे के जवाब के लिए एक टिप्पणी माना जाता था। मैं एसओ में स्पष्ट रूप से विफल रहता हूं।


आपका पहला वाक्य थोड़ा अजीब लगता है; मैं कहूंगा कि निर्भर प्रकार की बात है कि वे है ऐसा काम जब डेटा रन-टाइम पर ही उपलब्ध है। हालांकि, यह सीपीएस-शैली तकनीक समान नहीं है। मान लीजिए आपका कोई फंक्शन है Vec Zy -> IO String। आप इसका उपयोग नहीं कर सकते withZeroes, क्योंकि प्रकार Zyको forall n के साथ एकीकृत नहीं किया जा सकता है। हो सकता है कि आप एक या दो विशेष मामलों के लिए चारों ओर काम कर सकते हैं, लेकिन यह जल्दी से हाथ से निकल जाता है।
जॉन एल

जब बस टाइप की गई वैल्यू ली जाती है (जैसे गेटलाइन से स्ट्रिंग) और इसे मजबूत प्रकार के साथ किसी चीज़ में बदलना (जैसे कि नैट्टी एन ऊपर) तो आपको टाइप चेकर को यह विश्वास दिलाना होगा कि आप आवश्यक डायनेमिक चेक कर रहे हैं। आपके उदाहरण में आप एक मनमानी संख्या पढ़ रहे हैं ताकि forall nसमझ में आए । अधिक सटीक प्रतिबंध उसी तरह से लागू किए जा सकते हैं। क्या आपके पास एक बेहतर उदाहरण है Vec Zy(प्रोग्राम को अभी भी उपयोगकर्ता को 5 के बजाय 0 इनपुट करने की आवश्यकता होगी)?
१०:१० बजे

1
पहले वाक्य के साथ मेरे कहने का मतलब यह है कि मैं कभी-कभी ऐसे लोगों में भाग लेता हूं, जो मानते हैं कि अगर आप बाहरी दुनिया के साथ बातचीत करके अपना डेटा प्राप्त करते हैं तो आप निर्भर प्रकारों का उपयोग नहीं कर सकते। मेरा कहना यह है कि केवल एक चीज जो आपको करनी है वह है एक भरोसेमंद टाइप किए गए पार्सर को लिखना, जो आमतौर पर सीधे-आगे होता है।
१०:२३ बजे --nnnellell

1
ulfnorell: क्षमा करें, मैं स्पष्ट नहीं था। मान लीजिए कि आपके पास एक फ़ंक्शन है जो Vec Zy -> IO Stringकिसी और के लिए काम करेगा Vec n -> IO String, और आप केवल तभी उपयोग करना चाहते हैं यदि प्रकार मेल खाता है। हां यह संभव है, लेकिन इसे सक्षम करने के तंत्र क्लंकी हैं। और यह बहुत सरल तर्क है; यदि आपके पास अधिक जटिल तर्क है, तो यह बदतर है। साथ ही, आपको CPS में बहुत सारे कोड को फिर से लिखना पड़ सकता है। और आपके पास अभी भी एक प्रकार-स्तरीय अभिव्यक्ति नहीं है जो कि मूल्य स्तर पर एक शब्द पर निर्भर है
जॉन एल

आह, मैं देख रहा हूँ कि तुम क्या कह रहे हो। यह वही है जो नेट्टी के लिए है, जैसे vReplicate में जहां हम n के आधार पर अलग-अलग चीजें करते हैं। वास्तव में यह थोड़ा क्लंकी हो सकता है। CPS शैली का एक विकल्प पैक्ड अप अस्तित्व के साथ काम करना है zeroes :: IO (Some (Flip Vec Int)):।
22 22

19

सुअर का बच्चा एक उत्कृष्ट चर्चा देता है कि हमें निर्भर प्रकारों की ओर क्यों बढ़ना चाहिए : (ए) वे कमाल के हैं; (बी) वे वास्तव में बहुत कुछ सरल करेंगे जो हास्केल पहले से ही करता है।

"क्यों नहीं?" सवाल, मुझे लगता है कि एक युगल बिंदु हैं। पहला बिंदु यह है कि जबकि निर्भर प्रकारों के पीछे मूल धारणा आसान है (मानों पर निर्भर रहने के प्रकारों को अनुमति दें), उस मूल धारणा के प्रभाव सूक्ष्म और गहन दोनों हैं। उदाहरण के लिए, मूल्यों और प्रकारों के बीच का अंतर अभी भी जीवित है और अच्छी तरह से है; लेकिन उनके बीच के अंतर पर चर्चा करना दूर की बात हो जाती हैyer Hindley की तुलना में अधिक बारीक - मिलनर या सिस्टम F. कुछ हद तक यह इस तथ्य के कारण है कि निर्भर प्रकार मौलिक रूप से कठिन हैं (उदाहरण के लिए, प्रथम-क्रम तर्क अनिर्दिष्ट है)। लेकिन मुझे लगता है कि वास्तव में बड़ी समस्या यह है कि हमारे पास पकड़ने और समझाने के लिए एक अच्छी शब्दावली की कमी है कि क्या चल रहा है। जैसा कि अधिक से अधिक लोग निर्भर प्रकारों के बारे में सीखते हैं, हम एक बेहतर शब्दावली विकसित करेंगे और इसलिए चीजें समझना आसान हो जाएगा, भले ही अंतर्निहित समस्याएं अभी भी कठिन हैं।

दूसरा बिंदु इस तथ्य से है कि हास्केल बढ़ रहा हैनिर्भर प्रकारों की ओर। क्योंकि हम उस लक्ष्य के लिए वृद्धिशील प्रगति कर रहे हैं, लेकिन वास्तव में इसे वहां बनाए बिना, हम एक ऐसी भाषा के साथ फंस गए हैं जिसमें वृद्धिशील पैच के ऊपर वृद्धिशील पैच हैं। नई भाषाओं के लोकप्रिय होते ही दूसरी भाषाओं में भी ऐसा ही हुआ। जावा (पैरामीट्रिक) बहुरूपता का उपयोग नहीं करता था; और जब उन्होंने अंत में इसे जोड़ा, तो यह स्पष्ट रूप से कुछ अमूर्त लीक और अपंग शक्ति के साथ एक वृद्धिशील सुधार था। बाहर निकलता है, घटाव और बहुरूपता का मिश्रण स्वाभाविक रूप से कठिन है; लेकिन यही कारण नहीं है कि जावा जेनेरिक जिस तरह से काम करते हैं। वे जावा के पुराने संस्करणों के लिए एक वृद्धिशील सुधार के लिए बाधा के कारण काम करते हैं। Ditto, उस दिन के लिए जब OOP का आविष्कार हुआ था और लोगों ने "उद्देश्य" लिखना शुरू कर दिया था सी (उद्देश्य-सी के साथ भ्रमित नहीं होना), आदि याद रखें, सी ++ की सख्त सुपरसेट होने की आड़ में शुरू किया गया था। नए प्रतिमानों को जोड़ना हमेशा भाषा में नए सिरे से परिभाषित करने की आवश्यकता होती है, या फिर कुछ जटिल गड़बड़ के साथ समाप्त होता है। इस सब में मेरा कहना यह है कि हास्केल पर सच्चे आश्रित प्रकारों को जोड़ने के लिए भाषा की एक निश्चित मात्रा की आवश्यकता होती है। लेकिन उस तरह के ओवरहाल के लिए प्रतिबद्ध होना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं वह अल्पावधि में सस्ती लगती है। वास्तव में, ऐसे कई लोग नहीं हैं जो जीएचसी पर हैक करते हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। C ++ ने C के एक सख्त सुपरसेट होने की आड़ में शुरुआत की। नए प्रतिमानों को जोड़ने से हमेशा भाषा को नए सिरे से परिभाषित करने की आवश्यकता होती है, या फिर कुछ जटिल गड़बड़ियों के साथ समाप्त होता है। इस सब में मेरा कहना यह है कि, हास्केल पर सच्चे आश्रित प्रकारों को जोड़ने के लिए भाषा की एक निश्चित मात्रा की आवश्यकता होती है। लेकिन उस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं वह अल्पावधि में सस्ती लगती है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। C ++ ने C के एक सख्त सुपरसेट होने की आड़ में शुरुआत की। नए प्रतिमानों को जोड़ने से हमेशा भाषा को नए सिरे से परिभाषित करने की आवश्यकता होती है, या फिर कुछ जटिल गड़बड़ियों के साथ समाप्त होता है। इस सब में मेरा कहना यह है कि, हास्केल पर सच्चे आश्रित प्रकारों को जोड़ने के लिए भाषा की एक निश्चित मात्रा की आवश्यकता होती है। लेकिन उस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं वह अल्पावधि में सस्ती लगती है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। या कुछ जटिल गंदगी के साथ समाप्त हो रहा है। इस सब में मेरा कहना यह है कि, हास्केल पर सच्चे आश्रित प्रकारों को जोड़ने के लिए भाषा की एक निश्चित मात्रा की आवश्यकता होती है। लेकिन उस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं वह अल्पावधि में सस्ती लगती है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। या कुछ जटिल गंदगी के साथ समाप्त हो रहा है। इस सब में मेरा कहना है कि, हास्केल पर सच्चे आश्रित प्रकारों को जोड़ने के लिए भाषा की एक निश्चित मात्रा की आवश्यकता होती है। लेकिन उस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं वह अल्पावधि में सस्ती लगती है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। इस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं, वह अल्पावधि में सस्ता लगता है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं। इस तरह के ओवरहाल के लिए प्रतिबद्ध करना वास्तव में कठिन है, जबकि हम जो वृद्धिशील प्रगति कर रहे हैं, वह अल्पावधि में सस्ता लगता है। वास्तव में, जीएचसी पर हैक करने वाले कई लोग नहीं हैं, लेकिन जीवित रखने के लिए विरासत कोड की एक अच्छी मात्रा है। यह इस कारण का हिस्सा है कि डीडीसी, केयेन, इदरीस आदि जैसी कई स्पिनऑफ़ भाषाएँ हैं।

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