खोज…


मुक्त मठों ने डेटा संरचनाओं और दुभाषियों में मौद्रिक संगणना को विभाजित किया

उदाहरण के लिए, प्रॉम्प्ट में प्रॉम्प्ट को पढ़ने और लिखने के लिए संकेत दिया जाता है:

पहले हम अपने गणना के "कमांड" को एक फ़ंक्शनल डेटा प्रकार के रूप में वर्णित करते हैं

{-# LANGUAGE DeriveFunctor #-}

data TeletypeF next
    = PrintLine String next
    | ReadLine (String -> next)
    deriving Functor

फिर हम "Free Monad over TeletypeF " बनाने और कुछ बुनियादी ऑपरेशन बनाने के लिए Free का उपयोग करते हैं।

import Control.Monad.Free (Free, liftF, iterM)

type Teletype = Free TeletypeF

printLine :: String -> Teletype ()
printLine str = liftF (PrintLine str ())

readLine :: Teletype String
readLine = liftF (ReadLine id)

के बाद से Free f एक है Monad जब भी f एक है Functor , हम मानक का उपयोग कर सकते Monad (सहित combinators do निर्माण करने के लिए अंकन) Teletype संगणना।

import Control.Monad -- we can use the standard combinators

echo :: Teletype ()
echo = readLine >>= printLine

mockingbird :: Teletype a
mockingbird = forever echo

अंत में, हम एक "दुभाषिया" लिखकर Teletype a को कुछ Teletype a मूल्यों में बदल देते हैं Teletype a हम जानते हैं कि IO a साथ कैसे काम करना IO a

interpretTeletype :: Teletype a -> IO a
interpretTeletype = foldFree run where
  run :: TeletypeF a -> IO a
  run (PrintLine str x) = putStrLn *> return x
  run (ReadLine f) = fmap f getLine

जिसका उपयोग हम Teletype a IO में गणना करने के लिए "रन" के लिए कर सकते हैं

> interpretTeletype mockingbird
hello
hello
goodbye
goodbye
this will go on forever
this will go on forever

फ्री मोनाड निश्चित बिंदुओं की तरह हैं

की परिभाषा की तुलना करें Free की है कि Fix :

data Free f a = Return a
              | Free (f (Free f a))

newtype Fix f = Fix { unFix :: f (Fix f) }

विशेष रूप से, Fix कंस्ट्रक्टर के प्रकार के साथ Free कंस्ट्रक्टर के प्रकार की तुलना FixFree फ़िशर की तरह लेयर्स Fix , सिवाय इसके कि Free में एक अतिरिक्त Return a केस हो।

FoldFree और iterM कैसे काम करते हैं?

Free अभिकलन को फाड़ने में मदद करने के लिए कुछ कार्य हैं जो उन्हें एक और iterM :: (Functor f, Monad m) => (f (ma) -> ma) -> (Free fa -> ma) m में व्याख्या करके करते हैं: iterM :: (Functor f, Monad m) => (f (ma) -> ma) -> (Free fa -> ma) और foldFree :: Monad m => (forall x. fx -> mx) -> (Free fa -> ma) । वे क्या कर रहे हैं?

पहले आइए देखें कि एक व्याख्या को फाड़ने के लिए क्या करना होगा एक Teletype a IO मैन्युअल रूप से Teletype a फ़ंक्शन। हम Free fa को परिभाषित होने के रूप में देख सकते हैं

data Free f a 
    = Pure a 
    | Free (f (Free f a))

Pure मामला आसान है:

interpretTeletype :: Teletype a -> IO a
interpretTeletype (Pure x) = return x
interpretTeletype (Free teletypeF) = _

अब, एक Teletype गणना की व्याख्या कैसे करें जो Free कंस्ट्रक्टर के साथ बनाया गया था? हम teletypeF :: TeletypeF (Teletype a) जाँच करके IO a के प्रकार पर teletypeF :: TeletypeF (Teletype a) । आरंभ करने के लिए, हम एक फ़ंक्शन runIO :: TeletypeF a -> IO a जो एक मुक्त कार्रवाई के लिए एक runIO :: TeletypeF a -> IO a एक परत को मैप करता है IO कार्रवाई:

runIO :: TeletypeF a -> IO a
runIO (PrintLine msg x) = putStrLn msg *> return x
runIO (ReadLine k) = fmap k getLine

अब हम बाकी की interpretTeletype में भरने के लिए runIO का उपयोग कर सकते हैं। स्मरण करो कि teletypeF :: TeletypeF (Teletype a) a, TeletypeF functor की एक परत है जिसमें शेष Free संगणना होती है। हम सबसे बाहरी परत की व्याख्या करने के लिए runIO का उपयोग करेंगे (इसलिए हमारे पास runIO teletypeF :: IO (Teletype a) ) और फिर दिए गए Teletype a व्याख्या करने के लिए IO मोनड के >>= संयोजन का उपयोग करें।

interpretTeletype :: Teletype a -> IO a
interpretTeletype (Pure x) = return x
interpretTeletype (Free teletypeF) = runIO teletypeF >>= interpretTeletype

foldFree की परिभाषा केवल interpretTeletype , सिवाय इसके कि runIO फ़ंक्शन को runIO आउट किया गया है। नतीजतन, foldFree स्वतंत्र रूप से किसी विशेष बेस foldFree और किसी भी लक्ष्य foldFree काम करता है।

foldFree :: Monad m => (forall x. f x -> m x) -> Free f a -> m a
foldFree eta (Pure x) = return x
foldFree eta (Free fa) = eta fa >>= foldFree eta

foldFree का रैंक -2 प्रकार है: eta एक प्राकृतिक परिवर्तन है। हम foldFree एक प्रकार का foldFree Monad m => (f (Free fa) -> m (Free fa)) -> Free fa -> ma foldFree Monad m => (f (Free fa) -> m (Free fa)) -> Free fa -> ma , लेकिन इससे eta को f लेयर के अंदर Free कंपीटिशन का निरीक्षण करने की आज़ादी मिलती है। foldFree देते हुए यह अधिक प्रतिबंधक प्रकार सुनिश्चित करता है कि eta एक बार में एक ही परत को संसाधित कर सकता है।

iterM तह फ़ंक्शन को उप-विच्छेदन की जांच करने की क्षमता देता है। पिछले पुनरावृत्ति का (मानदिक) परिणाम f के पैरामीटर के अंदर, अगले के लिए उपलब्ध है। iterM एक के अनुरूप है paramorphism जबकि foldFree एक की तरह है catamorphism

iterM :: (Monad m, Functor f) => (f (m a) -> m a) -> Free f a -> m a
iterM phi (Pure x) = return x
iterM phi (Free fa) = phi (fmap (iterM phi) fa)

द फ्रीर मोनाड

फ्रीर (या प्रॉम्प्ट, या ऑपरेशनल) मोनड नामक मुक्त मोनाड का एक वैकल्पिक सूत्रीकरण है। फ़्रीर मोनड को अपने अंतर्निहित इंस्ट्रक्शन सेट के लिए फ़ंक्टर इंस्टेंस की आवश्यकता नहीं होती है, और इसमें मानक फ्री मोनाड की तुलना में अधिक पहचानी जाने वाली सूची जैसी संरचना होती है।

फ्रायर मोनाड निर्देश सेट i :: * -> * से संबंधित परमाणु निर्देशों के अनुक्रम के रूप में कार्यक्रमों का प्रतिनिधित्व करता है। प्रत्येक निर्देश अपने रिटर्न प्रकार को घोषित करने के लिए अपने पैरामीटर का उपयोग करता है। उदाहरण के लिए, State मठ के लिए आधार निर्देशों का सेट निम्नानुसार है:

data StateI s a where
    Get :: StateI s s  -- the Get instruction returns a value of type 's'
    Put :: s -> StateI s ()  -- the Put instruction contains an 's' as an argument and returns ()

इन निर्देशों पर विजय प्राप्त करना :>>= निर्माणकर्ता के साथ होता है। :>>= एक एकल निर्देश लौटाता है a और शेष कार्यक्रम में इसे जारी रखता है, इसकी वापसी मूल्य को जारी रखते हुए पाइप करता है। दूसरे शब्दों में, एक लौट रहा एक निर्देश दिए गए a , और एक समारोह एक चालू करने के लिए a एक लौटने एक कार्यक्रम में b , :>>= एक लौटने के लिए एक कार्यक्रम का उत्पादन करेगा b

data Freer i a where
    Return :: a -> Freer i a
    (:>>=) :: i a -> (a -> Freer i b) -> Freer i b

ध्यान दें कि a :>>= कंस्ट्रक्टर में मौजूद है। केवल एक दुभाषिया जानने के लिए क्या तरीका a है GADT पर पैटर्न मिलान कर रहा है i

एक तरफ : सह-योनेदा लेम्मा हमें बताती है कि Freer आइसोमॉर्फिक टू FreeCoYoneda functor की परिभाषा याद करें:

data CoYoneda i b where
  CoYoneda :: i a -> (a -> b) -> CoYoneda i b

Freer i , Free (CoYoneda i) बराबर है। यदि आप Free के कंस्ट्रक्टर लेते हैं और f ~ CoYoneda i सेट करते हैं, तो आपको मिलता है:

Pure :: a -> Free (CoYoneda i) a
Free :: CoYoneda i (Free (CoYoneda i) b) -> Free (CoYonda i) b ~
        i a -> (a -> Free (CoYoneda i) b) -> Free (CoYoneda i) b

जिससे हम ठीक हो सकता है Freer i बस की स्थापना द्वारा की कंस्ट्रक्टर्स Freer i ~ Free (CoYoneda i)

क्योंकि CoYoneda i एक है Functor किसी के लिए i , Freer एक है Monad से किसी के लिए i , भले ही i एक नहीं है Functor

instance Monad (Freer i) where
    return = Return
    Return x >>= f = f x
    (i :>>= g) >>= f = i :>>= fmap (>>= f) g  -- using `(->) r`'s instance of Functor, so fmap = (.)

कुछ हैंडलर मोनाड को निर्देश मैप करके Freer लिए दुभाषियों का निर्माण किया जा सकता है।

foldFreer :: Monad m => (forall x. i x -> m x) -> Freer i a -> m a
foldFreer eta (Return x) = return x
foldFreer eta (i :>>= f) = eta i >>= (foldFreer eta . f)

उदाहरण के लिए, हम एक Freer (StateI s) के रूप में रेगुलर State s Freer (StateI s) का उपयोग करके Freer (StateI s) व्याख्या कर सकते हैं:

runFreerState :: Freer (StateI s) a -> s -> (a, s)
runFreerState = State.runState . foldFreer toState
    where toState :: StateI s a -> State s a
          toState Get = State.get
          toState (Put x) = State.put x


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow