जब आप [1..1000000]
लिखते हैं, तो वास्तव में जीएचसी क्या करता है वह ऑब्जेक्ट बनाता है जिसमें 1
और 1000000
शामिल है जो बताता है कि ब्याज की सूची कैसे बनाएं; उस वस्तु को "थंक" कहा जाता है। सूची केवल केस जांच की पूर्ति के लिए जरूरी है; उदाहरण के लिए, आप लिख सकते हैं:
printList [] = putStrLn ""
printList (x:xs) = putStrLn (show x) >> printList xs
main = printList [1..1000000]
कौन इस तरह का मूल्यांकन करता है:
main
= { definition of main }
printList [1..1000000]
= { list syntax sugar }
printList (enumFromTo 1 1000000)
= { definition of printList }
case enumFromTo 1 1000000 of
[] -> putStrLn ""
x:xs -> putStrLn (show x) >> printList xs
= { we have a case, so must start evaluating enumFromTo;
I'm going to skip a few steps here involving unfolding
the definition of enumFromTo and doing some pattern
matching }
case 1 : enumFromTo 2 1000000 of
[] -> putStrLn ""
x:xs -> putStrLn (show x) >> printList xs
= { now we know which pattern to choose }
putStrLn (show 1) >> printList (enumFromTo 2 1000000)
तो फिर तुम पाते हैं कि 1
कंसोल के लिए मुद्रित किया गया था, और हम enumFromTo 2 1000000
साथ शीर्ष के निकट से शुरुआत करते हैं, enumFromTo 1 1000000
के बजाय। आखिरकार, आपको सभी संख्याओं को मुद्रित किया जाएगा और
printList (enumFromTo 1000000 1000000)
= { definition of printList }
case enumFromTo 1000000 1000000 of
[] -> putStrLn ""
x:xs -> putStrLn (show x) >> printList xs
= { skipping steps again to evaluate enumFromTo }
case [] of
[] -> putStrLn ""
x:xs -> putStrLn (show x) >> printList xs
= { now we know which pattern to pick }
putStrLn ""
का मूल्यांकन करने के लिए समय आएगा और मूल्यांकन समाप्त हो जाएगा।
कारण हमें धाराओं की आवश्यकता है थोड़ा सूक्ष्म है। मूल पेपर, Stream fusion: From lists to streams to nothing at all, शायद सबसे पूर्ण स्पष्टीकरण है।
concatMap foo . map bar . filter pred . break isSpecial
... यह तो स्पष्ट है कि कैसे संकलक सभी मध्यवर्ती सूचियों दूर संकलित करने के लिए प्राप्त करने के लिए नहीं है: लघु संस्करण है कि आप एक लंबे पाइप लाइन है जब है। आप देख सकते हैं कि हम सूचियों के बारे में सोच सकते हैं कि "राज्य" का पुनरावृत्ति किया जा रहा है, और यह कि इनमें से प्रत्येक कार्य, सूची की खोज करने के बजाय, प्रत्येक पुनरावृत्ति पर राज्य को संशोधित करने के तरीके को बदल रहा है। Stream
प्रकार यह स्पष्ट करने के लिए प्रयास करता है, और परिणाम स्ट्रीम संलयन है।यह इस प्रकार से दिखाई देता है: हम पहली धारा संस्करणों में इन सभी कार्यों कन्वर्ट:
(toList . S.concatMap foo . fromList) .
(toList . S.map bar . fromList) .
(toList . S.filter pred . fromList) .
(toList . S.break isSpecial . fromList)
तो देख सकते हैं कि हम हमेशा का सफाया कर सकते हैं fromList . toList
:
toList . S.concatMap foo . S.map bar . S.filter pred . S.break . fromList
... और फिर जादू क्योंकि श्रृंखला S.concatMap foo . S.map bar . S.filter pred . S.break
होता है आंतरिक रूप से निर्माण करके और फिर तुरंत वास्तविक सूचियों को नष्ट करने के बजाय इसे एक इटेटरेटर बनाता है।
एचएम, आप क्या कहते हैं कि धाराओं में स्थिर समय संलग्न/प्रीपेड होता है? कार्यान्वयन से, ऐसा लगता है कि एन तत्वों को जोड़ने के परिणामस्वरूप 'चरण' फ़ंक्शन होगा जो ओ (एन) बीजों को 'या तो' कन्स्ट्रक्टर नेस्टेड ओ (एन) गहराई से पार करना होगा। प्रलेखन इस निरंतर समय का दावा कहीं भी नहीं करता है जिसे मैं देख सकता हूं। –
@DanielWagner: पर्याप्त मेला। किसी भी मामले में, यह धाराओं को सूचियों की तरह और भी बनाता है। – Clinton
दरअसल, यह उन्हें बहुत अलग बनाता है। सूचियों के साथ, विपक्ष मुक्त है, और आप पहली सूची की लंबाई के आधार पर स्नोक और concatenate के लिए भुगतान करते हैं; तुलनात्मक रूप से, आप धाराओं के पेड़ की गहराई के लिए भुगतान करते हैं, और जिन चीजों को संयोजित किया जा रहा है, उनके आकार अप्रासंगिक हैं। लेकिन वह अंतर नहीं है जो धाराओं को महत्वपूर्ण बनाता है। –