Haskell Language
मोनाड ट्रांसफॉर्मर
खोज…
एक मौद्रिक काउंटर
पाठक, लेखक, और मोनाड ट्रांसफॉर्मर का उपयोग करके राज्य को कैसे तैयार किया जाए, इस पर एक उदाहरण। स्रोत कोड इस रिपॉजिटरी में पाया जा सकता है
हम एक काउंटर लागू करना चाहते हैं, जो किसी दिए गए स्थिर द्वारा इसके मूल्य में वृद्धि करता है।
हम कुछ प्रकारों और कार्यों को परिभाषित करके शुरू करते हैं:
newtype Counter = MkCounter {cValue :: Int}
deriving (Show)
-- | 'inc c n' increments the counter by 'n' units.
inc :: Counter -> Int -> Counter
inc (MkCounter c) n = MkCounter (c + n)
मान लें कि हम काउंटर का उपयोग करके निम्नलिखित गणना करना चाहते हैं:
- काउंटर को 0 पर सेट करें
- 3 के लिए वृद्धि निरंतर सेट करें
- 3 बार वेतन वृद्धि
- 5 के लिए वेतन वृद्धि सेट करें
- 2 बार काउंटर बढ़ाएँ
राज्य का मठ राज्य के आसपास से गुजरने के लिए सार प्रदान करता है। हम राज्य मुद्रा का उपयोग कर सकते हैं, और एक राज्य ट्रांसफार्मर के रूप में हमारे वेतन वृद्धि समारोह को परिभाषित कर सकते हैं।
-- | CounterS is a monad.
type CounterS = State Counter
-- | Increment the counter by 'n' units.
incS :: Int-> CounterS ()
incS n = modify (\c -> inc c n)
यह पहले से ही एक अधिक स्पष्ट और संक्षिप्त तरीके से गणना व्यक्त करने में सक्षम बनाता है:
-- | The computation we want to run, with the state monad.
mComputationS :: CounterS ()
mComputationS = do
incS 3
incS 3
incS 3
incS 5
incS 5
लेकिन हमें अभी भी प्रत्येक आह्वान पर वेतन वृद्धि को पारित करना होगा। हम इससे बचना चाहेंगे।
एक वातावरण जोड़ना
रीडर मोनैड परिवेश को पारित करने के लिए एक सुविधाजनक तरीका प्रदान करता है। OO दुनिया में निर्भरता इंजेक्शन के रूप में जाना जाता है यह प्रदर्शन करने के लिए कार्यात्मक प्रोग्रामिंग में इस मोनड का उपयोग किया जाता है।
इसके सरलतम संस्करण में, पाठक को दो प्रकार की आवश्यकता होती है:
पढ़ा जा रहा मूल्य का प्रकार (अर्थात, हमारा पर्यावरण, नीचे
r
),मूल्य पाठक इकाई (द्वारा लौटाए गए
a
नीचे)।पाठक रा
हालांकि, हमें राज्य के रूप में अच्छी तरह से मठ का उपयोग करने की आवश्यकता है। इस प्रकार, हमें ReaderT
ट्रांसफार्मर का उपयोग करने की आवश्यकता है:
newtype ReaderT r m a :: * -> (* -> *) -> * -> *
ReaderT
का उपयोग करते ReaderT
, हम अपने काउंटर को पर्यावरण और राज्य के साथ परिभाषित कर सकते हैं:
type CounterRS = ReaderT Int CounterS
हम एक incR
फंक्शन को परिभाषित करते हैं जो incR
को निरंतर (पर्यावरण से ask
) लेता है, और अपने इन्क्रीमेंट फंक्शन को परिभाषित करने के लिए हमारे CounterS
monad के संदर्भ में हम lift
फंक्शन (जो कि monad ट्रांसफॉर्मर वर्ग का है) का उपयोग करते हैं।
-- | Increment the counter by the amount of units specified by the environment.
incR :: CounterRS ()
incR = ask >>= lift . incS
पाठक मोन का उपयोग करके हम अपनी गणना को इस प्रकार परिभाषित कर सकते हैं:
-- | The computation we want to run, using reader and state monads.
mComputationRS :: CounterRS ()
mComputationRS = do
local (const 3) $ do
incR
incR
incR
local (const 5) $ do
incR
incR
आवश्यकताएं बदल गईं: हमें लॉगिंग की आवश्यकता है!
अब मान लें कि हम अपने अभिकलन में लॉगिंग जोड़ना चाहते हैं, ताकि हम समय में अपने काउंटर के विकास को देख सकें।
इस कार्य को करने के लिए हमारे पास एक सन्यासी भी है, लेखक मोनाद । पाठक मोनाद के साथ, चूंकि हम उनकी रचना कर रहे हैं, हमें पाठक मोनाड ट्रांसफार्मर का उपयोग करने की आवश्यकता है:
newtype WriterT w m a :: * -> (* -> *) -> * -> *
यहाँ w
संचय करने के लिए आउटपुट के प्रकार का प्रतिनिधित्व करता है (जिसे एक मोनोइड होना चाहिए, जो हमें इस मान को संचित करने की अनुमति देता है), m
आंतरिक मोनड है, और a
प्रकार का अभिकलन।
फिर हम अपने काउंटर को लॉगिंग, पर्यावरण और स्थिति के साथ परिभाषित कर सकते हैं:
type CounterWRS = WriterT [Int] CounterRS
और lift
उपयोग करके हम वेतन वृद्धि के संस्करण को परिभाषित कर सकते हैं जो प्रत्येक वेतन वृद्धि के बाद काउंटर के मूल्य को लॉग करता है:
incW :: CounterWRS ()
incW = lift incR >> get >>= tell . (:[]) . cValue
अब अभिकलन जिसमें लॉगिंग शामिल है को निम्नानुसार लिखा जा सकता है:
mComputationWRS :: CounterWRS ()
mComputationWRS = do
local (const 3) $ do
incW
incW
incW
local (const 5) $ do
incW
incW
सब कुछ एक ही बार में करना
इस उदाहरण का उद्देश्य काम में मोनाड ट्रांसफार्मर को दिखाना है। हालांकि, हम एक ही वेतन वृद्धि ऑपरेशन में सभी पहलुओं (पर्यावरण, राज्य और लॉगिंग) की रचना करके एक ही प्रभाव प्राप्त कर सकते हैं।
ऐसा करने के लिए हम प्रकार-बाधाओं का उपयोग करते हैं:
inc' :: (MonadReader Int m, MonadState Counter m, MonadWriter [Int] m) => m ()
inc' = ask >>= modify . (flip inc) >> get >>= tell . (:[]) . cValue
यहां हम एक ऐसे समाधान पर पहुंचते हैं जो ऊपर की बाधाओं को पूरा करने वाले किसी भी मठ के लिए काम करेगा। गणना कार्य को इस प्रकार परिभाषित किया गया है:
mComputation' :: (MonadReader Int m, MonadState Counter m, MonadWriter [Int] m) => m ()
क्योंकि इसके शरीर में हम inc 'का उपयोग करते हैं।
हम इस गणना को, उदाहरण के लिए ghci
REPL में चला सकते हैं:
runState ( runReaderT ( runWriterT mComputation' ) 15 ) (MkCounter 0)