2012-06-15 19 views
36

मैं इस बारे में सोच रहा हूं, लेकिन मुझे इसके बारे में कुछ भी नहीं मिला है।seq फ़ंक्शन और सख्तता

seq फ़ंक्शन का उपयोग करते समय, यह वास्तव में काम कैसे करता है? हर जगह, यह सिर्फ यह समझाया गया है कि seq a ba का मूल्यांकन करता है, परिणाम को छोड़ देता है और b देता है।

लेकिन वास्तव में का क्या अर्थ है? सख्त मूल्यांकन में निम्न परिणाम होगा:

foo s t = seq q (bar q t) where 
     q = s*t 

मैं क्या मतलब है, q सख्ती से bar में इस्तेमाल किया जा रहा से पहले मूल्यांकन किया जाता है? और निम्नलिखित बराबर होगा:

foo s t = seq (s*t) (bar (s*t) t) 

मैं इसे इस समारोह की कार्यक्षमता पर एक छोटे से कठिन हो रही बारीकियों पाते हैं।

+7

यह सहायक हो सकता है: http://stackoverflow.com/questions/6872898/haskell-what-is-weak-head-normal-form "इसके अर्थशास्त्र यह है कि seq xy का अर्थ है कि जब भी y को कमजोर सिर के लिए मूल्यांकन किया जाता है फॉर्म, एक्स का भी कमजोर सिर सामान्य रूप में मूल्यांकन किया जाता है। " – shang

उत्तर

29

आप अकेले नहीं हैं। seq शायद कुछ अलग कारणों से, सही तरीके से उपयोग करने के लिए सबसे कठिन हास्केल कार्यों में से एक है। अपने पहले उदाहरण में:

foo s t = seq q (bar q t) where 
     q = s*t 

q से पहले bar q t मूल्यांकन किया जाता है मूल्यांकन किया जाता है। यदि bar q t का मूल्यांकन कभी नहीं किया जाता है, तो q या तो नहीं होगा। तो अगर आप

main = do 
    let val = foo 10 20 
    return() 

val के रूप में इस्तेमाल कभी नहीं किया है, यह मूल्यांकन नहीं किया जाएगा। तो q का मूल्यांकन नहीं किया जाएगा। आप के बजाय

main = print (foo 10 20) 

है, तो foo 10 20 का परिणाम है, (print द्वारा) मूल्यांकन किया जाता है fooq के भीतर ऐसा bar का परिणाम से पहले मूल्यांकन किया जाता है।

myseq x = seq x x 

शब्दार्थ, इसका मतलब है पहले दूसरी x मूल्यांकन किया जाता है पहले x मूल्यांकन किया जाएगा:

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

आपका दूसरा उदाहरण एक ही चीज़ हो सकता है या नहीं भी हो सकता है। यहां, अभिव्यक्ति s*t का मूल्यांकन bar के आउटपुट से पहले किया जाएगा, लेकिन यह के पहले पैरामीटर के समान s*t नहीं हो सकता है। यदि संकलक सामान्य उप-अभिव्यक्ति उन्मूलन करता है, तो यह दो समान अभिव्यक्तियों को आम कर सकता है। हालांकि, सीएसई कहां से जीएचसी काफी रूढ़िवादी हो सकता है, इसलिए आप इस पर भरोसा नहीं कर सकते हैं। यदि मैं bar q t = q*t को परिभाषित करता हूं तो यह सीएसई करता है और बार में उस मान का उपयोग करने से पहले s*t का मूल्यांकन करता है। यह अधिक जटिल अभिव्यक्तियों के लिए ऐसा नहीं कर सकता है।

आप यह भी जानना चाहेंगे कि सख्त मूल्यांकन क्या है।seq कमजोर सिर सामान्य रूप (डब्ल्यूएचएनएफ) के पहले तर्क का मूल्यांकन करता है, जो डेटा प्रकारों के लिए बाहरीतम कन्स्ट्रक्टर को अनपॅक करना है। इस पर विचार करें:

baz xs y = seq xs (map (*y) xs) 

xsmap की वजह से सूची होनी चाहिए। जब seq यह मूल्यांकन करता है, यह अनिवार्य रूप से

case xs of 
    [] -> map (*y) xs 
    (_:_) -> map (*y) xs 

