हास्केल की सख्ती के बिंदु क्या हैं?


90

हम सभी जानते हैं (या पता होना चाहिए) कि हास्केल डिफ़ॉल्ट रूप से आलसी है। किसी भी चीज का मूल्यांकन तब तक नहीं किया जाता जब तक उसका मूल्यांकन न किया जाए। तो कुछ का मूल्यांकन कब किया जाना चाहिए? ऐसे बिंदु हैं जहां हास्केल को सख्त होना चाहिए। मैं इन "कठोरता बिंदुओं" को कहता हूं, हालांकि यह विशेष शब्द उतना व्यापक नहीं है जितना मैंने सोचा था। मेरे हिसाब से:

हास्केल में कटौती (या मूल्यांकन) केवल कठोरता बिंदुओं पर होती है।

तो सवाल यह है: क्या, ठीक है , हास्केल की सख्ती अंक हैं? मेरा अंतर्ज्ञान कहता है कि main, seq/ बैंग पैटर्न, पैटर्न मिलान, और किसी भी IOक्रिया के माध्यम से प्रदर्शन mainप्राथमिक कठोरता बिंदु हैं, लेकिन मुझे वास्तव में नहीं पता कि मैं क्यों जानता हूं।

(इसके अलावा, अगर वे "कठोरता अंक", कहा जाता है नहीं कर रहे हैं क्या कर रहे हैं वे कहा जाता है?)

मैं कल्पना करता हूं कि एक अच्छे उत्तर में WHNF वगैरह के बारे में कुछ चर्चा शामिल होगी। मैं यह भी कल्पना करता हूं कि यह लंबोदा पथरी पर छू सकता है।


संपादित करें: इस प्रश्न के बारे में अतिरिक्त विचार।

जैसा कि मैंने इस प्रश्न पर प्रतिबिंबित किया है, मुझे लगता है कि यह एक कठोरता बिंदु की परिभाषा में कुछ जोड़ना स्पष्ट होगा। सख़्ती अंक अलग हो सकता है संदर्भों और अलग गहराई (या कठोरता)। अपनी परिभाषा में वापस आते हुए कि "हास्केल में कमी केवल सख्ती के बिंदुओं पर होती है", हम इस खंड में उस परिभाषा को जोड़ते हैं: "एक कठोरता बिंदु केवल तभी ट्रिगर होता है जब इसके आसपास के संदर्भ का मूल्यांकन या कम किया जाता है।"

इसलिए, मुझे उस तरह के उत्तर पर आरंभ करने का प्रयास करना चाहिए जो मैं चाहता हूं। mainएक सख्त बिंदु है। इसे विशेष रूप से इसके संदर्भ के प्राथमिक सख्ती बिंदु के रूप में निर्दिष्ट किया गया है: कार्यक्रम। जब कार्यक्रम ( mainसंदर्भ) का मूल्यांकन किया जाता है, तो मुख्य की कठोरता बिंदु सक्रिय हो जाती है। मुख्य की गहराई अधिकतम है: इसका पूरी तरह से मूल्यांकन किया जाना चाहिए। मुख्य आमतौर पर आईओ कार्यों, जो भी कठोरता अंक, जिसका संदर्भ है से बना है main

अब आप कोशिश करते हैं: seqइन शब्दों में चर्चा और पैटर्न मिलान। फ़ंक्शन एप्लिकेशन की बारीकियों को समझाएं: यह कैसे सख्त है? यह कैसे नहीं है? किस बारे में deepseq? letऔर caseबयान? unsafePerformIO? Debug.Trace? शीर्ष स्तर की परिभाषाएँ? सख्त डेटा प्रकार? बैंग पैटर्न? आदि। इन मदों में से कितने को सिर्फ seq या पैटर्न मिलान के संदर्भ में वर्णित किया जा सकता है?


10
आपकी सहज सूची शायद बहुत ओर्थोगोनल नहीं है। मुझे संदेह है कि seqऔर पैटर्न मिलान पर्याप्त हैं, बाकी उन के संदर्भ में परिभाषित हैं। मुझे लगता है कि पैटर्न का मिलान IOक्रियाओं की रीढ़-कठोरता का आश्वासन देता है , उदाहरण के लिए।
सीए मैककैन

