2012-04-13 17 views
6

मैं एक प्रोग्राम है जो कार्यों f की एक श्रृंखला पैदा करता है और g जो ऐसा दिखाई देता है की एक श्रृंखला में तेजी लाने के (या memoize):कैसे परस्पर पुनरावर्ती कार्यों

step (f,g) = (newF f g, newG f g) 

newF f g x = r (f x) (g x) 
newG f g x = s (f x) (g x) 

foo = iterate step (f0,g0) 

कहाँ r और कुछ नीरस हैं f x और g x के कार्य। मुझे उम्मीद है कि foo होने पर एक सूची होगी इसका मतलब यह होगा कि जब मैं n'th f पर कॉल करता हूं तो यह (n-1) th f को फिर से गणना नहीं करेगा अगर यह पहले ही इसकी गणना कर चुका है (जैसा कि f और g नहीं हुआ होता फ़ंक्शन)। क्या पूरे कार्यक्रम को अलग किए बिना इसे याद करने का कोई तरीका है (उदाहरण के लिए सभी प्रासंगिक तर्कों पर f0 और g0 का मूल्यांकन करना और फिर ऊपर काम करना)?

+2

बार-बार n'th 'f' को पुन: संकुचित करने से बार-बार (n-1) 'th' f' पुन: गणना नहीं होती है ... लेकिन याद रखें, फ़ंक्शन को पुन: कंप्यूटिंग करने का मतलब यह नहीं है कि कॉलिंग के परिणाम को पुनः संयोजित करना एक तर्क के साथ एक समारोह! –

उत्तर

0

आपको Data.MemoCombinators उपयोगी (डेटा-मेमोकॉम्बिनेटर पैकेज में) मिल सकता है।

आप कहते हैं कि क्या तर्क प्रकारों अपने f और g ले --- वे दोनों तो अभिन्न मान लेता है, यदि आप इसे इस तरह का प्रयोग करेंगे:

import qualified Data.MemoCombinators as Memo 

foo = iterate step (Memo.integral f0, Memo.integral g0) 

यदि आवश्यक हो, आप के उत्पादन में memoise सकता है प्रत्येक चरण के साथ-साथ

step (f,g) = (Memo.integral (newF f g), Memo.integral (newG f g)) 

मुझे आशा है कि आप इसे पूरे कार्यक्रम को अलग करने के रूप में नहीं देख पाएंगे।


अपनी टिप्पणी के जवाब में:

यह सबसे अच्छा मैं के साथ आ सकता है। यह अवांछित है, लेकिन सही लाइनों के साथ काम करना चाहिए।

मुझे चिंता है कि Double और Rational के बीच परिवर्तित बेकार में अक्षम है --- अगर वहाँ हम बजाय Memo.bits इस्तेमाल कर सकते हैं Double के लिए एक Bits उदाहरण था। तो यह अंततः आपके लिए किसी भी व्यावहारिक उपयोग का नहीं हो सकता है।

import Control.Arrow ((&&&)) 
import Data.Ratio (numerator, denominator, (%)) 

memoV :: Memo.Memo a -> Memo.Memo (V a) 
memoV m f = \(V x y z) -> table x y z 
    where g x y z = f (V x y z) 
     table = Memo.memo3 m m m g 

memoRealFrac :: RealFrac a => Memo.Memo a 
memoRealFrac f = Memo.wrap (fromRational . uncurry (%)) 
          ((numerator &&& denominator) . toRational) 
          Memo.integral 

एक अलग दृष्टिकोण।

आप

step :: (V Double -> V Double, V Double -> V Double) 
    -> (V Double -> V Double, V Double -> V Double) 

है कैसे के बारे में आप बदल कि

step :: (V Double -> (V Double, V Double)) 
    -> (V Double -> (V Double, V Double)) 
step h x = (r fx gx, s fx gx) 
    where (fx, gx) = h x 

और यह भी करने के लिए बदल

foo = (fst . bar, snd . bar) 
    where bar = iterate step (f0 &&& g0) 
उम्मीद है कि

साझा fx और gx गति का एक सा में परिणाम चाहिए -अप।

+0

महान उत्तर के लिए धन्यवाद। इस दृष्टिकोण के साथ मुझे एकमात्र परेशानी यह है कि 'एफ' और' जी 'में' वी डबल -> वी डबल 'टाइप किया गया है, जहां' डेटा वी ए = वी एएए 'है और यह बिल्कुल स्पष्ट नहीं है कि मैं कैसे " 'Memo.v' "या यदि यह भी संभव है। –

+1

@SeanD मेरा संपादन देखें। – dave4420

0

क्या पूरे कार्यक्रम को अलग किए बिना इसे याद करने का कोई तरीका है (उदाहरण के लिए सभी प्रासंगिक तर्कों पर f0 और g0 का मूल्यांकन करना और फिर ऊपर काम करना)?

यह आपको "पूरे कार्यक्रम के अलावा फाड़" द्वारा क्या मतलब हो सकता है, लेकिन यहाँ एक समाधान है, जिसमें (मेरा मानना ​​है कि लेकिन एटीएम परीक्षण नहीं कर सकते) fooX साझा किया जा सकता है।

nthFooOnX :: Integer -> Int -> (Integer, Integer) 
nthFooOnX x = 
    let fooX = iterate step' (f0 x, g0 x) 
    in \n-> fooX !! n 

step' (fx,gx) = (r fx gx, s fx gx) 

-- testing definitions: 
r = (+) 
s = (*) 
f0 = (+1) 
g0 = (+1) 

मुझे नहीं पता कि यह आपके मूल कार्यान्वयन की भावना को संरक्षित करता है या नहीं।