2010-07-17 12 views
7

में "सभी" का प्रदर्शन मुझे हैकेल का लगभग कोई ज्ञान नहीं मिला और कुछ परियोजना यूलर समस्याओं को हल करने का प्रयास किया। Number 5 सुलझाने जब मैं (1..10 के लिए) इस समाधान लिखाहैकेल

--Check if n can be divided by 1..max 
canDivAll :: Integer -> Integer -> Bool 
canDivAll max n = all (\x -> n `mod` x == 0) [1..max] 

main = print $ head $ filter (canDivAll 10) [1..] 

अब मुझे पता चला, कि all इस तरह कार्यान्वित किया जाता है:

all p   = and . map p 

नहीं इसका मतलब, शर्त है है हर तत्व के लिए जाँच की? क्या इस स्थिति के पहले झूठे परिणाम पर तोड़ना ज्यादा तेज़ नहीं होगा? इससे उपरोक्त कोड को निष्पादित किया जाएगा।

धन्यवाद

उत्तर

20

and ही शॉर्ट सर्किट है और के बाद से दोनों map और all मूल्यांकन आलसी है, आप केवल जरूरत के रूप में कई तत्व मिल जाएगा - नहीं और अधिक।

आप एक GHCi सत्र के साथ यह सुनिश्चित कर सकता:

Prelude Debug.Trace> and [(trace "first" True), (trace "second" True)] 
first 
second 
True 
Prelude Debug.Trace> and [(trace "first" False), (trace "second" False)] 
first 
False 
1

आप यह सोचते हैं कर रहे हैं कि and शॉर्ट सर्किट नहीं है। and पहले false परिणाम पर निष्पादन को रोक देगा, इसलिए यह "तेज" है जैसा कि कोई उम्मीद कर सकता है।

+3

मुझे नहीं लगता कि उसकी समस्या वह एहसास नहीं था कि कि 'and' शॉर्ट सर्किट, बल्कि यह है कि उसने सोचा कि' नक्शा है 'और 'यहां तक ​​कि चलने से पहले पूरी सूची में जायेगा (जैसा कि उत्सुक भाषाओं में व्यवहार होगा) क्योंकि वह आलसी मूल्यांकन के बारे में नहीं समझता/जानता है। – sepp2k

4

mapand निष्पादन से पहले अपने सभी तर्कों का मूल्यांकन नहीं करता है। और and संक्षिप्त सर्किट है।

ध्यान दें कि जीएचसी all में वास्तव में इस तरह परिभाषित नहीं किया गया है।

-- | Applied to a predicate and a list, 'all' determines if all elements 
-- of the list satisfy the predicate. 
all      :: (a -> Bool) -> [a] -> Bool 
#ifdef USE_REPORT_PRELUDE 
all p     = and . map p 
#else 
all _ []  = True 
all p (x:xs) = p x && all p xs 
{-# RULES 
"all/build"  forall p (g::forall b.(a->b->b)->b->b) . 
       all p (build g) = g ((&&) . p) True 
#-} 
#endif 

हम उस all p (x:xs) = p x && all p xs, तो जब भी p x गलत है, मूल्यांकन बंद हो जाएगा देखते हैं।

इसके अलावा, वहाँ एक सरलीकरण नियम all/build, जो प्रभावी रूप से बदल देती है अपने एक सरल में all p [1..max] असफल फास्ट पाश * है, इसलिए मुझे नहीं लगता कि आप all को संशोधित करने से ज्यादा सुधार कर सकते हैं।


*। सरलीकृत कोड दिखना चाहिए:

eftIntFB c n x0 y | x0 ># y = n   
        | otherwise = go x0 
       where 
        go x = I# x `c` if x ==# y then n else go (x +# 1#) 

eftIntFB ((&&) . p) True 1# max# 

4

इस मिश्रित अनुकूलन के लिए एक अच्छा कार्यक्रम है, के रूप में अपने सभी छोरों फ्यूज़ होने वाले combinators के रूप में व्यक्त कर रहे हैं। इस प्रकार आप इसका उपयोग कर लिख सकते हैं, उदा। डेटा। वेक्टर, और सूचियों के मुकाबले बेहतर प्रदर्शन प्राप्त करें।

एन से = 20, सूचियों से अपने कार्यक्रम में के रूप में:

  • 52.484s

इसके अलावा, rem बजाय mod का उपयोग करें।

  • 15।712s

कहाँ सूची कार्यों वेक्टर संचालन बन:

import qualified Data.Vector.Unboxed as V 

canDivAll :: Int -> Int -> Bool 
canDivAll max n = V.all (\x -> n `rem` x == 0) (V.enumFromN 1 max) 

main = print . V.head $ V.filter (canDivAll 20) $ V.unfoldr (\a -> Just (a, a+1)) 1