2012-12-01 34 views
7

में एक गणना के रनटाइम को बाउंड करें, मैं हास्केल में एक गेम एआई लिख रहा हूं, और मैं एक निश्चित समय के लिए खेल राज्य पेड़ खोजना चाहता हूं (यानी मैं हमेशा एआई को 3 सेकंड लेने के लिए चाहता हूं क्या कदम उठाने का निर्णय)हैकेल

मैं इसे हास्केल जैसी शुद्ध भाषा में कैसे कर सकता हूं? मुझे उम्मीद है कि मुझे धागे में कुछ डाइविंग करने की ज़रूरत होगी और इस तरह मैं जितना कर सकता हूं उतना कम करना पसंद करूंगा।

+0

[टाइमआउट] (http://www.haskell.org/hoogle/?hoogle=timeout) का उपयोग करें। अंतर्दृष्टि के लिए – leftaroundabout

उत्तर

5

एक विचार: timeout (@MathematicalOrchid ने सुझाव दिया) परिवर्तनशील चर के साथ SafeSemaphore से मध्यवर्ती मूल्यों हर बार अपनी प्रक्रिया एक आंशिक परिणाम की गणना करता है स्टोर करने के लिए संयुक्त करें:

import Control.Monad 
import Control.Concurrent.MSampleVar 
import System.Timeout 

fac :: Integer -> Integer 
fac 0 = 1 
fac n = n * fac (n - 1) 

tmo :: Int -> ((a -> IO()) -> IO()) -> IO (Maybe a) 
tmo ms f = do 
    mvar <- newSV Nothing 
    timeout ms (f (writeSV mvar . (Just $!))) 
    readSV mvar 

longComp :: (Integer -> IO()) -> IO() 
longComp save = let loop n = save (fac n) >> loop (n + 1) 
       in loop 0 

main :: IO() 
main = tmo 10000 longComp >>= print 

समारोह tmo के लिए पारित किया अपना पहला तर्क के रूप में हो जाता है एक IO क्रिया जो वह मध्यवर्ती परिणामों को सहेजने के लिए उपयोग कर सकती है। यदि यह समय-समय पर हो जाता है, तो अंतिम सहेजा गया परिणाम वापस कर दिया जाता है। परिणाम डब्ल्यूएचएनएफ में परिवर्तित हो जाता है ताकि वास्तविक गणना उस धागे में होती है जो नतीजे को बचाती है, न कि उस प्रक्रिया में जो tmo से वापस आती है।

इस संस्करण में, tmo पर फ़ंक्शन को आउटपुट को सहेजना है, यह इसे वापस नहीं कर सकता है। लेकिन इसे संशोधित करना आसान होगा ताकि यह हस्ताक्षर (a -> IO()) -> IO a होगा।

यदि आप चीजों को और अधिक शुद्ध रखना चाहते हैं तो मैं अपना खुद का मोनड बनाने का सुझाव दूंगा जो इस विचार को IO आउट किए बिना इस विचार को समाहित करता है।


अद्यतन: ध्यान दें कि:

कोई गारंटी नहीं कि अपवाद तुरंत हालांकि क्रम सुनिश्चित करना है कि मनमाने ढंग से देरी नहीं होती है का प्रयास करेंगे वितरित किया जाएगा, नहीं है। जीएचसी में, एक अपवाद केवल तब उठाया जा सकता है जब कोई थ्रेड सुरक्षित बिंदु तक पहुंचता है, जहां एक सुरक्षित बिंदु है जहां स्मृति आवंटन होता है। कुछ लूप लूप के अंदर कोई मेमोरी आवंटन नहीं करते हैं और इसलिए फेंकने से बाधित नहीं हो सकता है।

(throwTo के दस्तावेज़ीकरण से)। उपर्युक्त उदाहरण में, fac कोई मेमोरी आवंटित नहीं करता है और इसलिए बड़ी संख्या में यह तुरंत बाधित नहीं होगा।

अद्यतन: मैंने उन विचारों के आधार पर एक छोटी पुस्तकालय बनाई जो गणना के लिए एक मोनाद को परिभाषित करता है जो अंतिम एक लौटने से पहले या समय-समय पर मरने से पहले आंशिक परिणाम लौटा सकता है। देखें https://github.com/ppetr/timeout-with-results

3

परिणाम के बाद से आप समय पर निर्भर करते हैं, यह अनिवार्य रूप से अशुद्ध कोड शामिल करने जा रहा है।

यह base पैकेज से System.Timeout तरह लग रहा है कुछ समय समाप्ति तक एक आई/ओ गणना चलाने की क्षमता प्रदान करता है (leftaroundabout द्वारा टिप्पणी प्रति।) तो तुम सब करने की जरूरत है एक IO गणना कि परिणाम आप 'रिटर्न बारे में है इसमें दिलचस्पी है। हालांकि ... मुश्किल हिस्सा IO कार्रवाई वास्तव में गणना परिणाम न केवल एक अनियमित परिणाम लौटा रहा है। इसके लिए, मैं सोचता हूं आपको Control.Exception से evaluate की आवश्यकता है।

+0

+1 कि समय पर निर्भर एक कार्य अनिवार्य रूप से अशुद्ध है। –

2

System.Timeout जाने का रास्ता है। यह एक बहुत ही साफ इंटरफ़ेस है, जो आपको लगता है कि आप थ्रेड के साथ गड़बड़ कर रहे हैं।

खेल अंतरिक्ष सर्च कर रहे हैं एक शुद्ध गणना की तरह लगता है, और System.Timeout रन IO कार्रवाई, ताकि आप return में मूल्य लपेट, और कोड सख्ती से पर्याप्त है कि timeout तुरंत एक जवाब पर विश्वास नहीं करता मूल्यांकन करने के लिए की आवश्यकता होगी लौटा दिया गया है जैसे ही इसका मूल्यांकन डब्ल्यूएचएनएफ में किया गया है।

एक उदाहरण है जो एक जैसी समस्या से कोड जैसा दिख सकता है, here का उदाहरण है।