2016-09-22 5 views
8

modifyIORef के हस्ताक्षर पर्याप्त सरल है। एक विकल्प है जो इस मुद्दे को संबोधित करता है:atomicModifyIORef के अतिरिक्त परिणाम पैरामीटर का उद्देश्य क्या है?</p> <pre><code>modifyIORef :: IORef a -> (a -> a) -> IO() </code></pre> <p>दुर्भाग्य से, यह सुरक्षित थ्रेड नहीं है:

atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b 

इन दो कार्यों के बीच अंतर क्या हैं? को संशोधित करते समय मुझे b पैरामीटर का उपयोग कैसे करना चाहिए जो किसी अन्य थ्रेड से पढ़ा जा सकता है?

उत्तर

1

ने एक टिप्पणी में कहा गया है, संगामिति के बिना आप लेकिन एक समवर्ती संदर्भ में, किसी और पढ़ने और लिखने के बीच संदर्भ बदल सकता है जैसे

modifyAndReturn ref f = do 
    old <- readIORef ref 
    let !(new, r) = f old 
    writeIORef r new 
    return r 

कुछ लिखने में सक्षम होगी।

11

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

atomicModifyIORef ref (\old -> (new, old)) 

आप वापस जाने के लिए एक मूल्य की जरूरत नहीं है, तो आप निम्न का उपयोग कर सकते हैं:

atomicModifyIORef_ :: IORef a -> (a -> a) -> IO() 
atomicModifyIORef_ ref f = 
    atomicModifyIORef ref (\val -> (f val,())) 

जो modifyIORef रूप में एक ही हस्ताक्षर हैं।

+0

एक इसलिए, यह किया गया था 'atomicModifyIORef :: IORef: तो हम State का उपयोग कर समारोह के रूप में निम्नानुसार reformulate कर सकते हैं एक ही उद्देश्य (और सरल, आईएमओ)। दिलचस्प। – chi

+0

जो मुझे समझ में नहीं आता है, मुझे 'atomicModifyIORef' के लिए इस सुविधा की आवश्यकता क्यों होगी, लेकिन 'संशोधित IORef' के लिए नहीं? – leftaroundabout

+0

@ बाएंअराउंडबाउट ठीक है, 'संशोधित IORef' किसी भी परमाणु गारंटी प्रदान नहीं करता है, इसलिए यह इसके लिए उपयोगी नहीं होगा। – redneb

2

यहां मैं इसे कैसे समझता हूं। ब्रैकेट मुहावरे का पालन करने वाले कार्यों के बारे में सोचें, उदा।

withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r 

ये फ़ंक्शन तर्क के रूप में कार्य करता है और उस फ़ंक्शन का रिटर्न मान देता है। atomicModifyIORef इसी तरह के समान है। यह एक तर्क के रूप में एक कार्य करता है, और इरादा उस समारोह के वापसी मूल्य वापस करने के लिए है। केवल एक जटिलता है: तर्क फ़ंक्शन, IORef में संग्रहीत करने के लिए एक नया मान भी लौटाता है। उस वजह से, atomicModifyIORef उस फ़ंक्शन से दो मानों को वापस करने की आवश्यकता है। बेशक, यह मामला ब्रैकेट मामले के साथ पूरी तरह से समान नहीं है (उदाहरण के लिए कोई IO शामिल नहीं है, हम अपवाद सुरक्षा आदि से निपट नहीं रहे हैं), लेकिन यह समानता आपको एक विचार देती है।

+0

दिलचस्प तुलना। मैं फिर भी [dfeuer का उत्तर] स्वीकार करूँगा (http://stackoverflow.com/a/39682119/745903) अब से "यह परमाणु मोडिफ़ाई के लिए क्यों जरूरी है, लेकिन 'संशोधित' के लिए" भाग यह था कि यह सवाल मुख्य रूप से था । – leftaroundabout

1

जिस तरह से मुझे यह देखना पसंद है State monad के माध्यम से है। एक राज्यव्यापी ऑपरेशन कुछ आंतरिक राज्य को संशोधित करता है और इसके अतिरिक्त एक आउटपुट उत्पन्न करता है। यहां राज्य IORef के अंदर है और परिणाम IO ऑपरेशन के हिस्से के रूप में वापस कर दिया गया है। > (एक - -> एक) -> आईओ A`, पुराने मूल्य लौटने की सेवा की है |

import Control.Monad.State 
import Data.IORef 
import Data.Tuple (swap) 

-- | Applies a stateful operation to a reference and returns its result. 
atomicModifyIORefState :: IORef s -> State s a -> IO a 
atomicModifyIORefState ref state = atomicModifyIORef ref (swap . runState state) 
संबंधित मुद्दे