2016-08-07 3 views
5

this answer में, किसी को यह बयान मिलता है कि वास्तविक पार्सिंग पहले से ही पूरा होने के साथ डेटाटाइप Tree के लिए Read उदाहरण को लागू करना बहुत कठिन नहीं होगा।हास्केल में, वास्तविक पार्सिंग के साथ पहले से पढ़ा गया एक उदाहरण उदाहरण कैसे कार्यान्वित करें?

हालांकि, मैं एक कठिन समय को समझने के लिए read काम करता है के रूप में इस तरह के एक समारोह हो रहा है: AFAIK, मैं read के बजाय एक readsPrec समारोह को लागू करना चाहिए और इस readsPrec केवल एक वर्ण से मिलकर स्ट्रिंग्स के लिए पढ़ने करना चाहिए। क्या ये सही है?
यदि ऐसा है, तो Tree का उदाहरण कैसे लागू करना चाहिए जब पार्सिंग के माध्यम से किया जाता है? क्या हम शब्द से पार्सिंग शब्द तोड़ सकते हैं, या ऐसा करने की कोई ज़रूरत है?

मैं हास्केल में एक मुश्किल सुविधा के रूप में read के बारे में सोच नहीं था, लेकिन अब मैं यह काफी उलझन और भ्रामक लगता है, और मैं readP_to_S, readS के रूप में इस तरह के सभी अपरिचित बातों के लिए Hoogle खोज में खो रहा हूँ, आदि

किसी भी मदद या संदर्भ की सराहना की जाएगी।

+1

के प्रकार दिखाई देते हैं 'readsPrec' सिर्फ' Int -> स्ट्रिंग -> [(ए, स्ट्रिंग)] 'है। आप पढ़ने की विफलता को इंगित करने के लिए खाली सूची वापस कर सकते हैं, या सिंगलटन '[(x," ")] 'जहां' x' सफलता को दर्शाने के लिए पार्स परिणाम है। यदि आपके पास पहले से ही आपके प्रकार के लिए 'पारसी' पार्सर है, या कोई अन्य पार्सर है, तो बस इस पार्सर को चलाएं और इसके आउटपुट को उचित रूप में रूपांतरित करें। – user2407038

+0

लेकिन यह गलत दिखता है: यह उस स्ट्रिंग को वापस नहीं करेगा जो पार्स नहीं किया गया है, है ना? – awllower

उत्तर

6

मैं कुछ समय के लिए इस बारे में सोच रहा हूं, और आपके प्रश्न ने मुझे इसे देखने के लिए प्रेरित किया।

सारांश: सबसे आसान तरीका मैन्युअल रूप से ऐसा करने के लिए:

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 जैसी लाइब्रेरी शायद बेहतर विकल्प हैं।

आप ऊर्जा खुद के स्रोत कोड में देखने के लिए है, तो प्रासंगिक मॉड्यूल

+2

'readsPrec _ str = [(parsecRead str," ")] 'एक बुरा विचार की तरह लगता है। यह पार्स त्रुटियों को पूरी तरह से अनदेखा करता है, और उन कार्यों के साथ अच्छी तरह से रचना नहीं करता है जो 'readsPrec' को स्ट्रिंग के अनपेक्षित बिट्स को वापस करने की अपेक्षा करते हैं। और और भी, इन तरीकों से बुरा होने के लिए भी जरूरी नहीं है: parsec पार्स त्रुटियों की रिपोर्ट करने में पूरी तरह सक्षम है और इनपुट स्ट्रिंग के अनपेक्षित हिस्से को वापस करने में पूरी तरह सक्षम है। –

+0

@DanielWagner ऐसा लगता है कि यह एक सुधार होगा! क्या आप एक उदाहरण प्रदान कर सकते हैं? मैं पार्ससी से बहुत परिचित नहीं हूं और मुझे दस्तावेज़ीकरण में अनपेक्षित हिस्से को वापस करने का एक स्पष्ट तरीका नहीं मिल रहा है। –

+0

[यहां अवधारणा का सबूत है।] (Http: // lpaste।नेट/175029) ghci में, 'parsecToReads (char' a '<|> char' b ') "abc" 'उत्पादन' [('a'," bc ")]'। –

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