Haskell Language
monads
खोज…
परिचय
एक मोनाड एक डेटा प्रकार की रचना करने योग्य क्रिया है। Monad
प्रकार के Monad
का वर्ग है, जिनके मूल्य ऐसे कार्यों का प्रतिनिधित्व करते हैं। शायद IO
सबसे ज्यादा पहचाने जाने योग्य है: IO a
का a
मूल्य "वास्तविक दुनिया से मूल्य प्राप्त करने के लिए एक नुस्खा है"।
हम कहते हैं कि एक टाइप कंस्ट्रक्टर m
(जैसे []
या Maybe
) एक मोनड बनाता है यदि एक instance Monad m
कुछ क्रियाओं की रचना के बारे में कुछ कानूनों को संतोषजनक करता है। फिर हम ma
बारे में एक "कार्रवाई जिसका परिणाम प्रकार a
" के रूप में कारण कर सकते हैं।
शायद मोनाड
Maybe
संभवतः खाली मूल्यों का प्रतिनिधित्व करने के लिए उपयोग किया जाता है - अन्य भाषाओं में null
समान। आमतौर पर इसका उपयोग आउटपुट प्रकार के कार्यों के रूप में किया जाता है जो किसी तरह से विफल हो सकते हैं।
निम्नलिखित कार्य पर विचार करें:
halve :: Int -> Maybe Int
halve x
| even x = Just (x `div` 2)
| odd x = Nothing
एक Int
आधार पर एक कार्रवाई के रूप में halve
बारे में सोचें, जो पूर्णांक को आधा करने की कोशिश करता है, अगर यह अजीब है तो विफल।
हम एक पूर्णांक को तीन बार halve
कैसे करते हैं?
takeOneEighth :: Int -> Maybe Int -- (after you read the 'do' sub-section:)
takeOneEighth x =
case halve x of -- do {
Nothing -> Nothing
Just oneHalf -> -- oneHalf <- halve x
case halve oneHalf of
Nothing -> Nothing
Just oneQuarter -> -- oneQuarter <- halve oneHalf
case halve oneQuarter of
Nothing -> Nothing -- oneEighth <- halve oneQuarter
Just oneEighth ->
Just oneEighth -- return oneEighth }
-
takeOneEighth
तीन का क्रम हैhalve
एक साथ श्रृंखलित चरणों। - एक तो
halve
कदम विफल रहता है, हम पूरी रचना चाहतेtakeOneEighth
विफल। - यदि एक
halve
कदम सफल होता है, तो हम इसके परिणाम को आगे बढ़ाना चाहते हैं।
instance Monad Maybe where
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
Nothing >>= f = Nothing -- infixl 1 >>=
Just x >>= f = Just (f x) -- also, f =<< m = m >>= f
-- return :: a -> Maybe a
return x = Just x
और अब हम लिख सकते हैं:
takeOneEighth :: Int -> Maybe Int
takeOneEighth x = halve x >>= halve >>= halve -- or,
-- return x >>= halve >>= halve >>= halve -- which is parsed as
-- (((return x) >>= halve) >>= halve) >>= halve -- which can also be written as
-- (halve =<<) . (halve =<<) . (halve =<<) $ return x -- or, equivalently, as
-- halve <=< halve <=< halve $ x
क्लेस्ली रचना <=<
के रूप में परिभाषित किया गया है (g <=< f) x = g =<< fx
, या समकक्ष के रूप में (f >=> g) x = fx >>= g
। इसके साथ उपरोक्त परिभाषा बस बन जाती है
takeOneEighth :: Int -> Maybe Int
takeOneEighth = halve <=< halve <=< halve -- infixr 1 <=<
-- or, equivalently,
-- halve >=> halve >=> halve -- infixr 1 >=>
तीन इकाई कानून है कि हर इकाई द्वारा पालन किया जाना चाहिए रहे हैं, कि हर प्रकार के जो का एक उदाहरण है है Monad
typeclass:
1. return x >>= f = f x
2. m >>= return = m
3. (m >>= g) >>= h = m >>= (\y -> g y >>= h)
जहाँ m
एक मोनड है, f
में टाइप a -> mb
और g
है टाइप b -> mc
।
या समकक्ष, ऊपर परिभाषित >=>
क्लेसीली रचना ऑपरेटर का उपयोग करते हुए:
1. return >=> g = g -- do { y <- return x ; g y } == g x
2. f >=> return = f -- do { y <- f x ; return y } == f x
3. (f >=> g) >=> h = f >=> (g >=> h) -- do { z <- do { y <- f x; g y } ; h z }
-- == do { y <- f x ; do { z <- g y; h z } }
इन कानूनों का पालन करना मठ के बारे में तर्क करना बहुत आसान बनाता है, क्योंकि यह गारंटी देता है कि अन्य मठों के समान ही, मठ के कार्यों का उपयोग करना और उनका उचित तरीके से व्यवहार करना।
आइए देखें कि क्या Maybe
मोनद तीन मानद कानूनों का पालन करता है।
- बाईं पहचान विधि -
return x >>= f = fx
return z >>= f
= (Just z) >>= f
= f z
- सही पहचान कानून -
m >>= return = m
-
Just
डेटा कंस्ट्रक्टर
Just z >>= return
= return z
= Just z
-
Nothing
डेटा कंस्ट्रक्टर नहीं
Nothing >>= return
= Nothing
- संबद्धता कानून -
(m >>= f) >>= g = m >>= (\x -> fx >>= g)
-
Just
डेटा कंस्ट्रक्टर
-- Left-hand side
((Just z) >>= f) >>= g
= f z >>= g
-- Right-hand side
(Just z) >>= (\x -> f x >>= g)
(\x -> f x >>= g) z
= f z >>= g
-
Nothing
डेटा कंस्ट्रक्टर नहीं
-- Left-hand side
(Nothing >>= f) >>= g
= Nothing >>= g
= Nothing
-- Right-hand side
Nothing >>= (\x -> f x >>= g)
= Nothing
आईओ मोनाद
प्रकार का एक मूल्य प्राप्त करने का कोई तरीका नहीं है a
प्रकार की अभिव्यक्ति से बाहर IO a
और वहाँ नहीं होना चाहिए। यह वास्तव में IO
को मॉडल करने के लिए मठों का उपयोग करने का एक बड़ा हिस्सा है।
IO a
प्रकार की अभिव्यक्ति के बारे में सोचा जा सकता है जो एक ऐसी क्रिया का प्रतिनिधित्व करता है जो वास्तविक दुनिया के साथ बातचीत कर सकता है और यदि निष्पादित किया जाता है, तो परिणाम कुछ प्रकार a
। उदाहरण के लिए, फ़ंक्शन getLine :: IO String
प्रस्ताव से getLine :: IO String
मतलब यह नहीं है कि getLine
नीचे कुछ विशिष्ट स्ट्रिंग है जिसे मैं निकाल सकता हूं - इसका मतलब है कि getLine
मानक इनपुट से लाइन प्राप्त करने की क्रिया का प्रतिनिधित्व करता है।
आश्चर्य की बात नहीं, main :: IO ()
चूंकि हास्केल कार्यक्रम एक गणना / कार्रवाई का प्रतिनिधित्व करता है जो वास्तविक दुनिया के साथ बातचीत करता है।
चीजें जो आप टाइप IO a
भावों को कर सकते हैं क्योंकि IO
एक सन्यासी है:
पहली क्रिया को निष्पादित करने वाली नई क्रिया का उपयोग करने के लिए
(>>)
दो क्रियाओं को अनुक्रमित करें, जो भी उत्पादन किया गया है, और फिर दूसरी क्रिया को निष्पादित करता है।-- print the lines "Hello" then "World" to stdout putStrLn "Hello" >> putStrLn "World"
कभी-कभी आप उस मूल्य को नहीं छोड़ना चाहते हैं जो पहली कार्रवाई में उत्पन्न हुआ था - आप वास्तव में इसे एक दूसरी कार्रवाई में खिलाया जाना पसंद करेंगे। उसके लिए हमारे पास
>>=
।IO
, यह टाइप(>>=) :: IO a -> (a -> IO b) -> IO b
।-- get a line from stdin and print it back out getLine >>= putStrLn
एक सामान्य मूल्य लें और इसे एक ऐसी क्रिया में परिवर्तित करें, जो आपके द्वारा दिए गए मूल्य को तुरंत वापस कर देती है। यह फ़ंक्शन कम स्पष्ट रूप से उपयोगी है जब तक आप नोटेशन का उपयोग
do
शुरू नहीं करतेdo
।-- make an action that just returns 5 return 5
यहाँ IO मठ पर हास्केल विकी से अधिक।
सूची में मोनाड
सूचियों में एक सनक होती है। उनके पास इस के बराबर एक मौन तात्कालिकता है:
instance Monad [] where return x = [x] xs >>= f = concat (map f xs)
हम अपनी गणनाओं में गैर-नियतत्ववाद का अनुकरण करने के लिए उनका उपयोग कर सकते हैं। हम उपयोग करते हैं xs >>= f
, समारोह f :: a -> [b]
सूची पर मैप किया गया है xs
, में से प्रत्येक आवेदन के परिणामों की सूची की एक सूची प्राप्त करने के f
के प्रत्येक तत्व से अधिक xs
, और के सभी सूचियों परिणाम तब सभी परिणामों की एक सूची में सम्मिलित किए जाते हैं। एक उदाहरण के रूप में, हम दो गैर-नियतात्मक संख्याओं का योग करते हैं, जो संकेतन का उपयोग करते हैं, दो सूचियों से पूर्णांकों के सभी युग्मों की सूची द्वारा प्रतिनिधित्व की जाने वाली राशि, प्रत्येक सूची एक गैर-निर्धारक संख्या के सभी संभावित मूल्यों का प्रतिनिधित्व करती है:
sumnd xs ys = do
x <- xs
y <- ys
return (x + y)
या समतुल्य का उपयोग कर liftM2
में Control.Monad
:
sumnd = liftM2 (+)
हमने प्राप्त किया:
> sumnd [1,2,3] [0,10]
[1,11,2,12,3,13]
मोनाद को उपप्रधान के रूप में
GHC 7.10 के रूप में, Applicative
की एक सुपर क्लास है Monad
(यानी, हर प्रकार के जो एक है Monad
भी एक होना चाहिए Applicative
)। सभी के तरीकों Applicative
( pure
, <*>
) के तरीके के मामले में लागू किया जा सकता Monad
( return
, >>=
)।
यह स्पष्ट है कि pure
और return
समान उद्देश्यों की सेवा करते हैं, इसलिए pure = return
। <*>
की परिभाषा बहुत अपेक्षाकृत स्पष्ट है:
mf <*> mx = do { f <- mf; x <- mx; return (f x) }
-- = mf >>= (\f -> mx >>= (\x -> return (f x)))
-- = [r | f <- mf, x <- mx, r <- return (f x)] -- with MonadComprehensions
-- = [f x | f <- mf, x <- mx]
यह कार्य मानक पुस्तकालयों में ap
रूप में परिभाषित किया गया है।
इस प्रकार यदि आप पहले से ही एक प्रकार के लिए Monad
का एक उदाहरण परिभाषित कर चुके हैं, तो आप प्रभावी रूप से इसके लिए "मुफ्त में" के लिए Applicative
का एक उदाहरण प्राप्त कर सकते हैं
instance Applicative < type > where
pure = return
(<*>) = ap
जैसा कि मोनाड कानूनों के साथ होता है, ये समानताएं लागू नहीं होती हैं, लेकिन डेवलपर्स को यह सुनिश्चित करना चाहिए कि वे हमेशा बरकरार रहें।
एक सामान्य गणना से मान निकालने का कोई सामान्य तरीका नहीं है
आप कार्यों में मूल्यों को लपेट सकते हैं और एक संगणना के परिणाम को दूसरे में डाल सकते हैं:
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
हालाँकि, एक मोनाद की परिभाषा मोनाद के प्रकार के अस्तित्व की गारंटी नहीं देती है Monad m => ma -> a
।
इसका मतलब है कि सामान्य तौर पर, एक संगणना से मूल्य निकालने का कोई तरीका नहीं है (यानी "इसे अनचेक करें")। यह कई उदाहरणों के लिए मामला है:
extract :: Maybe a -> a
extract (Just x) = x -- Sure, this works, but...
extract Nothing = undefined -- We can’t extract a value from failure.
विशेष रूप से, कोई कार्य नहीं है IO a -> a
, जो अक्सर शुरुआती को भ्रमित करता है; इस उदाहरण को देखें।
कर-अंकन
do
-notation मोनाड्स के लिए सिंटैक्टिक शुगर है। ये नियम हैं:
do x <- mx do x <- mx y <- my is equivalent to do y <- my ... ...
do let a = b let a = b in ... is equivalent to do ...
do m m >> ( e is equivalent to e)
do x <- m m >>= (\x -> e is equivalent to e)
do m is equivalent to m
उदाहरण के लिए, ये परिभाषाएँ समकक्ष हैं:
example :: IO Integer
example =
putStrLn "What's your name?" >> (
getLine >>= (\name ->
putStrLn ("Hello, " ++ name ++ ".") >> (
putStrLn "What should we return?" >> (
getLine >>= (\line ->
let n = (read line :: Integer) in
return (n + n))))))
example :: IO Integer
example = do
putStrLn "What's your name?"
name <- getLine
putStrLn ("Hello, " ++ name ++ ".")
putStrLn "What should we return?"
line <- getLine
let n = (read line :: Integer)
return (n + n)
मोनाद की परिभाषा
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
मोनाड्स से निपटने के लिए सबसे महत्वपूर्ण कार्य बाँध ऑपरेटर है >>=
:
(>>=) :: m a -> (a -> m b) -> m b
- के बारे में सोचो
ma
"एक साथ एक कार्रवाई के रूप मेंa
परिणाम"। - एक
b
परिणाम के साथa -> mb
रूप में "एक कार्रवाई (a
पैरामीटर के आधार पर) के बारे में सोचो ।" ।
>>=
पहली क्रिया से दूसरे तक परिणाम को पाइप करके दो क्रियाओं को एक साथ करता है।
Monad
द्वारा परिभाषित अन्य कार्य है:
return :: a -> m a
इसका नाम दुर्भाग्यपूर्ण है: इस return
का अनिवार्य प्रोग्रामिंग भाषाओं में पाए गए return
कीवर्ड से कोई लेना-देना नहीं है।
return x
इसके परिणाम के रूप में तुच्छ क्रिया उपज x
। (यह निम्नलिखित अर्थों में तुच्छ है :)
return x >>= f ≡ f x -- “left identity” monad law
x >>= return ≡ x -- “right identity” monad law