2010-08-23 6 views
58

आ रहा है, मैं थोड़ा सा हास्केल सीखने की कोशिश कर रहा हूं। संक्रमण काफी अच्छी तरह से चला जाता है लेकिन मैं डिबगिंग के साथ थोड़ा उलझन में हूं। मैं अपने ओकंपल कोड में (बहुत सारे) "printf" डालता था, कुछ मध्यवर्ती मूल्यों का निरीक्षण करने के लिए, या ध्वज के रूप में यह देखने के लिए कि गणना कहां विफल रही थी।प्रिंटफेस के साथ हास्केल को "डीबग" कैसे करें? O12l समुदाय से

printf के बाद से, एक आईओ कार्रवाई है आईओ इकाई के अंदर अपने सभी Haskell कोड डिबगिंग के इस प्रकार के लिए सक्षम होना मैं लिफ्ट करने के लिए क्या है? या वहां यह करने के लिए एक बेहतर तरीका

मैं भी ट्रेस समारोह लगता है (मैं वास्तव में हाथ से यह करने के लिए अगर यह बचा जा सकता है नहीं करना चाहती) है: http://www.haskell.org/haskellwiki/Debugging#Printf_and_friends लगता है जो मैं वास्तव में क्या चाहते हैं, लेकिन मुझे यह समझ में नहीं आता है: आईओ कहीं भी नहीं है! क्या कोई मुझे ट्रेस फ़ंक्शन के व्यवहार की व्याख्या कर सकता है?

+6

यह ध्यान दिया जाना चाहिए कि 'ट्रेस' केवल डीबगिंग के लिए है, और यदि आप इसे "वास्तविक" तर्क के लिए उपयोग करते हैं तो इसे समुदाय द्वारा छोड़ा जाता है। – luqui

उत्तर

53

trace डीबगिंग के लिए विधि का उपयोग करने का सबसे आसान तरीका है। यह IO में बिल्कुल आपके कारण के कारण नहीं है: IO मोनड में अपना कोड उठाने की कोई आवश्यकता नहीं है। यह इस

trace :: String -> a -> a 
trace string expr = unsafePerformIO $ do 
    putTraceMsg string 
    return expr 

तरह लागू हो जाता है तो वहाँ आईओ पर्दे के पीछे है, लेकिन unsafePerformIO इससे बाहर से बचने के लिए प्रयोग किया जाता है। यह एक ऐसा कार्य है जो संभावित रूप से संदर्भित पारदर्शिता को तोड़ देता है जिसे आप अनुमान लगा सकते हैं कि इसके प्रकार IO a -> a और इसका नाम भी देख रहा है।

-4

ठीक है, क्योंकि पूरे हास्केल आलसी मूल्यांकन के सिद्धांत के आसपास बनाया गया है (ताकि गणना का क्रम वास्तव में गैर-निर्धारक है), प्रिंटफ के उपयोग में बहुत कम समझ है।

यदि आरपीएल + निरीक्षण परिणाम मान आपके डीबगिंग के लिए वास्तव में पर्याप्त नहीं है, तो आईओ में सब कुछ लपेटना एकमात्र विकल्प है (लेकिन यह हास्केल प्रोग्रामिंग का सही तरीका नहीं है)।

+1

आपके दावों दोनों के रूप में डाउनवॉटेड हैं झूठे हैं। गणना के क्रम में कॉल में स्थिर रूप से निर्धारित किया जाता है। यह न केवल फ़ंक्शन बॉडी द्वारा निर्धारित किया जाता है, बल्कि बाहरी संदर्भ से भी कार्य निष्पादित होता है। ऐसा नहीं है कि डेटा निर्भरता रन टाइम पर निर्धारित होती है और रनटाइम मानों के आधार पर अप्रत्याशित प्रत्यक्ष नियंत्रण प्रवाह होती है। दूसरे पैराग्राफ के लिए - आरईपीएल के अलावा बहुत सारे विकल्प हैं: ट्रेसिंग (ढेर इंस्पेक्टरों को 'ट्रेस' से ज्यादा स्मार्ट), परीक्षण, ghci डीबगर और ग्राफ़िक फ्रंट इसके लिए समाप्त होता है (लेक्सह इत्यादि)। – nponeccop

16

trace बस अशुद्ध बना दिया गया है। IO मोनैड का बिंदु शुद्धता को संरक्षित करना है (टाइप सिस्टम द्वारा अनजान कोई IO नहीं) और बयान के निष्पादन के आदेश को परिभाषित करता है, जो अन्यथा आलसी मूल्यांकन के माध्यम से व्यावहारिक रूप से अपरिभाषित किया जाएगा।

अपने जोखिम पर हालांकि, आप फिर भी IO a -> a को एक साथ हैक कर सकते हैं, यानी अशुद्ध IO निष्पादित करें। यह एक हैक है और निश्चित रूप से आलसी मूल्यांकन से "पीड़ित" है, लेकिन यह डिबगिंग के लिए बस यही ट्रेस करता है।

फिर भी, हालांकि, तो आप शायद अन्य तरीकों डिबगिंग के लिए जाना चाहिए:

1) मध्यवर्ती मूल्यों

  • डिबगिंग के लिए की जरूरत को कम करने के लिए छोटे, पुन: प्रयोज्य, स्पष्ट, सामान्य कार्यों जिसका शुद्धता स्पष्ट है लिखें।
  • सही टुकड़ों को अधिक सही टुकड़ों में मिलाएं।
  • tests लिखें या टुकड़े सहभागी

