2017-07-08 12 views
5

मैं Cont के साथ खेल रहा हूं here और this SO question में वर्णित मोनैड चालें। मैं Cont के शीर्ष पर इकाई ट्रांसफार्मर के इन खिलौना उदाहरण हैपर स्टेट स्टेट। मेरा राज्य रीसेट क्यों नहीं किया जा रहा है?

import Control.Monad.Cont 
import Control.Monad.State.Strict 
import Control.Monad.Writer.Strict 

getCC' :: MonadCont m => a -> m (a,a -> m b) 
getCC' x0 = callCC (\c -> let f x = c (x, f) in return (x0, f)) 

:

इस समारोह आप गणना में पहले करने के लिए "वापस कूद", एक पैरामीटर लेने ताकि आप अलग तरह से काम कर सकते हैं की सुविधा देता है

foo :: WriterT String (Cont String)() 
foo = do 
    (stop,loop) <- getCC' False 
    if stop 
     then do tell "bbb" 
     else do tell "aaa" 
       loop True 

foo' :: StateT String (Cont String)() 
foo' = do 
    (stop,loop) <- getCC' False 
    if stop 
     then do modify $ \s -> s ++ "bbb" 
     else do modify $ \s -> s ++ "aaa" 
       loop True 

पहले उदाहरण में Cont के प्रभाव WriterT के प्रभाव पर "प्राथमिकता" है (अतः जुड़ा हुआ प्रश्न में explained के रूप में)। जब हम गणना रीसेट, लॉग खो दिया है:

*Main> print $ runCont (execWriterT foo) id 
"bbb" 

दूसरे उदाहरण बिल्कुल वही बात, केवल WriterT के बजाय StateT का उपयोग करता है। हालांकि, इस मामले में लॉग संरक्षित है!

*Main> print $ runCont (execStateT foo' "") id 
"aaabbb" 

इस विसंगति का स्पष्टीकरण क्या है?

उत्तर

4

(मुझे लगता है कि यह एक पूरी तरह से संतोषजनक जवाब नहीं है, लेकिन कम से कम यह एक छोटे से स्पष्ट करना चाहिए।)

मेरा मानना ​​है कि इस callCC उठाने की वजह से है।

liftCallCC :: CallCC m (a, s) (b, s) -> CallCC (StateT s m) a b 

नई इकाई के लिए एक callCC आपरेशन के वर्दी उठाने: राज्य इकाई मामले में, छेद नीचे खरगोश का पीछा करते हुए के बाद, हम इस को पूरा। यह संस्करण निरंतरता दर्ज करने पर मूल स्थिति में वापस रोल करता है।

liftCallCC' :: CallCC m (a, s) (b, s) -> CallCC (StateT s m) a b 

नए मोनाड में कॉलसीसी ऑपरेशन की स्थिति में उठाना। यह संस्करण निरंतरता दर्ज करने पर वर्तमान स्थिति का उपयोग करता है।

कौन सा लिया जाता है? एक संरक्षित राज्य:

instance MonadCont m => MonadCont (LazyState.StateT s m) where 
    callCC = LazyState.liftCallCC' callCC 

instance MonadCont m => MonadCont (StrictState.StateT s m) where 
    callCC = StrictState.liftCallCC' callCC 

लेखक मोनड के लिए क्या होता है?

instance (Monoid w, MonadCont m) => MonadCont (LazyWriter.WriterT w m) where 
    callCC = LazyWriter.liftCallCC callCC 

instance (Monoid w, MonadCont m) => MonadCont (StrictWriter.WriterT w m) where 
    callCC = StrictWriter.liftCallCC callCC 

आह-हा! नहीं '!

liftCallCC :: Monoid w => CallCC m (a, w) (b, w) -> CallCC (WriterT w m) a b 

लिफ्ट नई इकाई के लिए एक callCC आपरेशन।

लाइब्रेरी में कोई भी राज्य-संरक्षण संस्करण नहीं मिला है। इसके बाद के संस्करण संस्करण है, बजाय, वहाँ पाया जाता है के रूप में

liftCallCC callCC f = WriterT $ 
    callCC $ \ c -> 
    runWriterT (f (\ a -> WriterT $ c (a, mempty))) 

नोट mempty परिभाषित किया।अगर हमारे पास get ऑपरेशन था, तो हम वहां "वर्तमान स्थिति" स्टोर कर सकते थे, ताकि प्रक्रिया में यह खो न जाए, लेकिन अगर हमारे पास यह था कि हम अब लेखक मोनैड में नहीं होंगे, बल्कि राज्य में होंगे।


यह भी ध्यान दें कि विपरीत क्रम में मोनाडों को ढेर करना हम चाहते हैं कि प्राप्त करें।

bar :: ContT String (Writer String)() 
bar = do 
    (stop,loop) <- getCC' False 
    if stop 
     then do lift $tell "bbb" 
     else do lift $ tell "aaa" 
       loop True 

-- > runWriter (runContT bar (const $ pure "")) 
-- ("","aaabbb") 
+0

मुझे लगता है राज्य भूल व्यवहार डिफ़ॉल्ट एक ही नहीं, 'WriterT' साथ एकरूपता के लिए होना चाहिए, लेकिन सहज नियम यह है कि आंतरिक monads के प्रभाव कुछ अर्थों में" प्राथमिकता दी जाती है "लागू करने के लिए। – danidiaz

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