2012-11-16 14 views
7

में इंडेक्स के साथ एक राज्यव्यापी लुकअप टेबल रखने का बेवकूफ तरीका मैं सामान्य रूप से क्लोजर और कार्यात्मक प्रोग्रामिंग के लिए बिल्कुल नया हूं और मैं निम्नलिखित समस्या से जूझ रहा हूं। मैं टोकन (तार) की एक श्रृंखला के लिए एक अद्वितीय और स्थिर सूचकांक असाइन करना चाहता हूं। चूंकि सम्मिलन की तुलना में बहुत अधिक लुकअप होंगे, इसलिए हैश-मैप जाने का तरीका प्रतीत होता है।क्लोजर

जावा में मैं

int last = 0; 
HashMap<String, Integer> lut = new HashMap<String, Integer>(); 

function Integer getIndex(String token) { 
    Integer index = lut.get(token); 
    if(index == null) 
     last++; 
     lut.put(token, last); 
     return last; 
    else { 
     return index; 
    } 
} 

की तर्ज पर कुछ लिखा है होगा Clojure लिप्यंतरित संस्करण होगा

(def last-index (atom 0)) 
(def lookup-table (atom {})) 

(defn get-index [token] 
    (if (nil? (get @lookup-table token)) 
    (do 
     (swap! last-index inc) 
     (swap! lookup-table assoc token @last-index) 
     @last-index) 
    (get @lookup-table token))) 

की तरह कुछ लेकिन इस के बाद से बहुत idomatic होना प्रतीत नहीं होता है यह मूल रूप से साइड इफेक्ट्स और इसे छिपा भी नहीं करता है।

तो आप राज्य को रखने के लिए दो परमाणुओं के बिना ऐसा कैसे करेंगे? परमाणु में

+1

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

उत्तर

3

अंकुर द्वारा दिया गया उत्तर धागा सुरक्षित नहीं है, हालांकि मुझे नहीं लगता कि सीह का विवरण बहुत उपयोगी क्यों है, और उसके विकल्प खराब हैं। यह कहना उचित है "ठीक है, अब मैं कई धागे के बारे में चिंतित नहीं हूं", इस मामले में कि जवाब ठीक है। लेकिन यह भले ही आप किसी विशेष उदाहरण में है कि गारंटी की जरूरत नहीं है इस तरह की चीजों को सुरक्षित रूप से लिखने के लिए सक्षम होने के लिए महत्वपूर्ण है, और केवल सुरक्षित तरीका तो जैसे swap! अंदर अपने सभी तर्क करना है, यह है:

(let [m (atom {})] 
    (defn get-index [token] 
    (get (swap! m 
       #(assoc % token (or (% token) (count %)))) 
     token))) 

swap! से बचने पर आप इसे थोड़ा तेज कर सकते हैं यदि फ़ंक्शन कहलाते समय पहले से ही कोई प्रविष्टि हो, और swap! दर्ज करने के बाद पहले से ही कोई प्रविष्टि हो तो एक assoc से बचकर, लेकिन "डबल चेक "नक्शा में (count %) को असाइन करने से पहले वर्तमान टोकन के लिए प्रविष्टि नहीं है, क्योंकि swap! आईएनजी शुरू करने से पहले कुछ अन्य थ्रेड फंस गए होंगे (लेकिनपर निर्णय लेने के बाद), और वर्तमान टोकन के लिए एक मान असाइन किया है, इस मामले में आपको एक नया निर्माण करने के बजाय उस असाइनमेंट का सम्मान करना होगा।

संपादित करें: एक तरफ के रूप में, पाठ्यक्रम के जावा संस्करण में एक ही थ्रेड-सुरक्षा समस्या है, क्योंकि डिफ़ॉल्ट रूप से जावा में सबकुछ परिवर्तनीय है और थ्रेड-सुरक्षित नहीं है। क्लोजर में कम से कम आपको ! डालना होगा, "हाँ, मुझे पता है कि यह खतरनाक है, मुझे पता है कि मैं क्या कर रहा हूं।"

तो कुछ अर्थों में अंकुर का समाधान जावा 0 का सही अनुवाद है, लेकिन इससे भी बेहतर होगा!

+0

मैं अपने नोट के बारे में उत्सुक हूं कि आपने सोचा कि इससे मामला खराब हो जाएगा। मैं संक्षेप में था, लेकिन मेरा मुद्दा यह था कि परमाणु रूप से परमाणु को पुनर्निर्मित करना सुरक्षित नहीं है, क्योंकि दो रेसिंग धागे ऐसा करने से परिवर्तनों को छोड़ देंगे जो दूसरे ने करने की कोशिश की थी। आप उन दो रेसिंग धागे को कैसे समन्वयित करते हैं, डिजाइन की बात है। 'स्वैप!' के लिए प्रलेखन को दोबारा पढ़ना, मैं देखता हूं कि जब तक यह लगातार मूल्य निर्धारित नहीं करता है, और इसलिए 'तुलना-और-सेट' का उपयोग करने के लिए मेरा सुझाव अधिक होगा। मुझे अभी भी लगता है कि * * ref * के खिलाफ 'dosync' का उपयोग करना सबसे स्पष्ट तरीका है। – seh

+0

दो थ्रेड रेसिंग '(स्वैप! एफ)' कभी भी "फेंक दें" परिवर्तन नहीं। परमाणु हमेशा एक सतत स्थिति में होगा, और अंततः 'ए' को '(एफ (एफ पुराना-ए)) पर सेट किया जाएगा। समस्या यह है कि वह 'स्वैप' के बाहर * से * जानकारी के आधार पर 'एफ 1' और 'एफ 2' का निर्माण कर रहा है, जो कि पुराना हो सकता है। 'तुलना-और-स्वैप!' यह गलती करने के लिए बस * आसान * बनाता है, आईएमओ। 'dosync' ठीक है, जब तक आप सुनिश्चित करते हैं कि यह एक परमाणु के बजाय एक रेफरी है, लेकिन यह आमतौर पर एक संदर्भ के प्रबंधन के लिए अधिक है, और एक अच्छा' स्वैप 'लिखना सीखना महत्वपूर्ण है। – amalloy

0

एकल नक्शा पर्याप्त होगा:

(def m (atom {})) 
;adding new string to map 
(swap! m #(assoc %1 "Hello" (count %))) 
;get an index 
(@m "Hello") 

(defn get-index [token] 
    (or (@m token) 
     ((swap! m #(assoc %1 token (count %))) token))) 

आप मूल रूप से clojure जावा जरूरी कोड को मैप करने की कोशिश की और thats क्यों आप अपने सवाल में है कि समाधान मिल गया। चरणबद्ध अनिवार्य शैली को सोचने के बजाय अभिव्यक्ति लिखने के संदर्भ में सोचने की कोशिश करें।

+0

आपने 'तुलना-और-सेट' की बजाय 'स्वैप!' का उपयोग क्यों प्रस्तावित किया है, या यहां तक ​​कि 'dosync' कॉल के भीतर मानचित्र को पुन: बाध्य करना भी? यदि आप अन्य धागे के खिलाफ दौड़ने की उम्मीद कर रहे हैं, तो 'स्वैप!' का उपयोग करके यहां अनजाने में आपके परिवर्तनों को ओवरराइट करने की अनुमति मिलती है। – seh