2013-06-17 9 views
7

आज मैं जांच करना चाहता था कि डेटा प्रकार को इस तरह से बनाना संभव है, कि यह अपने प्रकार के हस्ताक्षर के प्रकार को संग्रहीत नहीं करता है, लेकिन इसका एक और प्रतिनिधित्व । तो, यहां एक जीएडीटी का मेरा प्रयास है जिसमें a प्रकार का एक प्रकार का कन्स्ट्रक्टर है, लेकिन ByteString प्रकार का डेटा कन्स्ट्रक्टर है।टाइप बाधा के साथ एक जीएडीटी के लिए फंक्टर इंस्टेंस

{-# LANGUAGE GADTs #-} 
import Data.ByteString.Char8 
import Data.Serialize 

data Serialized a where 
    MkSerialized :: (Serialize a) => ByteString -> Serialized a 

अब मैं निम्नलिखित तरीके से एक decode' समारोह को परिभाषित कर सकते हैं:

decode' :: (Serialize a) => Serialized a -> a 
decode' (MkSerialized bs) = let Right r = (decode bs) in r 

और यह काम करता है:

let s = MkSerialized (encode "test") :: Serialized String 
print $ decode' s  -- prints "test" 

मेरे समस्या अब है कि मैं Serialized चाहते हैं एक होने के लिए Functor का उदाहरण।

instance Functor Serialized where 
    fmap f (MkSerialized bs) = MkSerialized (encode (f (right (decode bs)))) 
           where right (Right r) = r 

लेकिन मुझे त्रुटि मिलती है (Serialize बी) को घटाया नहीं जा सकता है। मैं फंक्टर इंस्टेंस को कैसे बाधित कर सकता हूं ताकि Serializefmap में लागू हो सके?

+2

आप नहीं कर सकते। 'फ़ैक्टर' टाइप पैरामीटर की आवश्यकता होने पर बाधाओं की अनुमति नहीं देता है। 'Rmonad' पैकेज में एक प्रतिबंधित मज़ेदार वर्ग, [' RFunctor'] (http://hackage.haskell.org/packages/archive/rmonad/0.8/doc/html/Control-RMonad.html#t:RFunctor) है । शायद आप इसका इस्तेमाल कर सकते हैं। –

+2

यह आपके प्रश्न से संबंधित नहीं है - यह वास्तव में 'फंक्टर' के साथ संभव नहीं है - लेकिन मुझे उल्लेख करने के लिए बाध्य होना चाहिए: कृपया डिफ़ॉल्ट रूप से 'Data.ByteString.Char8' का उपयोग न करें! यह टूटा हुआ मॉड्यूल है जो टूटे हुए कोड को प्रोत्साहित करता है। कभी-कभी इसके लिए कुछ उपयोग होते हैं, लेकिन आपका कोड 'डेटा.बेटस्ट्रिंग' के साथ ही काम करता है, जो यूनिकोड की गलतफहमी को प्रोत्साहित नहीं करता है। – shachaf

+1

इसके लायक होने के लिए, आप 'CoYoneda'-style डेटा प्रकार जैसे डेटा को सीरियलाइज्ड कर सकते हैं जहां MkSerialized :: Serialize x => ByteString -> (x -> a) -> Serialized a' जो बाइटस्ट्रिंग और एक स्टोर करता है पोस्ट-डेसेरियलाइजेशन फ़ंक्शन, और जिसमें 'फ़ैक्टर' उदाहरण होता है। लेकिन निश्चित रूप से यहां उद्देश्य को हरा देता है। – shachaf

उत्तर

6

आप इसे CoYoneda functor का उपयोग कर ऐसा कर सकते हैं।

विचार सरल है: एक अतिरिक्त कार्यात्मक क्षेत्र है जहां आप अपने fmap आईएनजी कार्यों को जमा करते हैं। जब आप अपना मान डीकोड करते हैं, तो उस फ़ंक्शन को लागू करें। ,

{-# LANGUAGE GADTs #-} 
import Data.ByteString.Char8 
import Data.Serialize 

data Serialized a where 
    MkSerialized 
     :: (Serialize a) 
     => ByteString -> (a -> b) -> Serialized b 

decode' :: Serialized a -> a 
decode' (MkSerialized bs f) = let Right r = decode bs in f r 

instance Functor Serialized where 
    fmap f (MkSerialized bs g) = MkSerialized bs (f . g) 

यह भी स्वचालित रूप से बार-बार decodings के बजाय कई fmap रों और एन्कोडिंग fusing को लाभ मिलता है के रूप में अपने मामले में होगा:

कोड यह रहा।

+2

हालांकि यह वास्तव में मेरी समस्या को हल नहीं कर रहा है (क्योंकि मुझे बार-बार डी-एन्कोडिंग करने के लिए 'fmap' पसंद आया होगा), मैं यह जवाब स्वीकार करूंगा b/c मुझे लगता है कि मेरा मूल विचार संभव नहीं है और यह है एक बाध्य GADT के लिए एक मजेदार को परिभाषित करने का सबसे व्यावहारिक तरीका। इसके अलावा, [जीएडीटी और योनाना मज़दूरों के लिए दिलचस्प पढ़ना] (http://www.haskellforall.com/2012/06/gadts.html)। – Phae7rae

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