2011-06-15 14 views
8

मैं Haskell Wiki पर हास्केल निम्नलिखित अभिव्यक्ति सीख रहा हूँ और मैं वास्तव में मुझे हैरान:आत्म संदर्भ में कार्य

fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 

मैं काफी समझ नहीं क्यों यह काम करता है।

यदि मैं मानक करीइंग तर्क लागू करता हूं (zipWith (+)) एक फ़ंक्शन एक तर्क के रूप में सूची लेता है और बदले में, एक और फ़ंक्शन देता है जो तर्क के रूप में एक और सूची लेता है, और एक सूची (zipWith::(a -> b -> c) -> [a] -> [b] -> [c]) देता है। तो, fibs एक सूची के लिए एक संदर्भ है (जिनका अब तक मूल्यांकन नहीं किया गया) और (tail fibs) ही (unevaluated) सूची की पूंछ है। जब हम मूल्यांकन करने के लिए (take 10 fibs) की कोशिश, पहले दो तत्वों 0 और 1 करने के लिए बाध्य कर रहे हैं। दूसरे शब्दों में fibs==[0,1,?,?...] और (tail fibs)==[1,?,?,?]। पहले जोड़े को पूरा करने के बाद fibs[0,1,0+1,?,..] बन जाता है। इसी प्रकार, दूसरे जोड़े के बाद हमें [0,1,0+1,1+(0+1),?,?..]

  • क्या मेरा तर्क सही है?
  • वहाँ एक सरल तरीका यह समझाने के लिए है? (जो लोग जानते हैं कि हास्केल संकलक इस कोड के साथ करता है? से किसी भी अंतर्दृष्टि) (लिंक और संदर्भ स्वागत कर रहे हैं)
  • यह सच है कि कोड के इस प्रकार केवल आलसी मूल्यांकन की वजह से काम करता है?
  • क्या मूल्यांकन हो सकता है जब मैं fibs !! 4 करते हैं?
  • क्या यह कोड मानता है कि ज़िप प्रक्रियाओं को पहले आखिरी बार संसाधित करता है? (मुझे लगता है कि यह नहीं होना चाहिए, लेकिन मुझे समझ में नहीं आता क्यों नहीं)

EDIT2: मुझे अभी उपरोक्त प्रश्न पूछा गया और here का उत्तर दिया गया। मुझे खेद है अगर मैंने किसी के समय बर्बाद कर दिया।

संपादित करें:

filterAbort :: (a -> Bool) -> [a] -> [a] 
filterAbort p (x:xs) = if p x then x : filterAbort p xs else [] 

main :: Int 
main = primelist !! 10000 
     where primelist = 2 : 3 : 5 : [ x | x <- [7..], odd x, all (\y -> x `mod` y /= 0) (filterAbort (<= (ceiling (sqrt (fromIntegral x)))) primelist) ] 

ध्यान दें कि all (\y -> x mod y /= 0)... कैसे एक्स की चर्चा करते हुए यहां अनंत प्रत्यावर्तन कारण नहीं हो सकता: यहाँ एक और अधिक कठिन मामला (: Project Euler forums स्रोत) को समझने के लिए किया जाता है?

+0

यह सही लगता है। यह मेरे लिए भी आसान लगता है - जैसे ही आप हास्केल के साथ काम करते हैं, आपका दिमाग इन पैटर्न को चुनना शुरू कर देगा और यह आपके लिए भी आसान लगेगा। अच्छी शुरुआत। – luqui

+2

सबसे पहले, 'फ़िल्टरअबोर्ट'' टेकवॉली 'जैसा ही है। दूसरा, आप '[7,9 ..]' लिखकर भी संख्याओं से बच सकते हैं। तीसरा, यदि आप '5,7 ..]' का उपयोग करते हैं तो आपकी प्रारंभिक सूची में '5' होने की कोई आवश्यकता नहीं है। और आखिरकार, यह काम करने का कारण गहरा है। ऐसा इसलिए है क्योंकि प्रत्येक प्रधान 'पी' के लिए 'p^2' से पहले एक और प्राइम है। Lindemann (पी और 2 पी के बीच एक प्रधान) द्वारा एक प्रमेय का एक मामूली परिणाम है। – augustss

+0