में कोड बदल सकते हैं इसका मतलब यह है यह तय करेंगे यदि सूची खाली है या नहीं, तो दूसरा तर्क लौटने। ध्यान दें कि सूची मूल्यों में से कोई भी मूल्यांकन नहीं किया गया है। तो अगर आप ऐसा कर सकते हैं:

Prelude> seq [undefined] 4 
4 

लेकिन इस

Prelude> seq undefined 5 
*** Exception: Prelude.undefined 

जो भी डेटा प्रकार आप seq पहला तर्क के लिए उपयोग करते हैं, WHNF करने का मूल्यांकन अब तक निर्माता और आगे नहीं यह पता लगाने के लिए पर्याप्त नहीं होगा नहीं। जब तक डेटा प्रकार में ऐसे घटक नहीं होते हैं जिन्हें बैंग पैटर्न के साथ सख्त के रूप में चिह्नित किया जाता है। फिर सभी सख्त क्षेत्रों का मूल्यांकन डब्ल्यूएचएनएफ को भी किया जाएगा।

संपादित करें: (टिप्पणी में सुझाव के लिए डैनियल वैगनर के लिए धन्यवाद)

कार्यों के लिए, जब तक समारोह है, जिसका अर्थ है कि यह आवेदन के लिए तैयार है "एक लैम्ब्डा दिखा है" seq अभिव्यक्ति का मूल्यांकन करेंगे।

-- ok, lambda is outermost 
Prelude> seq (\x -> undefined) 'a' 
'a' 

-- not ok. Because of the inner seq, `undefined` must be evaluated before 
-- the lambda is showing 
Prelude> seq (seq undefined (\x -> x)) 'b' 
*** Exception: Prelude.undefined 

आप एक लैम्ब्डा एक (बिल्ट-इन) डेटा निर्माता के रूप में बाध्यकारी के बारे में सोच रहे हैं, तो seq कार्यों पर डेटा पर उपयोग के साथ पूरी तरह अनुरूप है: यहाँ कुछ उदाहरण का प्रदर्शन हो सकता है कि इसका क्या मतलब है।

इसके अलावा, "लैम्ब्डा बाध्यकारी" सभी प्रकार की फ़ंक्शन परिभाषाओं को कम करता है, चाहे लैम्ब्डा नोटेशन द्वारा परिभाषित किया गया हो या सामान्य कार्य के रूप में।

Controversy हास्केलविकि के सीक पृष्ठ के अनुभाग में कार्यों के संबंध में seq के कुछ परिणामों के बारे में कुछ नहीं है।

+3

बस इसे स्पष्ट करने के लिए: _when_ 'seq' कार्यों पर नो-ऑप होने के बारे में कोई विवाद नहीं है। यह वास्तव में एक नो-ऑप है जब फ़ंक्शन में "लैम्ब्डा दिखाना होता है", और नो-ऑप नहीं होता है जब लैम्ब्डा से पहले कुछ गणना की जानी चाहिए (और इसलिए आवेदन के लिए तैयार)। यह विवाद इस बात के बारे में है कि हमें ऑप्टिमाइज़ेशन डिज़ाइन करते समय 'seq' के उपयोग के बारे में सोचना चाहिए - क्योंकि 'seq' में हास्केल के अर्थशास्त्र में असहज स्थान है। –

+0

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

+0

आपका उत्तर बताता है कि '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' '' इसलिए '' '' sseq''' मौजूद है। https://wiki.haskell.org/Seq "हालांकि, यह मामला है कि बी का मूल्यांकन करना और फिर ए, फिर वापस लौटना बी पूरी तरह से वैध काम है; यह इस अस्पष्टता को रोकने के लिए था कि पीएससी का आविष्कार किया गया था, लेकिन यह दूसरा है कहानी। " –

4

आप seq के रूप में के बारे में सोच सकते हैं:

seq a b = case a of 
      _ -> b 

यह सिर सामान्य करने के लिए प्रपत्र (WHNF) a मूल्यांकन करने के बाद b के मूल्यांकन के साथ जारी रहेगा।

अगस्त के बाद संपादित करें टिप्पणी: यह case ... ofstrict, GHC Core one है, जो हमेशा इसके तर्क को मजबूर करता है।

+1

सिवाय इसके कि हास्केल 'ए' का मूल्यांकन नहीं करता है। – augustss

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