2013-01-07 14 views
19

प्रकार समानार्थी परिवारों का उपयोग करने के लाभ स्पष्ट हैं - यह प्रकार-स्तरीय कार्य है।डेटा परिवार मामलों का उपयोग

लेकिन यह डेटा परिवारों के साथ मामला नहीं है - इसलिए मेरा सवाल है, डेटा परिवारों के लिए उपयोग-मामलों क्या है? मुझे इसका उपयोग कहां करना चाहिए?

+0

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

उत्तर

23

एक लाभ यह है कि डेटा परिवार इंजेक्शनिव हैं, परिवारों के विपरीत।

आप

type family TF a 
data family DF a 

है तो आप जानते हैं कि DF a ~ DF b का तात्पर्य है कि a ~ b, जबकि TF के साथ, तुम नहीं - किसी भी a के लिए आप यह सुनिश्चित करें कि DF a एक पूरी तरह से नए प्रकार (बस की तरह है हो सकता है [a][b] से एक अलग प्रकार है, बेशक a ~ b), जबकि एक प्रकार का परिवार एक ही मौजूदा प्रकार पर एकाधिक इनपुट प्रकारों को मानचित्र कर सकता है।

एक सेकंड यह है कि डेटा परिवारों को आंशिक रूप से लागू किया जा सकता है, किसी अन्य प्रकार के कन्स्ट्रक्टर की तरह, जबकि परिवार नहीं कर सकते हैं।

यह एक विशेष रूप से वास्तविक दुनिया उदाहरण नहीं है, लेकिन उदाहरण के लिए, आप कर सकते हैं:

data instance DF Int = DInt Int 
data instance DF String = DString String 

class C t where 
    foo :: t Int -> t String 

instance C DF where -- notice we are using DF without an argument 
        -- notice also that you can write instances for data families at all, 
        -- unlike type families 
    foo (DInt i) = DString (show i) 

असल में, DF और DF a किसी अन्य की तरह, वास्तविक, प्रथम श्रेणी, वैध प्रकार, अपने आप में कर रहे हैं टाइप करें data के साथ घोषित करें। TF a सिर्फ एक मध्यवर्ती रूप है जो एक प्रकार का मूल्यांकन करता है।

लेकिन मुझे लगता है कि यह सब बहुत प्रबुद्ध नहीं है, या कम से कम यह मेरे लिए नहीं था, जब मैं डेटा परिवारों के बारे में सोच रहा था और इसी तरह की चीजें पढ़ता था।

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

vector लाइब्रेरी से वास्तविक दुनिया का उदाहरण। vector में कई अलग-अलग प्रकार के वेक्टर हैं: बॉक्स किए गए वैक्टर, अनबॉक्स किए गए वैक्टर, आदिम वैक्टर, स्टेबल वैक्टर। प्रत्येक Vector प्रकार के लिए एक संबंधित, mutable MVector प्रकार (सामान्य वेक्टर अपरिवर्तनीय हैं) टाइप करें। तो यह इस तरह दिखता है: बजाए किसी

type family Mutable v :: * -> * -> * -- the result type has two type parameters 

module Data.Vector{.Mutable} where 
data Vector a = ... 
data MVector s a = ... 
type instance Mutable Vector = MVector 

module Data.Vector.Storable{.Mutable} where 
data Vector a = ... 
data MVector s a = ... 
type instance Mutable Vector = MVector 

[etc.] 

अब, मैं नहीं बल्कि होगा:

data family Mutable v :: * -> * -> * 

module Data.Vector{.Mutable} where 
data Vector a = ... 
data instance Mutable Vector s a = ... 
type MVector = Mutable Vector 

module Data.Vector.Storable{.Mutable} where 
data Vector a = ... 
data instance Mutable Vector s a = ... 
type MVector = Mutable Vector 

[etc.] 

कौन सा अपरिवर्तनीय encodes ठीक एक Mutable Vector प्रकार है कि वहाँ हर Vector प्रकार के लिए, और है कि वहाँ उनके बीच एक-एक-एक पत्राचार। Vector के उत्परिवर्तनीय संस्करण को हमेशा Mutable Vector कहा जाता है: यह उसका नाम है, और इसमें कोई अन्य नहीं है। यदि आपके पास Mutable Vector है, तो आप संबंधित अपरिवर्तनीय Vector का प्रकार प्राप्त कर सकते हैं, क्योंकि यह एक प्रकार तर्क के रूप में ठीक है। type family Mutable के साथ, एक बार जब आप इसे तर्क के लिए लागू करते हैं तो यह एक अनिर्दिष्ट परिणाम प्रकार का मूल्यांकन करता है (संभवतः MVector कहा जाता है, लेकिन आप नहीं जानते), और आपके पास पीछे की ओर मानचित्र करने का कोई तरीका नहीं है।

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