बेंजामिन पियर्स ने TAPL में कहा
एक प्रकार की प्रणाली को एक कार्यक्रम में शर्तों के रन-टाइम व्यवहारों के लिए एक प्रकार के स्थैतिक सन्निकटन की गणना के रूप में माना जा सकता है।
इसीलिए एक खराब टाइप की भाषा की तुलना में एक शक्तिशाली प्रकार की प्रणाली से लैस भाषा कड़ाई से अधिक अभिव्यंजक है। आप उसी तरह से भिक्षुओं के बारे में सोच सकते हैं।
@Carl और sigfpe बिंदु के रूप में, आप उन सभी प्रचालनों के साथ डेटाटाइप को लैस कर सकते हैं, जिन्हें आप मोनाड्स, टाइपकालेज़ या जो भी अन्य सार सामान का सहारा लिए बिना चाहते हैं। हालांकि मोनैडस आपको न केवल पुन: प्रयोज्य कोड लिखने की अनुमति देता है, बल्कि सभी निरर्थक विवरणों का सार भी देता है।
एक उदाहरण के रूप में, मान लें कि हम किसी सूची को फ़िल्टर करना चाहते हैं। filter
फ़ंक्शन का उपयोग करने का सबसे सरल तरीका है :, filter (> 3) [1..10]
जो बराबर है [4,5,6,7,8,9,10]
।
का थोड़ा और अधिक जटिल संस्करण filter
, जो बाएं से दाएं एक संचायक भी गुजरता है, है
swap (x, y) = (y, x)
(.*) = (.) . (.)
filterAccum :: (a -> b -> (Bool, a)) -> a -> [b] -> [b]
filterAccum f a xs = [x | (x, True) <- zip xs $ snd $ mapAccumL (swap .* f) a xs]
सभी प्राप्त करने के लिए i
, कि इस तरह के i <= 10, sum [1..i] > 4, sum [1..i] < 25
, हम लिख सकते
filterAccum (\a x -> let a' = a + x in (a' > 4 && a' < 25, a')) 0 [1..10]
जो बराबर है [3,4,5,6]
।
या हम उस nub
फ़ंक्शन को पुनर्परिभाषित कर सकते हैं , जो सूची से डुप्लिकेट तत्वों को हटाता है filterAccum
: के संदर्भ में
nub' = filterAccum (\a x -> (x `notElem` a, x:a)) []
nub' [1,2,4,5,4,3,1,8,9,4]
बराबर होता है [1,2,4,5,3,8,9]
। एक सूची यहां एक संचायक के रूप में पारित की जाती है। कोड काम करता है, क्योंकि सूची में मोनड को छोड़ना संभव है, इसलिए पूरी गणना शुद्ध रहती है ( वास्तव में notElem
उपयोग नहीं करता है >>=
, लेकिन यह हो सकता है)। हालाँकि, IO मोनड को सुरक्षित रूप से छोड़ना संभव नहीं है (अर्थात आप IO क्रिया को निष्पादित नहीं कर सकते हैं और शुद्ध मान लौटा सकते हैं - मान हमेशा IO मुद्रा में लिपटा रहेगा)। एक अन्य उदाहरण परस्पर सारणी है: जब आप ST मोनाड को लीकेज कर लेते हैं, जहां एक उत्परिवर्तित सरणी रहते हैं, आप सरणी को निरंतर समय में अपडेट नहीं कर सकते। इसलिए हमें Control.Monad
मॉड्यूल से एक मानद फ़िल्टरिंग की आवश्यकता है :
filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
filterM _ [] = return []
filterM p (x:xs) = do
flg <- p x
ys <- filterM p xs
return (if flg then x:ys else ys)
filterM
एक सूची से सभी तत्वों के लिए एक राक्षसी कार्रवाई को निष्पादित करता है, तत्वों की पैदावार करता है, जिसके लिए राक्षसी कार्रवाई वापस आती है True
।
एक सरणी के साथ एक फ़िल्टरिंग उदाहरण:
nub' xs = runST $ do
arr <- newArray (1, 9) True :: ST s (STUArray s Int Bool)
let p i = readArray arr i <* writeArray arr i False
filterM p xs
main = print $ nub' [1,2,4,5,4,3,1,8,9,4]
[1,2,4,5,3,8,9]
उम्मीद के मुताबिक प्रिंट ।
और IO मोनाद के साथ एक संस्करण, जो पूछता है कि किन तत्वों को वापस लौटना है:
main = filterM p [1,2,4,5] >>= print where
p i = putStrLn ("return " ++ show i ++ "?") *> readLn
उदाहरण के लिए
return 1? -- output
True -- input
return 2?
False
return 4?
False
return 5?
True
[1,5] -- output
और अंतिम दृष्टांत के filterAccum
रूप में, के संदर्भ में परिभाषित किया जा सकता है filterM
:
filterAccum f a xs = evalState (filterM (state . flip f) xs) a
StateT
मठ के साथ , कि हुड के तहत प्रयोग किया जाता है, सिर्फ एक साधारण डेटाटाइप होने के नाते।
यह उदाहरण दिखाता है, कि मोनड्स न केवल आपको सारगर्भित संदर्भ देने की अनुमति देते हैं और स्वच्छ पुन: प्रयोज्य कोड लिखते हैं (क्योंकि मोनडर्स की रचनाशीलता के कारण @Carl बताते हैं), लेकिन यह भी उपयोगकर्ता-परिभाषित डेटाटाइप्स और अंतर्निहित प्राइमेटिव्स को समान रूप से व्यवहार करने के लिए।