प्रिमिटिव, जैसे +कि अंतर्निहित संख्यात्मक प्रकार भी सख्ती को मजबूर करते हैं, और मुझे लगता है कि शुद्ध एफएफआई कॉल पर भी यही लागू होता है।
हमार

4
ऐसा लगता है कि यहां दो अवधारणाएं भ्रमित हो रही हैं। पैटर्न मिलान और seq और बैंग पैटर्न ऐसे तरीके हैं जो एक अभिव्यक्ति अपने उप-अभिव्यक्तियों में सख्त हो सकती है - अर्थात, यदि शीर्ष अभिव्यक्ति का मूल्यांकन किया जाता है, तो यह सबप्रेप्रेशन है। दूसरी ओर, मुख्य प्रदर्शन IO क्रियाएं होती हैं कि मूल्यांकन कैसे शुरू होता है । ये अलग-अलग चीजें हैं, और उन्हें एक ही सूची में शामिल करने के लिए एक प्रकार की त्रुटि है।
क्रिस स्मिथ

@ क्रिसमिथ उन दो अलग-अलग मामलों को भ्रमित करने की कोशिश नहीं कर रहा हूं; अगर मैं कुछ भी पूछ रहा हूँ तो वे कैसे बातचीत करते हैं, इस बारे में और स्पष्टीकरण देने के लिए कह रहा हूँ। सख्ती किसी भी तरह से होती है, और दोनों मामले महत्वपूर्ण हैं, हालांकि अलग-अलग, सख्ती के कुछ हिस्सों में "हो रहा है"। (और @ मोनैडिक: ಠ_ಠ)
डैन बर्टन

यदि आप इस प्रश्न के पहलुओं पर चर्चा करने के लिए / आवश्यकता कक्ष चाहते हैं, तो पूर्ण उत्तर दिए बिना, मुझे इस प्रश्न के लिए मेरे / आर / हैसेल पोस्ट
दान बर्टन

जवाबों:


46

इस पेपर को समझने के लिए एक अच्छी जगह है: ए नेचुरल सेमेंटिक्स फॉर लेजी इवैल्यूएशन (लॉन्चबरी)। यह आपको बताएगा कि जीएचसी के कोर के समान छोटी भाषा के लिए भावों का मूल्यांकन कब किया जाता है। फिर शेष प्रश्न है कि फुल हास्केल को कोर में कैसे मैप किया जाए, और उस अनुवाद का अधिकांश हिस्सा हास्केल रिपोर्ट द्वारा दिया गया है। जीएचसी में हम इस प्रक्रिया को "डिसुगरिंग" कहते हैं, क्योंकि यह सिंटैक्टिक शुगर को हटा देता है।

खैर, यह पूरी कहानी नहीं है, क्योंकि जीएचसी में अवरोही और कोड पीढ़ी के बीच अनुकूलन का एक पूरा बेड़ा शामिल है, और इन परिवर्तनों में से कई कोर को पुनर्व्यवस्थित करेंगे ताकि चीजों को अलग-अलग समय पर मूल्यांकन किया जाए (विशेष रूप से कठोरता विश्लेषण से चीजों का मूल्यांकन किया जाएगा। पहले)। तो वास्तव में यह समझने के लिए कि आपके कार्यक्रम का मूल्यांकन कैसे किया जाएगा, आपको जीएचसी द्वारा उत्पादित कोर को देखने की आवश्यकता है।

शायद यह उत्तर आपको थोड़ा सार लगता है (मैंने विशेष रूप से बैंग पैटर्न या seq का उल्लेख नहीं किया है), लेकिन आपने कुछ सटीक पूछा , और यह सबसे अच्छा है जो हम कर सकते हैं।


