शानदार सवाल!
ए मोनैड ट्रांसफार्मर एक प्रकार है जो मोनैड-नेस को संरक्षित करते समय मनमाने ढंग से आधार मोनैड में कुछ कार्यक्षमता जोड़ता है। अफसोस की बात है, मोनड ट्रांसफार्मर सी # में अप्रचलित हैं क्योंकि वे उच्च प्रकार के प्रकारों का आवश्यक उपयोग करते हैं। तो, हास्केल में काम करना,
class MonadTrans (t :: (* -> *) -> (* -> *)) where
lift :: Monad m => m a -> t m a
transform :: Monad m :- Monad (t m)
चलो लाइन के अनुसार इस लाइन पर जाएं। पहली पंक्ति घोषित करती है कि एक मोनड ट्रांसफॉर्मर एक प्रकार t
है, जो कि * -> *
(यानी, एक तर्क की अपेक्षा रखने वाला एक प्रकार) का तर्क लेता है और इसे किसी अन्य प्रकार के * -> *
में बदल देता है। जब आपको एहसास होता है कि सभी मोनैड्स में * -> *
है तो आप देख सकते हैं कि इरादा यह है कि t
मोनैड अन्य मोनैड में बदल जाता है।
अगली पंक्ति कहना है कि सभी इकाई ट्रांसफार्मर एक lift
ऑपरेशन है, जो एक मनमाना इकाई m
और लिफ्टों यह ट्रांसफार्मर की दुनिया में ले जाता है t m
समर्थन करना चाहिए।
अंत में, transform
विधि कहती है कि किसी भी monad m
, t m
भी एक मोनड होना चाहिए। मैं प्रक्षेपण ऑपरेटर :-
the constraints
package से उपयोग कर रहा हूं।
यह एक उदाहरण के साथ और अधिक समझ में आ जाएगा। यहां एक मोनैड ट्रांसफार्मर है जो Maybe
जोड़ता है-एक मनमानी आधार मोनैड m
पर। nothing
ऑपरेटर हमें गणना को निरस्त करने की अनुमति देता है।
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
nothing :: Monad m => MaybeT m a
nothing = MaybeT (return Nothing)
आदेश में MaybeT
के लिए एक इकाई के ट्रांसफार्मर होने के लिए, यह एक इकाई जब भी अपने तर्क एक इकाई है होना चाहिए।
instance Monad m => Monad (MaybeT m) where
return = MaybeT . return . Just
MaybeT m >>= f = MaybeT $ m >>= maybe (return Nothing) (runMaybeT . f)
अब MonadTrans
कार्यान्वयन लिखने के लिए। lift
के कार्यान्वयन को Just
में आधार मोनैड के वापसी मूल्य को लपेटता है। का कार्यान्वयन अनिच्छुक है; यह केवल जीएचसी के बाधा सॉल्वर को यह सत्यापित करने के लिए बताता है कि MaybeT
वास्तव में जब भी इसका तर्क होता है तो एक मोनड होता है।
instance MonadTrans MaybeT where
lift = MaybeT . fmap Just
transform = Sub Dict
अब हम एक monadic गणना जो MaybeT
का उपयोग करता है करने के लिए विफलता को जोड़ने के लिए, उदाहरण के लिए, State
इकाई लिख सकते हैं। lift
हमें मानक State
विधियों get
और put
का उपयोग करने की अनुमति देता है, लेकिन अगर हमें गणना में विफल होने की आवश्यकता है तो हमारे पास nothing
तक पहुंच भी है। (मैं IEnumerable
(उर्फ []
के अपने उदाहरण का उपयोग के बारे में सोचा है), लेकिन वहाँ कुछ एक इकाई जो पहले से ही इसका समर्थन करता है करने के लिए विफलता जोड़ने के बारे में विकृत है।)
example :: MaybeT (State Int)()
example = do
x <- lift get
if x < 0
then nothing
else lift $ put (x - 1)
क्या इकाई ट्रांसफार्मर वास्तव में उपयोगी बनाता है उनके stackability है। यह आपको एक क्षमता के साथ बहुत सारे मोनैडों में से कई क्षमताओं के साथ बड़े मोनैड लिखने की अनुमति देता है। उदाहरण के लिए, किसी दिए गए एप्लिकेशन को आईओ करने, कॉन्फ़िगरेशन चर पढ़ने और अपवाद फेंकने की आवश्यकता हो सकती है; इस तरह
type Application = ExceptT AppError (ReaderT AppConfig IO)
एक प्रकार से एन्कोड किया जाएगा वहाँ the mtl
package में उपकरण जो किसी दिए गए ढेर में सटीक संग्रह और इकाई ट्रांसफॉर्मर के आदेश से अधिक सार करने में मदद, आप lift
के लिए कॉल छिपाना करने की इजाजत दी है।
मुझे मोनैड के संयोजन का वास्तव में एक दिलचस्प संदर्भ मिला: http://heinrichapfelmus.github.com/operational/Documentation.html#alternatives-to-monad-transformers यह मोनाड्स के संयोजन के एक सामान्य तरीके की वकालत करता है। आपको यह पेपर भी पढ़ना चाहिए, यह वर्णन करता है कि कैसे डेटा प्रकारों को सामान्य और एक्स्टेंसिबल तरीके से जोड़ना है: http://www.cs.ru.nl/~wouters/Publications/DataTypesALaCarte.pdf –