2013-03-01 9 views
8

Scrap your boilerplate reloaded में, लेखक Scrap Your Boilerplate की एक नई प्रस्तुति का वर्णन करते हैं, जो मूल के बराबर माना जाता है।टाइपरप और "टाइप" के बीच संबंध GADT

हालांकि, एक अंतर यह है कि वे एक निश्चित मान, "आधार" प्रकार, के साथ एक GADT

data Type :: * -> * where 
    Int :: Type Int 
    List :: Type a -> Type [a] 
    ... 

मूल SYB में, प्रकार-सुरक्षित डाली प्रयोग किया जाता है इनकोडिंग का सेट बंद, Typeable का उपयोग कर लागू किया है कक्षा।

मेरे प्रश्न हैं:

  • इन दो दृष्टिकोणों के बीच क्या संबंध है?
  • "एसईबी रीलोडेड" प्रस्तुति के लिए जीएडीटी प्रतिनिधित्व क्यों चुना गया था?
+0

यह एक समान दृष्टिकोण जैसा लगता है [यहां] (http://link.springer.com/chapter/10.1007%2F978-3-540-27764-4_4?LI=true#page-1) सार्वभौमिक ' यूनिवर्स 'टाइप, लेकिन मैंने केवल उस पेपर को स्किम किया है। – jberryman

उत्तर

4

[मैं "SYB रीलोडेड" कागज के लेखकों में से एक हूँ।]

टी एल; डॉ हम वास्तव में सिर्फ यह प्रयोग किया जाता है क्योंकि यह हमारे लिए अधिक सुंदर लग रहा था। कक्षा-आधारित Typeable दृष्टिकोण अधिक व्यावहारिक है। Spine व्यू को Typeable कक्षा के साथ जोड़ा जा सकता है और यह Type GADT पर निर्भर नहीं है।

कागज राज्यों इसके निष्कर्षों में इस:

हमारी कार्यान्वयन सामान्य प्रोग्रामिंग के दो केंद्रीय तत्व संभालती अलग ढंग से मूल SYB कागज से: हम के आधार पर अतिभारित कार्यों के बजाय स्पष्ट प्रकार तर्क के साथ अतिभारित कार्यों का उपयोग एक प्रकार-सुरक्षित कास्ट 1 या कक्षा-आधारित एक्स्टेंसिबल योजना [20]; और हम संयोजक-आधारित दृष्टिकोण के बजाय स्पष्ट रीढ़ व्यू का उपयोग करते हैं। दोनों परिवर्तन स्वतंत्र हैं एक दूसरे के हैं, और स्पष्टता के साथ दिमाग में किए गए हैं: हमें लगता है कि एसआईबी दृष्टिकोण की संरचना हमारी सेटिंग में अधिक दिखाई दे रही है, और संबंध पॉलीपी और जेनेरिक हास्केल के लिए स्पष्ट हो गए हैं। हमने खुलासा किया है कि रीढ़ की हड्डी जेनेरिक कार्यों के वर्ग में सीमित है, जिसे लिखा जा सकता है, यह है, जिसमें जीएडीटी समेत डेटा प्रकारों की एक बहुत बड़ी कक्षा के लिए लागू होता है।

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

तो, प्रकार के प्रतिनिधित्व के लिए जीएडीटी का उपयोग करने की पसंद एक है जिसे हमने मुख्य रूप से स्पष्टता के लिए बनाया है। जैसा कि डॉन ने अपने उत्तर में कहा है, इस प्रतिनिधित्व में कुछ स्पष्ट फायदे हैं, अर्थात् यह किस प्रकार के प्रकार के प्रतिनिधित्व के बारे में स्थिर जानकारी बनाए रखता है, और यह हमें बिना किसी जादू के कलाकारों को लागू करने की अनुमति देता है, और विशेष रूप से उपयोग के बिना unsafeCoerce का। प्रकार-अनुक्रमित कार्यों को प्रकार के पैटर्न मिलान का उपयोग करके और mkQ या extQ जैसे विभिन्न संयोजकों पर वापस गिरने के बिना सीधे लागू किया जा सकता है।

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

तो संक्षेप में: यदि आपको वास्तव में बंद ब्रह्मांड के लिए गतिशील प्रकार की जानकारी की आवश्यकता है, तो मैं हमेशा जीएडीटी के लिए जाता हूं, क्योंकि आप प्रकार-अनुक्रमित कार्यों को परिभाषित करने के लिए पैटर्न मिलान का उपयोग कर सकते हैं, और आपको unsafeCoerce और न ही उन्नत कंपाइलर जादू पर भरोसा करें। यदि ब्रह्मांड खुला है, हालांकि, सामान्य रूप से जेनेरिक प्रोग्रामिंग सेटिंग के लिए, आम तौर पर जीएडीटी दृष्टिकोण निर्देशक हो सकता है, लेकिन व्यावहारिक नहीं है, और Typeable का उपयोग करने का तरीका है।

लेकिन, जैसा कि हम भी कागज के निष्कर्ष में राज्य, TypeTypeable से अधिक की पसंद नहीं अन्य विकल्प हम अर्थात् Spine दृश्य का उपयोग करने, कर रहे हैं, जो मुझे लगता है कि ज्यादा महत्वपूर्ण है के लिए एक शर्त है और वास्तव में कागज का मूल।

पेपर स्वयं ही (धारा 8 में) "Scrap your Boilerplate with Class" पेपर से प्रेरित एक भिन्नता दिखाता है, जो Spine का उपयोग कक्षा की बाधा के साथ करता है। लेकिन हम एक और प्रत्यक्ष विकास भी कर सकते हैं, जो मैं निम्नलिखित में दिखाता हूं।इसके लिए हमें Data.Typeable से Typeable इस्तेमाल करेंगे, लेकिन हमारे अपने Data वर्ग को परिभाषित है, जो सादगी के लिए, बस toSpine विधि में शामिल हैं:

data Spine :: * -> * where 
    Constr :: a -> Spine a 
    (:<>:) :: (Data a) => Spine (a -> b) -> a -> Spine b 
:

class Typeable a => Data a where 
    toSpine :: a -> Spine a 

Spine डेटाप्रकार अब Data बाधा का उपयोग करता है

फ़ंक्शन fromSpine अन्य प्रतिनिधित्व के साथ तुच्छ जैसा है:

fromSpine :: Spine a -> a 
fromSpine (Constr x) = x 
fromSpine (c :<>: x) = fromSpine c x 
के लिए

उदाहरण ऐसे Int के रूप में फ्लैट प्रकार के लिए तुच्छ हैं:

instance Data Int where 
    toSpine = Constr 

और वे अभी भी इस तरह द्विआधारी पेड़ के रूप में संरचित प्रकार के लिए पूरी तरह से स्पष्ट कर रहे हैं:

data Tree a = Empty | Node (Tree a) a (Tree a) 

instance Data a => Data (Tree a) where 
    toSpine Empty  = Constr Empty 
    toSpine (Node l x r) = Constr Node :<>: l :<>: x :<>: r 

कागज तो पर और परिभाषित करता चला जाता है विभिन्न सामान्य कार्य, जैसे mapQ। ये परिभाषा शायद ही बदलती है। हम केवल Data a => के लिए वर्ग की कमी मिल जहां कागज Type a -> के समारोह तर्क हैं:

mapQ :: Query r -> Query [r] 
mapQ q = mapQ' q . toSpine 

mapQ' :: Query r -> (forall a. Spine a -> [r]) 
mapQ' q (Constr c) = [] 
mapQ' q (f :<>: x) = mapQ' q f ++ [q x] 

उच्चतर स्तर के कार्यों में इस तरह के everything के रूप में भी सिर्फ अपने स्पष्ट प्रकार तर्क खो (और फिर वास्तव में बिल्कुल मूल SYB में जैसे ही दिखते हैं) :

everything :: (r -> r -> r) -> Query r -> Query r 
everything op q x = foldl op (q x) (mapQ (everything op q) x) 

जैसा कि मैंने ऊपर कहा, अगर हम अब एक सामान्य योग समारोह सभी Int घटनाओं संक्षेप परिभाषित करना चाहते हैं, हम अब और नहीं पैटर्न मैच कर सकते हैं, लेकिन mkQ में वापस आने का है, लेकिन mkQ संदर्भ में विशुद्ध रूप से परिभाषित किया गया है 01 काऔर Spine की पूरी तरह से स्वतंत्र: (बिल्कुल के रूप में मूल SYB में फिर से)

mkQ :: (Typeable a, Typeable b) => r -> (b -> r) -> a -> r 
(r `mkQ` br) a = maybe r br (cast a) 

और फिर:

sum :: Query Int 
sum = everything (+) sumQ 

sumQ :: Query Int 
sumQ = mkQ 0 id 

बाद में समाचार पत्र में सामान में से कुछ के लिए (जैसे, जोड़ने निर्माता जानकारी), एक थोड़ा और काम की जरूरत है, लेकिन यह सब किया जा सकता है। तो Spine का उपयोग करके वास्तव में Type का उपयोग करने पर निर्भर नहीं है।

4

ठीक है, जाहिर है कि Typeable उपयोग खुला है - तथ्य के बाद नए संस्करणों को जोड़ा जा सकता है, और मूल परिभाषाओं को संशोधित किए बिना।

महत्वपूर्ण परिवर्तन हालांकि यह है कि TypeRep में कोई टाइप नहीं है। यही है, रनटाइम प्रकार, TypeRep, और स्थिर प्रकार के एन्कोड के बीच कोई कनेक्शन नहीं है। जीएडीटी दृष्टिकोण के साथ हम जीएडीटी Type a द्वारा दिए गए a और इसके Type के बीच मैपिंग को एन्कोड कर सकते हैं।

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

पुराने टाइपरप मामले में, हमारे पास ऐसा कोई सबूत नहीं है और यह रनटाइम स्ट्रिंग समानता के लिए आता है, और एक कॉरर्स और fromDynamic के माध्यम से सर्वोत्तम के लिए आशा करता है।

toDyn :: Typeable a => a -> TypeRep -> Dynamic 

बनाम GADT शैली:

हस्ताक्षर की तुलना करें

toDyn :: Type a => a -> Type a -> Dynamic 

मैं नकली नहीं मेरी प्रकार सबूत है, और मुझे लगता है कि उपयोग कर सकते हैं कर सकते हैं बाद में जब चीजें पुनर्निर्माण, उदा करने के लिए a के लिए टाइप क्लास उदाहरण देखें जब मेरे पास Type a है।

+0

मैं सहमत नहीं हूं। जीएडीटी मामले में, प्रकार को बाद में अस्तित्व मात्रा में मिटा दिया जाता है ('स्पाइन' की परिभाषा देखें)। इस प्रकार, दोनों मामलों में आप रन टाइम पर प्रकार को पुनर्प्राप्त करते हैं - एक मामले में जीएडीटी टैग का उपयोग करके, और दूसरे में 'टाइपरप' का उपयोग करते हैं। –

+0

दरअसल, हस्ताक्षर 'toDyn :: टाइप करने योग्य ए => ए -> गतिशील' बनाम 'toDyn :: टाइप करें -> ए -> गतिशील'। यह सच है कि 'टाइप करने योग्य' वर्ग को एक प्रकार के 'टाइपरिप' का उपयोग करके आंतरिक रूप से कार्यान्वित किया जाता है, लेकिन केवल कुछ फ़ंक्शन सीधे 'टाइपरप' के साथ काम करते हैं। हां, आप अपने 'टाइप करने योग्य' उदाहरणों को परिभाषित किए जाने तक नकली 'टाइप करने योग्य' उदाहरण बना सकते हैं। – kosmikus

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