18
मैंने हमेशा यह मनोरंजक पाया है कि किस GHC को "डीसुगैरिंग" कहा जाता है, निकाले जा रहे सिंटैक्टिक शुगर में हास्केल भाषा का वास्तविक सिंटैक्स ही शामिल है ... इसका अर्थ है, यह लग सकता है, कि जीएचसी वास्तव में जीएचसी के लिए एक अनुकूलन कंपाइलर है। कोर भाषा, जो संयोगवश भी होती है, जिसमें हास्केल को कोर में अनुवाद करने के लिए एक बहुत विस्तृत फ्रंट-एंड शामिल है। :]
सीए मैक्कैन

टाइप सिस्टम ठीक से नहीं जता है ... विशेष रूप से लेकिन केवल स्पष्ट शब्दों में टाइपकास्ट का अनुवाद करने के संबंध में नहीं, जैसा कि मुझे याद है। और सभी नवीनतम TF / GADT सामान, जैसा कि मैं इसे समझता हूं, उस अंतर को अभी भी व्यापक बना दिया है।
sclv

GCC C को ऑप्टिमाइज़ नहीं करता है: gcc.gnu.org/oniltocs/gccint/Passes.html#Passes
György Andrasek

20

मैं शायद इस सवाल का पुनर्पाठ करूंगा, हास्केल किन परिस्थितियों में एक अभिव्यक्ति का मूल्यांकन करेगा? (शायद "सामान्य रूप से कमजोर सिर के लिए।"

पहले सन्निकटन के लिए, हम इसे इस प्रकार निर्दिष्ट कर सकते हैं:

  • IO क्रियाओं का निष्पादन किसी भी ऐसे भाव का मूल्यांकन करेगा जिसकी उन्हें "आवश्यकता" है। (इसलिए आपको यह जानने की आवश्यकता है कि क्या IO कार्रवाई निष्पादित की जाती है, उदाहरण के लिए यह नाम मुख्य है, या इसे मुख्य से बुलाया जाता है और आपको यह जानना होगा कि कार्रवाई की क्या आवश्यकता है।)
  • एक अभिव्यक्ति जिसका मूल्यांकन किया जा रहा है (हे, वह एक पुनरावर्ती परिभाषा है!) किसी भी अभिव्यक्ति की आवश्यकता का मूल्यांकन करेगा।

आपकी सहज सूची से, मुख्य और IO क्रियाएँ पहली श्रेणी में आती हैं, और seq और पैटर्न मिलान दूसरी श्रेणी में आते हैं। लेकिन मुझे लगता है कि पहली श्रेणी "सख्ती बिंदु" के आपके विचार के अनुरूप है, क्योंकि यह वास्तव में है कि हम कैसे हास्केल में उपयोगकर्ताओं के लिए अवलोकन प्रभाव का मूल्यांकन करते हैं।

सभी विवरण विशेष रूप से देना एक बड़ा काम है, क्योंकि हास्केल एक बड़ी भाषा है। यह भी काफी सूक्ष्म है, क्योंकि समवर्ती हास्केल चीजों का सट्टा रूप से मूल्यांकन कर सकता है, भले ही हम अंत में परिणाम का उपयोग न करें: यह उन चीजों की एक तीसरी नस्ल है जो मूल्यांकन का कारण बनती हैं। दूसरी श्रेणी काफी अच्छी तरह से अध्ययन की गई है: आप इसमें शामिल कार्यों की कठोरता को देखना चाहते हैं । पहली श्रेणी को भी "सख्ती" का एक प्रकार माना जा सकता है, हालांकि यह थोड़ा चकमा देने वाला है क्योंकि evaluate xऔर seq x $ return ()वास्तव में अलग चीजें हैं! यदि आप IO सनक (स्पष्ट रूप से RealWorld#सरल मामलों के लिए एक टोकन पासिंग कार्य) पास कर रहे हैं, तो आप इसे ठीक तरह से व्यवहार कर सकते हैं , लेकिन मुझे नहीं पता कि सामान्य रूप से स्तरीकृत कठोरता विश्लेषण के इस प्रकार का कोई नाम है या नहीं।


17

सी में अनुक्रम बिंदुओं की अवधारणा है , जो विशेष संचालन के लिए गारंटी है कि एक ऑपरेंड का मूल्यांकन दूसरे से पहले किया जाएगा। मुझे लगता है कि यह सबसे नज़दीकी मौजूदा अवधारणा है, लेकिन अनिवार्य रूप से समतुल्य शब्द की सख्ती का बिंदु (या संभवतः बल बिंदु ) हास्केल सोच के अनुरूप है।

व्यवहार में हास्केल एक विशुद्ध रूप से आलसी भाषा नहीं है: उदाहरण के लिए पैटर्न मिलान आमतौर पर सख्त होता है (इसलिए एक पैटर्न मैच बलों के मूल्यांकन की कोशिश कर रहा है कि मैच को स्वीकार या अस्वीकार करने के लिए कम से कम पर्याप्त हो।

...

प्रोग्रामर seqअभिव्यक्ति का बल देने के लिए आदिम का उपयोग कर सकते हैं, इस बात की परवाह किए बिना कि क्या कभी भी परिणाम का उपयोग किया जाएगा।

$!के संदर्भ में परिभाषित किया गया है seq

- आलसी बनाम गैर-सख्त

के बारे में अपनी सोच तो !/ $!और seqअनिवार्य रूप से सही है, लेकिन पैटर्न मिलान सूक्ष्म नियमों के अधीन है। आप हमेशा ~आलसी पैटर्न से मेल खाने के लिए मजबूर कर सकते हैं । उसी लेख से एक दिलचस्प बात:

कठोरता विश्लेषक उन मामलों की भी तलाश करता है, जहां बाहरी अभिव्यक्ति द्वारा हमेशा उप-अभिव्यक्ति की आवश्यकता होती है, और उन लोगों को उत्सुक मूल्यांकन में परिवर्तित करता है। यह कर सकते हैं क्योंकि शब्दार्थ ("नीचे" के संदर्भ में) नहीं बदलते हैं।

चलो खरगोश छेद नीचे जारी रखें और GHC द्वारा किए गए अनुकूलन के लिए डॉक्स देखें:

कठोरता विश्लेषण एक प्रक्रिया है जिसके द्वारा जीएचसी संकलन-समय पर निर्धारित करने का प्रयास करता है, जो निश्चित रूप से डेटा की 'हमेशा जरूरत' होगी। जीएचसी तब गणना को संग्रहीत करने और बाद में इसे निष्पादित करने के लिए सामान्य (उच्च ओवरहेड) प्रक्रिया के बजाय ऐसे डेटा की गणना करने के लिए कोड का निर्माण कर सकता है।

- जीएचसी ऑप्टिमाइज़ेशन: सख्ती विश्लेषण

दूसरे शब्दों में, कड़ाई से अनुकूलन के रूप में कहीं भी सख्त कोड उत्पन्न हो सकता है , क्योंकि थ्रैड बनाना अनावश्यक रूप से महंगा है, जब डेटा की हमेशा जरूरत होगी (और / या केवल एक बार उपयोग किया जा सकता है)।

… मूल्य पर कोई और मूल्यांकन नहीं किया जा सकता है; इसे सामान्य रूप में कहा जाता है । यदि हम किसी भी मध्यवर्ती कदम पर हैं ताकि हमने कम से कम कुछ मूल्यांकन एक मूल्य पर किया है, तो यह कमजोर सिर सामान्य रूप (WHNF) में है। (एक 'हेड नॉर्मल फॉर्म' भी है, लेकिन हास्केल में इसका इस्तेमाल नहीं किया गया है।) WHNF में किसी चीज का पूरी तरह से मूल्यांकन करने से वह सामान्य रूप में किसी चीज को कम कर देता है ...

- विकीबुक्स हास्केल: आलस्य

(एक शब्द हेड नॉर्मल रूप में होता है अगर हेड पोजीशन 1 में कोई बीटा-रेडेक्स नहीं है । एक रेडेक्स एक हेड रेडेक्स है यदि यह केवल गैर-रेडेक्स 2 के लैम्ब्डा एब्स्ट्रैक्टर्स से पहले है ।) तो जब आप एक थन को बल देना शुरू करते हैं। आप WHNF में काम कर रहे हैं; जब बल के लिए अधिक थक्के नहीं बचे, तो आप सामान्य रूप में हों। एक और दिलचस्प बिंदु:

... अगर कुछ बिंदु पर हमें उपयोगकर्ता से प्रिंट करने की आवश्यकता होती है, तो हम इसे पूरी तरह से मूल्यांकन करने की आवश्यकता होगी ...

जिसका स्वाभाविक रूप से तात्पर्य यह है कि, वास्तव में, किसी भी IOकार्रवाई main को बल से किया जाता है , जो कि हास्केल कार्यक्रम वास्तव में, चीजें करते हैं, यह देखते हुए स्पष्ट होना चाहिए। किसी भी चीज़ को परिभाषित अनुक्रम से गुजरने की ज़रूरत mainहै जो सामान्य रूप में होनी चाहिए और इसलिए यह सख्त मूल्यांकन के अधीन है।

सीए मैककैन ने इसे टिप्पणियों में सही पाया, हालांकि: केवल एक चीज जो विशेष mainहै कि mainइसे विशेष के रूप में परिभाषित किया गया है; रचनाकार पर पैटर्न का मिलान IOमोनाड द्वारा लगाए गए अनुक्रम को सुनिश्चित करने के लिए पर्याप्त है । उस संबंध में केवल seqऔर पैटर्न-मिलान मौलिक हैं।


4
वास्तव में, "अगर किसी बिंदु पर हमें उपयोगकर्ता को प्रिंट करने की आवश्यकता होती है, तो हम इसे पूरी तरह से मूल्यांकन करने की आवश्यकता होगी" पूरी तरह से सही नहीं है। यह उतना ही सख्त है जितना Showकि मूल्य मुद्रित होना।
नॉमिनोलो

10

हास्केल AFAIK एक शुद्ध आलसी भाषा नहीं है, बल्कि एक गैर-सख्त भाषा है। इसका मतलब यह है कि यह आवश्यक रूप से अंतिम समय पर शर्तों का मूल्यांकन नहीं करता है।

हैज़ेल के "आलसीपन" के मॉडल का एक अच्छा स्रोत यहां पाया जा सकता है: http://en.wikibooks.org/wiki/Haskell/Laziness

मूल रूप से, एक थन और कमजोर हेडर सामान्य रूप WHNF के बीच अंतर को समझना महत्वपूर्ण है।

मेरी समझ यह है कि हेकेल अनिवार्य भाषाओं की तुलना में पीछे की ओर से गणना खींचती है। इसका मतलब यह है कि "seq" और बैंग पैटर्न की अनुपस्थिति में, यह अंततः कुछ प्रकार का दुष्प्रभाव होगा जो एक थंक के मूल्यांकन को मजबूर करता है, जो बदले में पूर्व मूल्यांकन का कारण हो सकता है (सच्ची आलसीता)।

जैसा कि यह एक भयानक अंतरिक्ष रिसाव को जन्म देगा, संकलक तब पता लगाता है कि अंतरिक्ष को बचाने के लिए समय से पहले थ्रकों का मूल्यांकन कैसे और कब करना है। प्रोग्रामर तब सख्ती से एनोटेशन (en.wikibooks.org/wiki/Haskell/Strictness, www.haskell.org/haskellwiki/Performance/Strictness) देकर इस प्रक्रिया का समर्थन कर सकता है ताकि नेस्टेड थ्रो के रूप में अंतरिक्ष उपयोग को कम किया जा सके।

मैं हैसेल के परिचालन शब्दार्थ में विशेषज्ञ नहीं हूं, इसलिए मैं लिंक को केवल एक संसाधन के रूप में छोड़ दूंगा।

कुछ और संसाधन:

http://www.haskell.org/haskellwiki/Performance/Laziness

http://www.haskell.org/haskellwiki/Haskell/Lazy_Evaluation


6

आलसी का मतलब कुछ भी नहीं है। जब भी आपका प्रोग्राम पैटर्न एक caseअभिव्यक्ति से मेल खाता है , तो यह कुछ का मूल्यांकन करता है - वैसे भी पर्याप्त। अन्यथा यह पता नहीं चल सकता है कि किस RHS का उपयोग करना है। अपने कोड में किसी भी मामले के भाव नहीं देखें? चिंता न करें, कंपाइलर आपके कोड को हास्केल के एक स्ट्रिप्ड डाउन फॉर्म में ट्रांसलेट कर रहा है जहां वे उपयोग करने से बचना मुश्किल है।

एक शुरुआत के लिए, अंगूठे का एक मूल नियम letआलसी है, caseकम आलसी है।


2
ध्यान दें कि caseहमेशा GHC कोर में मूल्यांकन करने पर मजबूर करता है, लेकिन यह नियमित हास्केल में ऐसा नहीं करता है। उदाहरण के लिए, प्रयास करें case undefined of _ -> 42
हमार

2
caseजीएचसी कोर डब्ल्यूएचएनएफ के लिए अपने तर्क का मूल्यांकन करता है, जबकि caseहास्केल अपने तर्क का मूल्यांकन उतना ही करता है जितना उपयुक्त शाखा का चयन करने के लिए आवश्यक है। हमार के उदाहरण में case 1:undefined of x:y:z -> 42, यह बिल्कुल नहीं है, लेकिन यह WHNF की तुलना में अधिक गहराई से मूल्यांकन करता है।
मैक्स

और यह भी case something of (y,x) -> (x,y)मूल्यांकन की जरूरत नहीं है something। यह सभी उत्पाद प्रकारों के लिए सही है।
इंगो सेप

@ इंगो - यह गलत है। somethingटपल निर्माता तक पहुंचने के लिए WHNF को मूल्यांकन करने की आवश्यकता होगी।
जॉन एल

जॉन - क्यों? हम जानते हैं कि यह एक तुच्छ होना चाहिए, इसलिए इसका मूल्यांकन करने की बात कहाँ है? यदि x और y ऐसे कोड के लिए बाध्य हैं जो टुपल का मूल्यांकन करते हैं और उपयुक्त स्लॉट को निकालने के लिए बाध्य हैं, तो क्या उन्हें कभी खुद की जरूरत है।
इंगो सेप

4

यह कर्म के लिए लक्षित पूर्ण उत्तर नहीं है, लेकिन सिर्फ पहेली का एक टुकड़ा है - इस हद तक कि यह शब्दार्थ के बारे में है, ध्यान रखें कि कई मूल्यांकन रणनीतियाँ हैं जो एक ही शब्दार्थ प्रदान करती हैं । यहाँ एक अच्छा उदाहरण है - और परियोजना यह भी बताती है कि हम आम तौर पर हास्केल शब्दार्थ के बारे में कैसे सोचते हैं - एगर हास्केल परियोजना थी, जो समान शब्दार्थ को बनाए रखते हुए मूल्यांकन रणनीतियों को बदल देती है : http://csg.csail.mit.edu/ पब / haskell.html


2

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

निश्चित रूप से वास्तविक भाषा में ऐसा नहीं होता है। कंपाइलर हास्केल को बहुत परिष्कृत तरीके से कोर में परिवर्तित करता है, जिससे कई चीजें संभवतः आलसी हो सकती हैं और कुछ भी जो हमेशा आलसी की जरूरत होती है। इसके अतिरिक्त, अनबॉक्स्ड मान और ट्यूपल हैं जो हमेशा सख्त होते हैं।

यदि आप किसी फ़ंक्शन को हाथ से मूल्यांकन करने का प्रयास करते हैं, तो आप मूल रूप से सोच सकते हैं:

  • वापसी के सबसे बाहरी निर्माता का मूल्यांकन करने का प्रयास करें।
  • यदि परिणाम प्राप्त करने के लिए किसी और चीज की आवश्यकता होती है (लेकिन केवल अगर यह वास्तव में आवश्यक है) भी मूल्यांकन किया जाएगा। आदेश मायने नहीं रखता।
  • IO के मामले में आपको पहले से लेकर अंतिम तक के सभी कथनों के परिणामों का मूल्यांकन करना होगा। यह थोड़ा अधिक जटिल है, क्योंकि आईओ सनक एक विशिष्ट क्रम में मूल्यांकन को मजबूर करने के लिए कुछ तरकीबें करता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.