2012-03-29 15 views
14

मैं वर्तमान में SICP के माध्यम से हास्केल के साथ काम कर रहा हूं। व्यायाम 1.15 पूछता है कि फ़ंक्शन को कितनी बार बुलाया जाता है। विचार शायद यह है कि आपको प्रतिस्थापन विधि का उपयोग करना चाहिए, लेकिन मैं जानना चाहता हूं कि कोड में ऐसा कैसे करें।फ़ंक्शन को कितनी बार बुलाया गया था, एफपी तरीका

एक अनिवार्य भाषा में कोई वैश्विक वैरिएबल रख सकता है और हर बार फ़ंक्शन कहलाता है। लेकिन आप इसके बारे में हास्केल (या शुद्ध कार्यात्मक तरीके) में कैसे जाएंगे?

+0

अगर केवल डीबगिंग के लिए, आप 'Debug.Trace' के' trace' फ़ंक्शन का उपयोग कर सकते हैं। यह संदर्भित पारदर्शिता तोड़ता है, लेकिन यदि आप डिबगिंग या अन्वेषण कर रहे हैं तो यह ठीक होना चाहिए। – GManNickG

+3

अहम, मुझे लगता है कि एसआईसीपी वास्तव में गिनती को 0 या 1 होने की उम्मीद कर रहा है - जिस्ट "का मूल्यांकन किया गया है या नहीं?"। एक समारोह को कितनी बार बुलाया जाता है यह गिनने का एक पूरी तरह कार्यात्मक तरीका नहीं है। नीचे दिए गए उत्तरों अच्छे monadic "समाधान" प्रदान करते हैं, लेकिन वे संबंधित monad के भीतर "रन" होने के लिए समारोह में निर्भर करते हैं। यह एक महत्वपूर्ण नाइट-पिक है - वे सामान्य कार्यों की गणना नहीं करते हैं। –

उत्तर

18

इसे पूर्ण करने के Writer इकाई का उपयोग कर सकते हैं, बशर्ते कि प्रश्न में समारोह के लिए कॉल के सभी एक do ब्लॉक में एक साथ बांटा जा सकता है:

import Control.Monad.Writer 

myFunc :: Int -> Int -> Writer (Sum Int) Int 
myFunc a b = tell (Sum 1) >> return (a + b) 

callMyFunc :: ((Int, Int, Int), Sum Int) 
callMyFunc = runWriter $ do a <- myFunc 2 3 
          b <- myFunc 8 7 
          c <- myFunc 3 5 
          return (a, b, c) 

main = putStrLn $ 
    "myFunc was called " 
     ++ show (getSum $ snd callMyFunc) 
     ++ " times and produced " 
     ++ show (fst callMyFunc) 

कौन सा आउटपुट:

myFunc was called 3 times and produced (5,15,8) 
6

ऐसा लगता है कि आपको किसी प्रकार का काउंटर होना चाहिए चाहे आप एक कार्यात्मक या गैर-कार्यात्मक तरीके से जाएं या नहीं। हास्केल में, आप राज्य का ट्रैक रखने के State इकाई इस्तेमाल कर सकते हैं:

import Control.Monad.State 

someFunc x = do 
    num <- get 
    put (num + 1) 
    return $ x * x 

runSomeFuncs = do 
    someFunc 1 
    someFunc 2 
    someFunc 3 

main = do 
    let (res, state) = runState runSomeFuncs 0 
    putStrLn ("result: " ++ (show res)) 
    putStrLn ("# of calls: " ++ show state) 

यहाँ, आप कितनी बार someFunc लिए बुला लिया गया का ट्रैक रखने के लिए चाहते हैं, तो हम राज्य के रूप में में एक पूर्णांक गुजरती हैं और बढ़ा देते पूर्णांक हर बार फ़ंक्शन का उपयोग करके बुलाया जाता है:

num <- get 
put (num + 1) 

और उसके बाद 1 और यह put वापस द्वारा यह बढ़ा देते। आप इस स्क्रिप्ट चलाते हैं, तो इसे प्रिंट चाहिए

result: 9 
# of calls: 3 
+14

या 'get'ting और' put'ting के बजाय 'संशोधित करें (+ 1)'। – dave4420

+7

यहां 'राज्य' का उपयोग काउंटर पर भी निर्भर करता है, और एक अनावश्यक डेटा निर्भरता बनाता है (उदाहरण के लिए समानांतरता को सीमित करेगा)। आप 'मानदंड 'के साथ' मानदंड' के रूप में 'राइटर' का उपयोग कर सकते हैं, और फिर काउंटर को बढ़ाने के लिए 'बताएं (Sum 1) 'का उपयोग कर सकते हैं। यह अच्छी तरह से जोड़ की सहयोगीता का शोषण करता है, और एक ही राइटर गणना को कई बार कॉल करते समय सीएसई को भी अनुमति देता है। – Peaker

+0

@Peaker इसे विस्तृत करें और इसे उत्तर के रूप में पोस्ट करें। – dave4420

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