मैं कुछ समय के लिए इस बारे में सोच रहा हूं, और आपके प्रश्न ने मुझे इसे देखने के लिए प्रेरित किया।
सारांश: सबसे आसान तरीका मैन्युअल रूप से ऐसा करने के लिए:
instance Read Tree where
readsPrec _ str = [(parsecRead str,"")]
लेकिन deriving
सुरक्षित विकल्प है, उपरोक्त [Tree]
और अन्य डेटा प्रकारों के साथ काम नहीं करता है। मेरी समझ यह है कि Show
और Read
मैन्युअल रूप से लागू करने का इरादा नहीं है; वे व्युत्पन्न किए जाने चाहिए और पर कार्य करें, हास्केल अभिव्यक्ति को व्यवस्थित रूप से सही करें।
यह कारण यह है कि Read
के रूप में, पुनरावर्ती
class Read a where
read :: String -> a
पार्सर combinators, Parsec से करने के लिए समान है, लेकिन अलग करने की प्रणाली है कि वहाँ है, कि मॉड्यूलर के लिए बनाया गया के रूप में सरल नहीं है की तरह लग रहा , और इसी तरह। लेकिन चूंकि हम पहले से ही एक अलग पार्सर संयोजक लाइब्रेरी, पारसेक का उपयोग कर रहे हैं, मुझे लगता है कि जितना संभव हो सके अन्य सिस्टम के साथ गड़बड़ करना सबसे अच्छा है।
प्रीलूड प्रलेखन का कहना है कि Read
का न्यूनतम पूर्ण कार्यान्वयन readsPrec
या readPrec
है। उत्तरार्द्ध को "नए-शैली पार्सर्स (केवल जीएचसी) का उपयोग करके रीडस्पेक के लिए प्रस्तावित प्रतिस्थापन के रूप में वर्णित किया गया है। यह मुझे परेशानी की तरह गंध करता है, तो चलो readsPrec
लागू करने के साथ चलते हैं।
प्रकार
readsPrec :: Read a => Int -> ReadS a
type ReadS a = String -> [(a,String)]
है और ReadS
के लिए दस्तावेज़ "एक प्रकार a
, एक समारोह है कि एक String
लेता है और (a,String)
जोड़े के रूप में संभव पार्स करता है की एक सूची देता है के रूप में प्रतिनिधित्व के लिए एक पार्सर" पढ़ता है।मेरे लिए, यह पूरी तरह से स्पष्ट है कि एक "पार्स" है नहीं है, लेकिन source code for read
in Text.Read
पर एक नज़र प्रकट कर रहा है:
read :: Read a => String -> a
read s = either errorWithoutStackTrace id (readEither s)
readEither :: Read a => String -> Either String a
readEither s =
-- minPrec is defined as 0 in Text.ParserCombinators.ReadPrec
case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
[x] -> Right x
[] -> Left "Prelude.read: no parse"
_ -> Left "Prelude.read: ambiguous parse"
where
read' = -- read' :: P.ReadPrec a
do x <- readPrec
lift P.skipSpaces -- P is Text.ParserCombinators.ReadP
return x
मैं readPrec_to_S
आदि की परिभाषा का विस्तार करने की कोशिश की, लेकिन मुझे लगा कि यह इसके लायक नहीं था । मुझे लगता है कि परिभाषा स्पष्ट करती है कि हमें एक सफल पार्स के रूप में [(x,"")]
वापस करना चाहिए।
readsPrec
पर पूर्णांक तर्क "प्राथमिकता संदर्भ" प्रतीत होता है। मेरा अनुमान है कि अगर हम सिर्फ एक पेड़ को एक समय में पार्स करना चाहते हैं, तो इसे अनदेखा करना सुरक्षित है, लेकिन अगर हम [Tree]
के उदाहरणों को पार्स करने का प्रयास करते हैं तो इससे अनदेखा करना समस्याएं पैदा करेगा। मैं इसे अनदेखा कर दूंगा क्योंकि मुझे नहीं लगता कि यह मुसीबत के लायक है।
संक्षेप में, अगर हम parsecRead :: String -> Tree
है के रूप में की गई पोस्ट को देखें में परिभाषित (लेखक यह read'
कहा जाता है)
instance Read Tree where
readsPrec _ str = [(parsecRead str,"")]
अगर हम जाँच यह कैसे एक प्रोग्राम (Show
उदाहरण है कि मूल का उपयोग कर में काम करता है प्रश्नकर्ता प्रदान की गई):
main = do
print (read "ABC(DE)F" == example)
print ([read "ABC(DE)F", read "ABC(DE)F"] :: [Tree])
print (read "[ABC(DE)F,ABC(DE)F]" :: [Tree])
हम
True
[ABC(DE)F,ABC(DE)F]
Test.hs: Prelude.read: no parse
मिल
यहां जटिलता और दस्तावेज़ीकरण की कमी वास्तव में मुझे लगता है कि deriving (Read)
वास्तव में एकमात्र सुरक्षित विकल्प है, जब तक कि आप प्राथमिकता के स्तर के विवरण में डुबकी नहीं लेना चाहते हैं। मुझे लगता है कि मैंने कहीं पढ़ा है कि Show
और Read
वास्तव में कर रहे मुख्य रूप से प्राप्त किया जा करने का इरादा है, और उस तार (कृपया मुझे ठीक कर लें मैं गलत हूँ) वाक्य रचना सही हास्केल भाव करने का इरादा कर रहे हैं। अधिक सामान्य पार्सिंग के लिए, Parsec
जैसी लाइब्रेरी शायद बेहतर विकल्प हैं।
आप ऊर्जा खुद के स्रोत कोड में देखने के लिए है, तो प्रासंगिक मॉड्यूल
के प्रकार दिखाई देते हैं 'readsPrec' सिर्फ' Int -> स्ट्रिंग -> [(ए, स्ट्रिंग)] 'है। आप पढ़ने की विफलता को इंगित करने के लिए खाली सूची वापस कर सकते हैं, या सिंगलटन '[(x," ")] 'जहां' x' सफलता को दर्शाने के लिए पार्स परिणाम है। यदि आपके पास पहले से ही आपके प्रकार के लिए 'पारसी' पार्सर है, या कोई अन्य पार्सर है, तो बस इस पार्सर को चलाएं और इसके आउटपुट को उचित रूप में रूपांतरित करें। – user2407038
लेकिन यह गलत दिखता है: यह उस स्ट्रिंग को वापस नहीं करेगा जो पार्स नहीं किया गया है, है ना? – awllower