धन्यवाद, अगस्त। ऑप्टिमाइज़ेशन और क्लीन अप आपको समझ में आता है। समाप्ति के लिए, क्या आप विस्तारित कर सकते हैं? 'X \ 'में बाध्य है' (\ y -> x mod y/= 0)'? मुझे संदेह है कि मेरी गलती यह सोच रही है कि यह एक अनंत सूची के लिए बाध्य है। यदि यह केवल एक मान के लिए बाध्य है (कहें, '7') तो कोई समस्या नहीं है। क्या आप पुष्टि कर सकते हैं? –

उत्तर

15

मैं तुम्हारे लिए मूल्यांकन का पता लगाने जाएगा:

साथ
> fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 

:

> zipWith f (a:as) (b:bs) = f a b : zipWith f as bs 
> zipWith _ _  _  = [] 

> tail (_:xs)    = xs 
> tail []     = error "tail" 

तो:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 
↪ fibs = 0 : 1 : ((+) 0 1 : zipWith (+) (tail fibs) (tail (tail fibs))) 
↪ fibs = 0 : 1 : 1 : ((+) 1 1 : zipWith (+) (tail (tail fibs)) (taii (tail (tail fibs)))))  
↪ fibs = 0 : 1 : 1 : 2 : ((+) 1 2 : zipWith (+) (tail (tail (tail fibs))) (tail (taii (tail (tail fibs)))))) 
↪ fibs = 0 : 1 : 1 : 2 : 3 : ((+) 2 3 : zipWith (+) (tail (tail (tail (tail fibs)))) (tail (tail (taii (tail (tail fibs))))))) 

आदि तो अगर आप इस संरचना में सूचकांक, यह इंडेक्स मिलने तक फाइबर के प्रत्येक चरण का मूल्यांकन किया जाना चाहिए।

क्यों इस कुशल है? एक शब्द: साझाकरण

fibs की गणना की जाती है, यह ढेर में बढ़ती है, जो रिकॉर्डिंग मान कंप्यूटर है। fibs के बाद के संदर्भों में fibs के लिए पहले के गणना किए गए मानों का पुन: उपयोग करना होगा। नि: शुल्क यादें!

ढेर में यह साझाकरण कैसा दिखता है?

enter image description here

आप सूची के अंत पर वस्तु के लिए पूछने के रूप में, हास्केल अगले मूल्य की गणना करता है, यह रिकॉर्ड करता है, और कहा कि एक नोड नीचे आत्म संदर्भ ले जाता है।

तथ्य यह है कि यह समाप्त होता है आलस्य पर महत्वपूर्ण रूप से निर्भर करता है।

+0

धन्यवाद, डॉन। मैं अभी भी थोड़ा अस्पष्ट हूं कि हास्केल कैसे जानता है कि अगले तत्व को प्राप्त करने के लिए इसे फाइब्स को कॉल करने की आवश्यकता है, और यदि फाइब्स वास्तव में एक सूची है तो इसका मतलब क्या है "फाइब्स को कॉल करें"। मैं चारों ओर देख रहा था, और मुझे एक [समान प्रश्न] मिला (http://stackoverflow.com/questions/3887201/funky-haskell-lazy-list-implicit-recursion), लेकिन मुझे अभी भी यकीन नहीं है कि बीच क्या अंतर है सूची में '1' नोड और 'fibs ...' नोड Haskell संकलक के लिए। –

+1

आप 'फाइब्स' के बारे में सोच सकते हैं केवल एक सूचक के रूप में। इसलिए प्रत्येक बार जब आप 'fibs' का संदर्भ लेते हैं तो यह मान को देखता है। वह मान एक सूची होता है। –

+0

आह! ये एक अच्छा बिंदु है। मुझे अपना प्रश्न सही करना चाहिए। नोटेशन '0: 1: ज़िप ... क्या उत्पादन करता है? यह एक सूची के रूप में शुरू होता है, जिसे मैं समझता हूं। लेकिन फिर यह सूची में एक नोड हो जाता है जो एक फंक्शन कॉल है? या फंक्शन कॉल के रूप में सूची में सभी नोड्स के बारे में सोचना बेहतर है? अर्थात। 'पहचान x = x' कहें, तो' fib = (पहचान 0) :(पहचान 1) :(ज़िप ... ... '। मैं इस मामले संकलक * सभी * कोशिकाओं का मूल्यांकन करता हूं, लेकिन आखिरी वाला एक फ़ंक्शन कॉल के रूप में समाप्त होता है जो एक सूची देता है? और '(ज़िप ... ... '' fibs' सूची को इंगित करने के लिए होता है। सही? –