तो मैं आलसी उत्पन्न करने के तरीके पर काम कर रहा था, और मैं इन तीन परिभाषाओं के साथ आया, जो सभी समान तरीके से काम करते हैं - सिर्फ यह जांचते हैं कि प्रत्येक नए पूर्णांक में पिछले सभी के बीच एक कारक है अभाज्य संख्या:हास्केल शैली/दक्षता
primes1 :: [Integer]
primes1 = mkPrimes id [2..]
where mkPrimes f (x:xs) =
if f (const True) x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) xs
else
mkPrimes f xs
primes2 :: [Integer]
primes2 = mkPrimes id (const True) [2..]
where mkPrimes f f_ (x:xs) =
if f_ x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) (f $ g $ const True) xs
else
mkPrimes f f_ xs
primes3 :: [Integer]
primes3 = mkPrimes [] [2..]
where mkPrimes ps (x:xs) =
if all (\p -> x `mod` p > 0) ps
then
x : mkPrimes (ps ++ [x]) xs
else
mkPrimes ps xs
तो मुझे लगता है primes2
, primes1
की तुलना में थोड़ा तेजी से किया जाना चाहिए, क्योंकि यह हर पूर्णांक (जो मुझे लगता है कि के लिए f_ = f (const True)
recomputing अभाज्य संख्या की संख्या के आदेश पर काम की आवश्यकता है से बचा जाता है हम अब तक पाया गया है), और जब हम एन्क करते हैं तो केवल अपडेट होते हैं एक नया प्रधान काउंटर।
बस अवैज्ञानिक परीक्षण से (GHCi में take 1000
चल) यह primes3
रन तेजी से primes2
से की तरह लगता है।
मैं इस से एक सबक लग सकते हैं और मानते हैं कि अगर मैं एक सरणी पर एक आपरेशन के रूप में एक समारोह का प्रतिनिधित्व कर सकते हैं, कि मैं यह दक्षता के लिए बाद ढंग से लागू करना चाहिए, या वहाँ कुछ किसी और यहाँ पर जा रहा है ?
(जैसा कि मुझे यकीन है कि अब तक आप जानते हैं) 'primes3' में' कॉलिंग 'सभी' एक विशाल ओवरकिल है - केवल 'x' के' sqrt' से ऊपर नहीं है केवल प्राइम लेना पर्याप्त है - इस प्रकार एक ही प्राइम सूची का उपयोग किया जा सकता है जो बनाया जा रहा है - फ़ंक्शन सरल फ़िल्टर बन जाता है: 'primes4 = 2: फ़िल्टर (\ x-> सभी ((/ = 0)। (rem x)) $ takeWhile ((<= x)। (^ 2)) primes4) [3,5 ..] ',' ओ 'एन (1.45)' अनुभवजन्य रूप से, 'एन' प्राइम उत्पादित' में चल रहा है - * आपके प्रश्न में सभी तीन * संस्करण वर्गबद्ध दिखते हैं - इससे कोई फर्क नहीं पड़ता कि आप अपने कार्यों को कैसे बनाते हैं 'sqrt x' के नीचे केवल उन सभी के बजाय * सभी * प्राइम्स द्वारा परीक्षण करें। –