2)

  • उपयोग breakpoints आदि (संकलक आधारित डीबगिंग)

3)

  • की कोशिश जेनेरिक एम का प्रयोग करें onads। यदि आपका कोड मोनैडिक है, फिर भी इसे एक ठोस मोनड से स्वतंत्र लिखें। सादे IO ... के बजाय type M a = ... का उपयोग करें। बाद में आप आसानी से ट्रांसफॉर्मर के माध्यम से मोनैड को जोड़ सकते हैं और इसके शीर्ष पर एक डिबगिंग मोनड डाल सकते हैं। यहां तक ​​कि यदि मोनैड की आवश्यकता खत्म हो गई है, तो आप शुद्ध मूल्यों के लिए Identity a डाल सकते हैं।
13

क्या इसके लायक है के लिए, वहाँ वास्तव में इस मुद्दे पर यहाँ हैं "डिबगिंग" के दो प्रकार: इस तरह के मूल्य एक विशेष उपसूचक एक पुनरावर्ती समारोह में प्रत्येक कॉल पर है के रूप में

  • लॉगिंग मध्यवर्ती मूल्यों,
  • अभिव्यक्ति के मूल्यांकन के रनटाइम व्यवहार का निरीक्षण

सख्त अनिवार्य भाषा में ये आम तौर पर मेल खाते हैं। हास्केल में, वे अक्सर नहीं करते:

  • रिकॉर्डिंग मध्यवर्ती मूल्य रनटाइम व्यवहार को बदल सकते हैं, जैसे कि अन्यथा छोड़े जाने वाले शब्दों के मूल्यांकन को मजबूर कर सकते हैं।
  • आलस्य की वास्तविक प्रक्रिया आलस्य और साझा उप-अभिव्यक्तियों के कारण अभिव्यक्ति की स्पष्ट संरचना से नाटकीय रूप से भिन्न हो सकती है। बल्कि IO में सब कुछ उठाने की तुलना में, उदाहरण के लिए, एक साधारण Writer इकाई पर्याप्त होगा, कार्य करने के लिए इस से किया जा रहा बराबर -

तुम सिर्फ मध्यवर्ती मूल्यों की एक लॉग रखने के लिए चाहते हैं, तो ऐसा करने के लिए कई तरीके हैं अपने वास्तविक परिणाम और एक संचयक मूल्य (कुछ प्रकार की सूची, आमतौर पर) के 2-टुपल को वापस करें।

यह भी नहीं आम तौर पर आवश्यक इकाई में सब कुछ डाल करने के लिए है, केवल कार्यों कि "लॉग ऑन" मूल्य पर लिखने की जरूरत है - उदाहरण के लिए, आप बस subexpressions कि लॉगिंग करने के लिए आवश्यकता हो सकती है बाहर कारक बन सकते हैं, मुख्य तर्क शुद्ध छोड़कर, फिर fmap एस और व्हाट्नॉट के साथ सामान्य कार्यों में शुद्ध कार्यों और लॉगिंग कंप्यूटेशंस को जोड़कर समग्र गणना को फिर से इकट्ठा करें। ध्यान रखें कि Writer एक मोनैड के लिए खेदजनक बहाना है: लॉग से पढ़ने के लिए कोई तरीका नहीं है, केवल इसे लिखें, प्रत्येक गणना तर्कसंगत रूप से इसके संदर्भ से स्वतंत्र है, जिससे चीजों को चारों ओर जोड़ना आसान हो जाता है।

लेकिन कुछ मामलों में भी यह अधिक है - कई शुद्ध कार्यों के लिए, केवल उप-अभिव्यक्तियों को अपरिवर्तित करने और आरईपीएल में चीजों को करने की कोशिश करना बहुत अच्छी तरह से काम करता है।

आप वास्तव में निरीक्षण शुद्ध कोड का रन-टाइम व्यवहार, तथापि करना चाहते हैं - उदाहरण के लिए, यह पता लगाने की क्यों एक उपसूचक diverges - वहाँ सामान्य में अन्य शुद्ध कोड से ऐसा करने के लिए कोई रास्ता नहीं है - वास्तव में, यह अनिवार्य रूप से परिभाषा शुद्धता है। तो उस स्थिति में, आपके पास शुद्ध भाषा "बाहरी" मौजूद उपकरण का उपयोग करने के अलावा कोई विकल्प नहीं है: या तो unsafePerformPrintfDebugging --errr जैसे अशुद्ध कार्य, मेरा मतलब है trace - या संशोधित रनटाइम पर्यावरण, जैसे कि जीएचसीआई डीबगर।

1

trace भी प्रक्रिया में आलस्य के बहुत से लाभ खोने, प्रिंटिंग के लिए अपने तर्क का अधिक मूल्यांकन करने का प्रयास करता है।

+0

अच्छी तरह से, तब ऐसा न करें :-) (यानी केवल उस चीज का पता लगाएं जिसे आप मजबूर करने में विश्वास करते हैं) – sclv

0

आप जब तक कार्यक्रम, उत्पादन का अध्ययन से पहले समाप्त हो गया तो एक Writer monad स्टैकिंग है एक लकड़हारा को लागू करने के लिए दृष्टिकोण होता है इंतज़ार कर सकते हैं। मैं इस here का उपयोग अशुद्ध एचडीबीसी कोड से परिणाम सेट वापस करने के लिए करता हूं।

+0

आलसी मूल्यांकन के कारण: प्रोग्राम को समाप्त होने तक आपको वास्तव में प्रतीक्षा नहीं करना पड़ेगा। –

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