किन स्थितियों में liftIOउपयोग किया जाना चाहिए? जब मैं उपयोग कर रहा होता हूं ErrorT String IO, तो liftफ़ंक्शन IO क्रियाओं को ऊपर उठाने का काम करता है ErrorT, इसलिए liftIOयह बहुत ही अच्छा लगता है।
जवाबों:
liftहमेशा "पिछली" परत से लिफ्ट करता है। यदि आपको दूसरी परत से उठाने की आवश्यकता है, तो आपको आवश्यकता होगीlift . lift ।
दूसरी ओर, liftIOहमेशा IO परत से लिफ्ट करता है (जो, जब मौजूद होता है, हमेशा स्टैक के तल पर होता है)। इसलिए, यदि आपके पास भिक्षुओं की 2 से अधिक परतें हैं, तो आप सराहना करेंगे liftIO।
निम्नलिखित लंबों में तर्क के प्रकार की तुलना करें:
type T = ReaderT Int (WriterT String IO) Bool
> :t \x -> (lift x :: T)
\x -> (lift x :: T) :: WriterT String IO Bool -> T
> :t \x -> (liftIO x :: T)
\x -> (liftIO x :: T) :: IO Bool -> T
लिफ़्टियो, आईओ मोनाद का एक शॉर्टकट है, आप जिस भी मोनाड में हैं, मूल रूप से, लिफ़्टियो एक परिवर्तनीय संख्या में लिफ्टों का उपयोग करने के लिए बराबर है। सबसे पहले यह बेमानी लग सकता है, लेकिन लिफ़्टियो का उपयोग करने का एक बड़ा फायदा है: यह आपके आईओ कोड को वास्तविक मोनाड निर्माण के प्रति उदासीन बना देता है, ताकि आप उसी कोड का पुन: उपयोग कर सकें चाहे आपके अंतिम मोनाड की परत कितनी बनी हो (यह काफी महत्वपूर्ण है जब एक मोनड ट्रांसफार्मर लिख रहा हो)।
ओह्टर पर, लिफ्टियो मुफ्त में नहीं आ रहा है, जैसा कि लिफ्ट करता है: आपके द्वारा उपयोग किए जाने वाले मोनाड ट्रांसफार्मर इसके लिए समर्थन होना चाहिए, जैसे कि आप जिस मोनाड में होना चाहिए वह मोनाडिओ वर्ग का एक उदाहरण है, लेकिन आजकल अधिकांश मोनाड्स करते हैं (और निश्चित रूप से, टाइप-चेकर यह आपके लिए संकलन समय पर जाँच करेगा: यह हास्क की ताकत है)।
पिछले उत्तर सभी अंतर को अच्छी तरह से समझाते हैं। मैं सिर्फ आंतरिक कामकाज पर कुछ प्रकाश डालना चाहता था ताकि यह समझना आसान हो सके कि liftIOकुछ जादुई नहीं है (मेरे जैसे नौसिखिए हास्केलर्स के लिए)।
liftIO :: IO a -> m a
एक बुद्धिमान उपकरण है बस पर निर्माण
lift :: (Control.Monad.Trans.Class.MonadTrans t, Monad m) => m a -> t m a
और सबसे ज्यादा इस्तेमाल तब किया जाता है जब नीचे का मोनाड होता है IO। के लिए IOइकाई यह की परिभाषा काफी सरल है।
class (Monad m) => MonadIO m where
liftIO :: IO a -> m a
instance MonadIO IO where
liftIO = id
यही कारण है कि साधारण ... liftIOबस वास्तव में idके लिए IOइकाई और मूल रूप से IOकेवल एक ही है कि प्रकार वर्ग की परिभाषा के भीतर आता है।
बात यह है कि जब हमारे पास एक मोनाड प्रकार होता है, जो कि मोनाड ट्रांसफॉर्मर की कई परतों से बना होता है IO, तो हम बेहतर रूप MonadIOसे उन मोनाड ट्रांसफॉर्मर परतों में से प्रत्येक के लिए एक उदाहरण है। उदाहरण के लिए MonadIOके कहने MaybeT mकी आवश्यकता mका होना MonadIOऔर साथ ही typeclass।
एक MonadIOउदाहरण लिखना मूलतः एक बहुत सरल कार्य है। इसके लिए MaybeT mइसे परिभाषित किया गया है
instance (MonadIO m) => MonadIO (MaybeT m) where
liftIO = lift . liftIO
या के लिए StateT s m
instance (MonadIO m) => MonadIO (StateT s m) where
liftIO = lift . liftIO
वे सभी एक जैसे हैं। सोचिए जब आपके पास 4 लेयर का ट्रांसफार्मर स्टैक है तो आपको या तो करना होगा lift . lift . lift . lift $ myIOActionया बस liftIO myIOAction। यदि आप इसके बारे में सोचते हैं, तो हर lift . liftIOएक स्टैक में आपको एक परत नीचे ले जाएगा , जब तक कि वह नीचे सभी तरह से खोदता नहीं है IOजहां liftIOपर परिभाषित किया गया है idऔर liftऊपर दिए गए रचित s जैसे कोड के साथ अंतिम रूप देता है।
तो यह मूल रूप से ट्रांसफार्मर स्टैक कॉन्फ़िगरेशन की परवाह किए बिना है, बशर्ते कि सभी अंडरलेइंग परतें सदस्य हैं MonadIOऔर MonadTransएक ही liftIOठीक है।
liftIOIO परत को उठाने के लिए उपयोग करूंगा भले हीliftपर्याप्त हो, क्योंकि तब मैं मोनाड स्टैक को बदल सकता हूं और कोड अभी भी काम करता है।