GHC.IO

2015-02-27 3 views
11

से `ioToST` और` unsafeIOToST` के बीच क्या अंतर है और unsafeSTToIOGHC.IO में परिभाषित अंतर और इच्छित उपयोग क्या हो सकता है?GHC.IO

-- --------------------------------------------------------------------------- 

-- Coercions between IO and ST 

-- | A monad transformer embedding strict state transformers in the 'IO' 
-- monad. The 'RealWorld' parameter indicates that the internal state 
-- used by the 'ST' computation is a special one supplied by the 'IO' 
-- monad, and thus distinct from those used by invocations of 'runST'. 
stToIO  :: ST RealWorld a -> IO a 
stToIO (ST m) = IO m 

ioToST  :: IO a -> ST RealWorld a 
ioToST (IO m) = (ST m) 

-- This relies on IO and ST having the same representation modulo the 
-- constraint on the type of the state 
-- 
unsafeIOToST  :: IO a -> ST s a 
unsafeIOToST (IO io) = ST $ \ s -> (unsafeCoerce# io) s 

unsafeSTToIO :: ST s a -> IO a 
unsafeSTToIO (ST m) = IO (unsafeCoerce# m) 
+5

अंतर इस प्रकार में है।ioToST केवल 'एसटी रियलवर्ल्ड ए' उत्पन्न कर सकता है जिसे आप 'runST :: (forall s। एसटी एस) -> ए' तक नहीं पारित कर सकते हैं। – user2407038

उत्तर

12

सुरक्षित संस्करणों आईओ इकाई में शुरू करनी चाहिए (क्योंकि आप runST से एक ST RealWorld प्राप्त नहीं कर सकता) और आप आईओ संदर्भ और एक ST RealWorld संदर्भ बीच स्विच कर सकते। वे सुरक्षित हैं क्योंकि ST RealWorld मूल रूप से आईओ के समान ही है।

असुरक्षित संस्करण कहीं भी शुरू हो सकते हैं (क्योंकि runST कहीं भी कहा जा सकता है) और आपको मनमाने ढंग से एसटी मोनैड और आईओ मोनैड के बीच स्विच करने की अनुमति देता है। शुद्ध संदर्भ से runST का उपयोग करना और फिर राज्य मोनैड के भीतर unsafeIOToST करना मूल रूप से unsafePerformIO का उपयोग करने के बराबर है।

+4

मुझे पता है कि यह ओपी का सवाल नहीं है, लेकिन मेरे दिमाग में बड़ा सवाल यह है कि, अगर कुछ भी है, तो 'असुरक्षित टीओआई' असुरक्षित बनाता है। – dfeuer

+1

@dfeuer इसे या तो 'unsafeIOToST' के साथ समरूपता के लिए असुरक्षित कहा जा सकता है, या हो सकता है कि आप इसे' STVAR' 'के बाहर' STVAR' तक पहुंचने के लिए इसका उपयोग करने का एक तरीका ढूंढ सकें, जिस स्थिति में यह वास्तव में असुरक्षित होगा अपने आप। –

+2

मुझे इसके बारे में हैकेल-कैफे पर एक धागा मिला। ऐसा लगता है कि यह वास्तव में असुरक्षित है, लेकिन मुझे किसी भी उदाहरण को समझ में नहीं आता है। – dfeuer

9

टीएल; डीआर। इन चारों में से सभी कार्य केवल टाइपकास्ट हैं। वे रन-टाइम पर सभी नो-ऑप हैं। केवल उनके बीच के अंतर प्रकार हस्ताक्षर — है लेकिन यह प्रकार हस्ताक्षर कि पहली जगह में सभी सुरक्षा की गारंटी देता है लागू है!


ST इकाई और IO इकाई दोनों आप परिवर्तनशील राज्य दे।

IO मोनड से बचने के लिए यह बेहद असंभव है। [ठीक है, नहीं, तुम अगर आप unsafePerformIO उपयोग कर सकते हैं। ऐसा मत करो!] इस वजह से, सब मैं/हे कि अपने कार्यक्रम कभी प्रदर्शन एक विशाल IO ब्लॉक में बंडल हो जाता है, इस प्रकार के संचालन पर एक वैश्विक आदेश को लागू करने। [कम से कम, जब तक आप forkIO फोन है, लेकिन वैसे भी ...]

कारण unsafePerformIO इतना असुरक्षित शापित है, है कि वहाँ , अगर कोई रास्ता नहीं वास्तव में जब यह पता लगाने की है या कितनी बार संलग्न मैं/हे ऑपरेशंस — होगा जो आमतौर पर बहुत बुरी चीज है।

ST इकाई भी परिवर्तनशील राज्य प्रदान करता है, लेकिन यह करता बचने तंत्र — runST समारोह है। यह आपको एक शुद्ध एक में एक अशुद्ध मूल्य बदलने देता है। लेकिन अब वहाँ कोई रास्ता नहीं गारंटी करने के लिए क्या आदेश अलग ST ब्लॉकों में चलेंगे। क्रम पूरा तबाही को रोकने के लिए है, तो हम यह सुनिश्चित करें कि अलग ST ब्लॉक एक दूसरे के साथ नहीं "हस्तक्षेप" कर सकते हैं की जरूरत है।

इसी कारण से, आप ST मोनैड में कोई I/O संचालन नहीं कर सकते हैं। आप परिवर्तनीय स्थिति तक पहुंच सकते हैं, लेकिन उस राज्य को ST ब्लॉक से बचने की अनुमति नहीं है।

IO मोनड और ST मोनड वास्तव में समान मोनैड हैं। और IORef वास्तव में एक STRef है, और इसी तरह। तो यह वास्तव में हंसमुख उपयोगी द्वारा कोड लिख सकते हैं और दोनों monads में इसका इस्तेमाल करने में सक्षम हो जाएगा। और आपके द्वारा बताए गए सभी चार कार्य प्रकार-प्रकार हैं जो आपको बिल्कुल ऐसा करने देते हैं।

खतरे को समझने के लिए, हमें यह समझने की आवश्यकता है कि ST इसकी छोटी सी चाल कैसे प्राप्त करता है। यह सभी प्रकार के प्रेत में s प्रकार में है। एक ST ब्लॉक चलाने के लिए, यह सब संभव s के लिए काम करने की जरूरत:

runST :: (forall s. ST s x) -> x 

सभी परिवर्तनशील सामान प्रकार में s रूप में अच्छी तरह है, और एक खुश दुर्घटना से, इसका मतलब है कि किसी भी प्रयास को बाहर परिवर्तनशील सामान वापस करने के लिए कि ST मोनड बीमार टाइप किया जाएगा। (यह वास्तव में एक हैक का थोड़ा सा है, लेकिन यह बहुत पूरी तरह से काम करता है ...)

कम से कम, यदि आप runST का उपयोग करते हैं तो यह खराब टाइप किया जाएगा। ध्यान दें कि ioToST आपको ST RealWorld x देता है। लगभग बोलते हुए, IO x और लगभग; ST RealWorld x। लेकिन runST इनपुट के रूप में स्वीकार नहीं करेगा। तो आप I/O चलाने के लिए runST का उपयोग नहीं कर सकते।

ioToST आपको एक प्रकार देता है जिसे आप runST के साथ उपयोग नहीं कर सकते हैं। लेकिन unsafeIOToST आपको एक प्रकार देता है जो runST के साथ ठीक काम करता है। एक अनुमान क्या चल रहा है ले

foobar = do 
    v <- unsafeSTToIO (newSTRef 42) 
    let w = runST (readSTRef v) 
    let x = runST (writeSTRef v 99) 
    print w 

वाना:

unsafePerformIO = runST . ioToST 

unsafeSTToIO आप दूसरे में एक ST ब्लॉक से बाहर परिवर्तनशील सामान पाने के लिए, और संभवतः अनुमति देता है: उस समय, आप मूल रूप से unsafePerformIO को लागू किया है मुद्रित करने के लिए? क्योंकि बात यह है कि हमारे पास तीन ST क्रियाएं हैं, जो बिल्कुल किसी भी क्रम में हो सकती हैं। readSTRefwriteSTRef से पहले या उसके बाद होगा?

[वास्तव में, इस उदाहरण में, लेखन कभी नहीं होता है, क्योंकि हम x के साथ कुछ भी नहीं करते हैं। लेकिन अगर मैं कोड के कुछ दूर, असंबद्ध हिस्से में x पास करता हूं, और वह कोड इसका निरीक्षण करने के लिए होता है, अचानक हमारे आई/ओ ऑपरेशन कुछ अलग करता है। शुद्ध कोड ऐसा परिवर्तनशील सामान प्रभावित करने के लिए सक्षम नहीं होना चाहिए]


संपादित करें: ऐसा प्रतीत होता है मैं थोड़ा समय से पहले था। unsafeSTToIO फ़ंक्शन आपको ST मोनैड से एक म्यूटेबल मान लेने की अनुमति देता है, लेकिन ऐसा लगता है कि इसे पर एक दूसरी कॉल की आवश्यकता है ताकि म्यूटेबल चीज़ को ST मोनड फिर से डाला जा सके। आप कुछ unsafeIOToST में पाठ्यक्रम मिश्रण के रूप में अच्छी तरह कर सकता है (उस समय, दोनों कार्य IO कार्रवाई, इसलिए उनके आदेश की गारंटी है कर रहे हैं।)

, लेकिन वास्तव में साबित नहीं होता कि unsafeSTToIO से ही असुरक्षित है:

foobar = do 
    v <- unsafeSTToIO (newSTRef 42) 
    let w = runST (unsafeIOToST $ unsafeSTToIO $ readSTRef v) 
    let x = runST (unsafeIOToST $ unsafeSTToIO $ writeSTRef v 99) 
    print w 

मैं इस के साथ चारों ओर खेला है, और मैं अभी तक इस प्रकार चेकर को समझाने के लिए मुझे कुछ provably असुरक्षित केवलunsafeSTToIO का उपयोग कर करते हैं करने में कामयाब नहीं किया है। मुझे विश्वास है कि यह किया जा सकता है, और इस सवाल पर विभिन्न टिप्पणियां सहमत हैं, लेकिन मैं वास्तव में एक उदाहरण नहीं बना सकता। हालांकि आपको विचार मिलता है; प्रकारों को बदलें, और आपकी सुरक्षा टूट जाती है।

+3

"तो यह वास्तव में कोड लिखने और इसे दोनों monads में उपयोग करने में सक्षम होने के लिए उपयोगी है।" वहाँ वास्तव में एक बहुत साफ रास्ता कुछ भी असुरक्षित बिना इस उद्देश्य को पूरा करने है: [ 'primitive'] (https://hackage.haskell.org/package/primitive)' अनुसूचित जनजाति s' और 'IO' उदाहरणों के साथ एक' PrimMonad' वर्ग प्रदान करता है और केवल उन सभी चीज़ों के बारे में जिन्हें आप लिखना चाहते हैं जो कि उदाहरण के साथ सौदा कर सकते हैं। इन रूपांतरणों को केवल इस तथ्य से निपटने के लिए जरूरी है कि कई लाइब्रेरी फ़ंक्शंस (अनावश्यक) विशिष्ट हैं। – dfeuer

+1

एर ... मैंने अभी कोशिश की, और आपका प्रोग्राम टाइपशेक नहीं करता है। असली उदाहरण अपेक्षाकृत अधिक सूक्ष्म प्रतीत होते हैं। – dfeuer

+2

मुझे विश्वास है कि 'foobar' उदाहरण काम नहीं कर सकता है। कारण यह है कि 'runST' को पॉलीटाइप मान की आवश्यकता होती है, जबकि' v' monotyped है। दरअसल, 'असुरक्षित टीओआईओ (न्यूस्ट्रिफ 42)' टाइप टाइप 'के लिए है। आईओ (एसटीआरएफ एस इंट) ', और' आईओ (फोर्स एस। एसटीआरआईफ़ एस इंट) 'नहीं। – chi