2011-08-26 7 views
6

मैं हास्केल में निम्नलिखित समारोह:क्या हास्केल में कोई मूल्य ज्ञापन करने का कोई तरीका है?

memdb = -- load the contents of a database into memory as a Map 

और फिर मैं निम्न पंक्ति है:

map (\x -> memdb ! x) values 

मैं केवल एक बार मानचित्र उत्पन्न करने के लिए memdb चाहते हैं, के बजाय map के हर यात्रा पर । मैं कुछ इस तरह का उपयोग कर इसे कर सकता है:

make_memdb = -- equivalent to memdb in previous example 
memdb <- make_memdb 
map (\x -> memdb ! x) values 

लेकिन इसका मतलब यह है कि मैं हर कार्य यह का उपयोग करता है करने के लिए memdb पारित करने के लिए होगा। क्या कोई तरीका है:

ए। प्रत्येक बार इसे memdb पुन: गणना करने से बचें जब इसे OR

बी कहा जाता है। make_memdb में बनाए गए मान को निरंतर के रूप में सहेजें ताकि मैं इसे उपयोग करने वाले प्रत्येक फ़ंक्शन में इसे पारित करने से बच सकूं?

+0

संभव डुप्लिकेट हास्केल?] (Http://stackoverflow.com/questions/141650/how-do-you-make-a-generic-memoize-function-in-haskell) –

+0

@ क्रेग स्टंटज़: मैंने उस प्रश्न के माध्यम से पढ़ा था मेरा पोस्ट करने से पहले। उन उत्तरों को मुझे कैसे प्राप्त करने में मदद मिलेगी। या बी। ? –

+0

@ क्रेग: शीर्षक के बावजूद, यह प्रश्न वास्तव में शब्द की सामान्य समझ में ज्ञापन के बारे में नहीं है। यह उस प्रश्न का डुप्लिकेट नहीं है। – hammar

उत्तर

13

जैसे आपका नक्शा डेटाबेस से आता है, इसका मतलब है कि यह स्थिर नहीं हो सकता क्योंकि यह आपके आवेदन के रनों के बीच अलग हो सकता है।

लेकिन इसका मतलब यह है कि मैं हर कार्य यह का उपयोग करता है करने के लिए memdb पारित करने के लिए होगा।

हां, लेकिन यह लगता है कि इससे कम बुरा बनाने के लिए उपकरण हैं। विशेष रूप से, यह the reader monad के लिए एक पूर्ण उपयोग केस की तरह लगता है!

रीडर मोनैड आमतौर पर उपयोग किए जाते हैं जब आपके पास कुछ मूल्य होता है, जैसे कॉन्फ़िगरेशन, जिसे आप अपने प्रोग्राम की शुरुआत में लोड करना चाहते हैं और फिर इसे अपने प्रोग्राम के चारों ओर आसानी से पास किए बिना इसे एक्सेस करने में सक्षम हो ।

main = do 
    memdb <- make_memdb -- Get the memdb from the database once and for all 
    runReaderT foo memdb 

foo = do 
    memdb <- ask -- Grab the memdb. Will not reload from the database 
    liftIO $ putStrLn "Hello, world" -- IO actions have to be lifted 
    -- [...] 

भी देखें:: यहाँ आप इसे कैसे प्रयोग करेंगे की एक छोटी सी उदाहरण है

की [कैसे आप में एक सामान्य memoize समारोह कर सकता हूँ
+0

बहुत बहुत धन्यवाद! –

+0

यह लगभग है जैसे कि यह प्रश्न पाठक मोनड को सुसमाचार देने के लिए * बनाया गया था। अच्छा उत्तर। –

1

आप memdbIO के माध्यम से अधिक पैरामीटर पास करने से बचने के तरीके के रूप में memdb प्राप्त करना चाहते हैं, सही? फिर आप पूछते हैं कि क्या आप या तो (ए) memdb को परिभाषित कर सकते हैं, जिसका अर्थ यह है कि यह डीबी से डेटा लोड करने के ऊपरी हिस्से के बिना शीर्ष स्तर का फ़ंक्शन होगा, (यदि आप लोड किए गए डेटा संरचना को वैश्विक दायरे से बचा सकते हैं।

इनमें से दोनों शीर्ष स्तर के उत्परिवर्तनीय वैश्विक चर को परिभाषित करने के लिए IORef और unsafePerformIO के साथ काम करने योग्य हैं। मुझे यह नहीं लगता कि आप ऐसा करते हैं। यह रिएक्टर के लिए बेकार और परेशान है। जिसके अनुसार, मैं तुम्हें दिखाता हूँ कैसे वैसे भी:

make_memdb :: IO (Map K V) 

आप एक शीर्ष स्तर परिवर्तनशील चर घोषणा कर सकते हैं:

मान लें कि आप एक समारोह है

import Data.Map as M 
import Data.IORef 

mRef :: IORef (Map K V) 
mRef = unsafePerformIO $ newIORef M.empty 
{-# NOINLINE mRef #-} 

main = do 
    m <- make_memdb 
    writeIORef mRef m 
    ... do stuff using mRef ... 

stuffUsingMRef ... = do 
    memdb <- readIORef 
    let vs = map (memdb !) values 
    return vs 

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

+0

क्या आप मुझे उदाहरण दे सकते हैं कि राज्य मोनड कैसे मदद करेगा? –

+0

रीडर मोनैड का उपयोग करके हथौड़ा का जवाब देखें, जो कि मैंने आपको दिखाया होगा (किसी भी संशोधन के बिना राज्य मोनैड का उपयोग करके - इसलिए मुझे 'रीडर' के बारे में भी सोचना चाहिए था)। –

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