Haskell Language
नि: शुल्क मोनाडेस
खोज…
मुक्त मठों ने डेटा संरचनाओं और दुभाषियों में मौद्रिक संगणना को विभाजित किया
उदाहरण के लिए, प्रॉम्प्ट में प्रॉम्प्ट को पढ़ने और लिखने के लिए संकेत दिया जाता है:
पहले हम अपने गणना के "कमांड" को एक फ़ंक्शनल डेटा प्रकार के रूप में वर्णित करते हैं
{-# 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
कंस्ट्रक्टर के प्रकार की तुलना Fix
। Free
फ़िशर की तरह लेयर्स 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
आइसोमॉर्फिक टूFree
।CoYoneda
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