2016-06-15 9 views
14

नहीं होना चाहिए मेरे पास यह हास्केल कोड है जो जीएचसी के साथ संकलित और चलाया जाता है, एक लूप के साथ aborts का पता चला।हास्केल प्रोग्राम "लूप" के साथ बंद करता है लेकिन मुझे लगता है कि यह

data Foo = Foo() 
deriving (Eq,Show) 

type Foop = Foo -> ((),Foo) 

noOp :: Foop 
noOp st = ((),st) 

someOp :: Foop 
someOp [email protected](Foo x) = ((),st) 

(<+>) :: Foop -> Foop -> Foop 
(<+>) f g st = let ((_,st'),(_,st'')) = ((f st),(g st')) in ((),st'') 

main = print $ (noOp <+> someOp) $ Foo() 

मुझे लगता है कि यह नहीं होना चाहिए, और यहां कुछ संशोधन हैं। उनमें से प्रत्येक पाश दूर जाना बनाता है:

  • परिवर्तन data Foonewtype Foo-
  • परिवर्तन (noOp <+> someOp)(someOp <+> noOp)-
  • हटाने विखंडन @(Foo x)

इस GHC में एक बग है या यह मेरी कमी है मूल्यांकन प्रक्रिया को समझने के लिए?

उत्तर

8

यह एक बग नहीं है - आपको आलसी पैटर्न अर्थशास्त्र का एक मुश्किल कोना मिला है। मुझे एक सरल मामले को पेश करते हैं:

> data Id a = Id a 
> let Id a = undefined ; Id b = Id 3 in b 
3 
> let (Id a, Id b) = (undefined, Id 3) in b 
*** Exception: Prelude.undefined 

अंतर यह है कि पहले let

case undefined of 
    ~(Id a) -> case Id 3 of 
       ~(Id b) -> b 

के बराबर है, जबकि दूसरा है

case (undefined, Id 3) of 
    ~(Id a, Id b) -> b 

पहले undefined जब तक मूल्यांकन नहीं होगा a की मांग है (जो नहीं होता है)।

दोनों पैटर्न Id a और Id b के खिलाफ दूसरे इच्छा पैटर्न मैच के रूप में जल्द के रूप में या तो चर की मांग की है, इस प्रक्रिया में दोनों undefined और Id 3 मजबूर।

नोट इस समस्या के कारण, पैटर्न ~(K1 (K2 x) (K3 y)), ~(K1 ~(K2 x) (K3 y)), ~(K1 (K2 x) ~(K3 y)) और ~(K1 ~(K2 x) ~(K3 y)) अलग अर्थ विज्ञान है,।

अपने कोड को ठीक करने के लिए,

let (~(_,st'),~(_,st'')) = ((f st),(g st')) in ((),st'') 

या

let (_,st') = f st ; (_,st'') = g st' in ((),st'') 
+0

यह एक अपरिहार्य मैच का उपयोग करने के लिए पर्याप्त है: 'चलो ((_, सेंट'), ~ (_, st '')) = (f st, g st ') '। – leftaroundabout

+0

@ बाएंअराउंडबाउट 'पहली चीज' की मांग नहीं की जा रही है? 'चलो ... में ((), सेंट' ')'। इसके अलावा, सामान्य मामले में 'जी' गैर-सख्त हो सकता है। – chi

+0

धन्यवाद, वह अंतर्दृष्टिपूर्ण था। अब मेरे कोड में कोई 'अपरिभाषित' नहीं है और मैं अभी भी नहीं देखता कि यह क्यों लूप करता है। क्या आप उस पर कुछ प्रकाश भी डाल सकते हैं? –

12
  • प्रतिमान मिलान (_, _) मांगों (f st, g st') की WHNF प्रयास करें। आसान।
  • पैटर्न मिलान (_, (_,_))g st' के WHNF की मांग करता है। यहां समस्या है, क्योंकि g सख्त है, इसलिए इसे पहले डब्ल्यूएचएनएफ में st' की भी आवश्यकता है। रनटाइम st' पैटर्न ((_,st'), (_,_)) में पाता है, इसलिए इससे पहले यह वास्तव में st' में जा सकता है, इसे दोनों tuples में WHNF की आवश्यकता होती है। चूंकि g सख्त है, लेकिन पहले इसे st' ... और इसी तरह की आवश्यकता है।

आप एक आलसी अकाट्य पैटर्न

(<+>) f g st = let ((_,st'), ~(_,st'')) = (f st, g st') in ((),st'') 

तो समस्या दूर हो जाने के साथ g का परिणाम से मेल खाते हैं, क्योंकि इस इस प्रकार मूल्यांकन किया जाता है: (f st, g st') की

  • प्रतिमान मिलान (_, _) मांगों WHNF । आसान।
  • पैटर्न मिलान (_, ~(_,_)) समय के लिए और कुछ नहीं मांगता है।
  • पैटर्न मिलान ((_,st'), ~(_,_))f st के WHNF की मांग करता है। सौभाग्य से, हम इसे पूरा कर सकते हैं, क्योंकि st पैटर्न पर निर्भर नहीं है।
  • अब हम पैटर्न मिलान से संतुष्ट हैं, रनटाइम in ((),st'') के साथ पहले से ही आगे बढ़ सकता है। केवल इस बिंदु पर अचूक पैटर्न ~(_,st'') मजबूर है, लेकिन अब यह कोई समस्या नहीं है क्योंकि st' यहां उपलब्ध है, इसलिए यह केवल g कंप्यूटिंग की बात है।

फिक्स आप g गैर सख्त बनाने के लिए सभी राशि की कोशिश की है:

विखंडन @(Foo _)

कि बिना

निकालने के लिए, g वास्तव में देखने के लिए की जरूरत नहीं है इसके परिणाम कंकाल बनाने के लिए तर्क, यानी ट्यूपल मैच (_,st'') बिना पहले st' के डब्ल्यूएचएनएफ की आवश्यकता के बिना सफल हो सकता है।

परिवर्तन data Foonewtype Foo

को इस आशय है कि Foo निर्माता वास्तव में कार्यावधि में मौजूद नहीं है, है, तो वहाँ कुछ भी नहीं है कि पैटर्न [email protected](Foo _) मजबूर होना पड़ा है।

noOp <+> someOpsomeOp <+> noOp

करने के लिए परिवर्तन जैसा कि मैंने कहा, पाश ही के बारे में क्योंकि g सख्त है आता है। यदि आप अपनी स्थिति में f डालते हैं, जो सख्त नहीं है, तो कोई समस्या नहीं है।

+0

धन्यवाद, यह मुझे समझने में मेरी मदद करने के लिए एक अच्छा कदम हो सकता है :-) हालांकि मुझे अभी भी समझ में नहीं आ रहा है कि क्यों यह पहले नहीं हो सकता है कि बाएं टुपल को 'st''' प्राप्त करने के लिए क्यों और फिर सही टुपल प्राप्त करने के लिए 'st'''? मैं देख सकता हूं कि दाएं ट्यूपल को डब्ल्यूएचएनएफइंग के लिए बाएं ट्यूपल डब्ल्यूएचएनएफइंग की आवश्यकता है लेकिन मुझे बाएं ट्यूपल डब्ल्यूएचएनएफइंग के साथ समस्या नहीं दिखाई दे रही है। –

+0

आप पहले बाएं ट्यूपल डब्ल्यूएचएनएफ कर सकते हैं, लेकिन यह आपको 'st'' नहीं देता है। यह आपको केवल '(_, ~ st') 'देता है, जैसा कि यह था। – leftaroundabout

+0

विशिष्ट मामले में, '(_, st ') = f st = noOp st = ((), st)', तो 'st' = st = foo() 'जो' g' उपनाम की सख्तता को भी संतुष्ट करेगा 'someOp'। गणना करना संभव नहीं होना चाहिए? –

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