मैं इस प्रश्न का उत्तर देने के लिए एक अधिक व्यवस्थित दृष्टिकोण का प्रस्ताव करना चाहता हूं, और ऐसे उदाहरण भी दिखाना चाहता हूं जो "नीचे" मान या अनंत डेटा प्रकार या उस जैसे कुछ भी विशेष चाल का उपयोग न करें।
टाइप कंस्ट्रक्टर कब टाइप करने के लिए असफल होते हैं?
सामान्य तौर पर, दो प्रकार के कारण एक प्रकार के निर्माणकर्ता एक निश्चित प्रकार के वर्ग की आवृत्ति के लिए असफल हो सकते हैं:
- प्रकार वर्ग से आवश्यक विधियों के प्रकार हस्ताक्षर को लागू नहीं कर सकते।
- प्रकार के हस्ताक्षर लागू कर सकते हैं लेकिन आवश्यक कानूनों को पूरा नहीं कर सकते।
पहली तरह के उदाहरण दूसरी तरह के लोगों की तुलना में आसान होते हैं क्योंकि पहली तरह के लिए, हमें सिर्फ यह जांचने की जरूरत है कि क्या कोई फ़ंक्शन किसी दिए गए प्रकार के हस्ताक्षर के साथ लागू कर सकता है, जबकि दूसरी तरह के लिए, हमें यह साबित करना होगा कि कोई कार्यान्वयन नहीं है संभवतः कानूनों को संतुष्ट कर सकता है।
विशिष्ट उदाहरण
यह एक कॉन्ट्रैक्टर है, न कि किसी फंक्शनलर के साथ, टाइप पैरामीटर के संबंध में a
, क्योंकि a
एक कॉन्ट्रैवियरी स्थिति में है। प्रकार हस्ताक्षर के साथ एक फ़ंक्शन को लागू करना असंभव है (a -> b) -> F z a -> F z b
।
एक प्रकार का कंस्ट्रक्टर, जो कानूनन फ़नकार नहीं है, भले ही उसके प्रकार के हस्ताक्षर fmap
लागू किए जा सकते हैं:
data Q a = Q(a -> Int, a)
fmap :: (a -> b) -> Q a -> Q b
fmap f (Q(g, x)) = Q(\_ -> g x, f x) -- this fails the functor laws!
इस उदाहरण का जिज्ञासु पहलू यह है कि हम सही प्रकार का कार्यान्वयन कर सकते हैं fmap
, भले ही F
संभवतः एक फ़नकार नहीं हो सकता है क्योंकि यह a
एक कंट्राविरेंट स्थिति में उपयोग करता है। तो fmap
ऊपर दिखाया गया यह कार्यान्वयन भ्रामक है - भले ही इसके पास सही प्रकार के हस्ताक्षर हों (मेरा मानना है कि यह उस प्रकार के हस्ताक्षर का एकमात्र संभव कार्यान्वयन है), फ़नकार कानून संतुष्ट नहीं हैं। उदाहरण के लिए, fmap id
≠ id
, क्योंकि let (Q(f,_)) = fmap id (Q(read,"123")) in f "456"
है 123
, लेकिन let (Q(f,_)) = id (Q(read,"123")) in f "456"
है 456
।
वास्तव में, F
केवल एक प्रोफेसर है, - यह न तो एक फनकार है और न ही एक कॉन्ट्रैक्टर है।
एक कानूनन फ़नकार जो लागू नहीं होता है क्योंकि उस प्रकार के हस्ताक्षर को pure
लागू नहीं किया जा सकता है: राइटर मोनाड को लें (a, w)
और w
एक मोहरा होना चाहिए कि बाधा को हटा दें । इसके बाद (a, w)
बाहर से मूल्य का निर्माण करना असंभव है a
।
एक फ़नकार जो कि आवेदक नहीं है क्योंकि उस प्रकार के हस्ताक्षर को <*>
लागू नहीं किया जा सकता है data F a = Either (Int -> a) (String -> a)
:।
एक फ़नकार जो क़ानूनी रूप से लागू नहीं है, भले ही टाइप क्लास के तरीके लागू किए जा सकते हैं:
data P a = P ((a -> Int) -> Maybe a)
टाइप कंस्ट्रक्टर P
एक फन्नेकार है क्योंकि यह a
केवल सहसंयोजक पदों में उपयोग करता है ।
instance Functor P where
fmap :: (a -> b) -> P a -> P b
fmap fab (P pa) = P (\q -> fmap fab $ pa (q . fab))
के प्रकार के हस्ताक्षर का एकमात्र संभावित कार्यान्वयन <*>
एक ऐसा कार्य है जो हमेशा लौटता है Nothing
:
(<*>) :: P (a -> b) -> P a -> P b
(P pfab) <*> (P pa) = \_ -> Nothing -- fails the laws!
लेकिन यह कार्यान्वयन आवेदक फंक्शनलर्स के लिए पहचान कानून को संतुष्ट नहीं करता है।
- एक फ़नकार जो कि ऐसा
Applicative
नहीं है,Monad
क्योंकि टाइप हस्ताक्षर bind
लागू नहीं किया जा सकता है।
मैं ऐसे किसी भी उदाहरण को नहीं जानता!
- एक फ़नकार जो कि ऐसा
Applicative
नहीं है,Monad
क्योंकि एक क़ानून को संतुष्ट नहीं किया जा सकता, भले ही उस प्रकार के हस्ताक्षर को bind
लागू किया जा सके।
इस उदाहरण ने काफी चर्चा पैदा की है, इसलिए यह कहना सुरक्षित है कि इस उदाहरण को सही साबित करना आसान नहीं है। लेकिन कई लोगों ने अलग-अलग तरीकों से इसे स्वतंत्र रूप से सत्यापित किया है। देखें `डेटा पीओई ए = खाली | जोड़ी आ` मोनाद? अतिरिक्त चर्चा के लिए।
data B a = Maybe (a, a)
deriving Functor
instance Applicative B where
pure x = Just (x, x)
b1 <*> b2 = case (b1, b2) of
(Just (x1, y1), Just (x2, y2)) -> Just((x1, x2), (y1, y2))
_ -> Nothing
यह साबित करना थोड़ा बोझिल है कि कोई कानूनन Monad
उदाहरण नहीं है। गैर-मौद्रिक व्यवहार का कारण यह है कि bind
जब कोई फ़ंक्शन f :: a -> B b
वापस आ सकता है Nothing
या Just
विभिन्न मूल्यों के लिए लागू करने का कोई प्राकृतिक तरीका नहीं है a
।
यह विचार करना शायद स्पष्ट है Maybe (a, a, a)
, जो एक सन्यासी भी नहीं है, और इसके लिए कार्यान्वयन करने का प्रयास करना join
है। कोई यह पाएगा कि लागू करने का कोई सहज तरीका नहीं है join
।
join :: Maybe (Maybe (a, a, a), Maybe (a, a, a), Maybe (a, a, a)) -> Maybe (a, a, a)
join Nothing = Nothing
join Just (Nothing, Just (x1,x2,x3), Just (y1,y2,y3)) = ???
join Just (Just (x1,x2,x3), Nothing, Just (y1,y2,y3)) = ???
-- etc.
द्वारा इंगित मामलों में ???
, यह स्पष्ट लगता है कि हम Just (z1, z2, z3)
छह अलग-अलग प्रकार के मूल्यों में से किसी भी उचित और सममित तरीके से उत्पादन नहीं कर सकते हैं a
। हम निश्चित रूप से इन छह मूल्यों में से कुछ मनमाना उपसमुच्चय चुन सकते हैं, उदाहरण के लिए, हमेशा पहली गैर Maybe
- रिक्तता लें - लेकिन यह मठ के कानूनों को संतुष्ट नहीं करेगा। लौटना Nothing
भी कानूनों को संतुष्ट नहीं करेगा।
- एक पेड़ की तरह डेटा संरचना जो एक सन्यासी नहीं है, भले ही इसके लिए सहानुभूति हो
bind
- लेकिन पहचान कानूनों को विफल करता है।
सामान्य वृक्ष के समान मोनाड (या "फ़नकार के आकार की शाखाओं वाला वृक्ष") के रूप में परिभाषित किया गया है
data Tr f a = Leaf a | Branch (f (Tr f a))
यह फन्नेकार पर एक स्वतंत्र मोनाड है f
। डेटा का आकार एक पेड़ है जहां प्रत्येक शाखा बिंदु उपप्रकारों का एक "फंक्टर-फुल" है। मानक बाइनरी ट्री के साथ प्राप्त किया जाएगा type f a = (a, a)
।
यदि हम इस डेटा संरचना को f
फंक्शनल के आकार में भी बनाकर संशोधित करते हैं , तो हम उसे "सेमिमोनड" कहते हैं - bind
जो कि स्वाभाविकता और सहानुभूति कानूनों को संतुष्ट करता है, लेकिन इसकी pure
विधि पहचान कानूनों में से एक को विफल करती है। "सेमीमोनड एंडोफ़ुन्क्टरों की श्रेणी में अर्धवृत्त हैं, समस्या क्या है?" यह प्रकार वर्ग है Bind
।
सादगी के लिए, मैं join
इसके बजाय विधि को परिभाषित करता हूं bind
:
data Trs f a = Leaf (f a) | Branch (f (Trs f a))
join :: Trs f (Trs f a) -> Trs f a
join (Leaf ftrs) = Branch ftrs
join (Branch ftrstrs) = Branch (fmap @f join ftrstrs)
शाखा ग्राफ्टिंग मानक है, लेकिन पत्ती ग्राफ्टिंग गैर मानक है और एक उत्पादन करती है Branch
। यह संबद्धता कानून के लिए कोई समस्या नहीं है, लेकिन पहचान कानूनों में से एक को तोड़ देता है।
बहुपद के प्रकार कब होते हैं?
न तो फंक्शनलर्स Maybe (a, a)
और न ही Maybe (a, a, a)
उन्हें कोई कानूनी Monad
उदाहरण दिया जा सकता है , हालांकि वे स्पष्ट रूप से हैं Applicative
।
कोई - ये functors कोई चाल है Void
या bottom
कहीं भी, कोई मुश्किल आलस्य / कठोरता, कोई अनंत संरचनाओं, और कोई प्रकार वर्ग की कमी। Applicative
उदाहरण के लिए पूरी तरह से मानक है। फ़ंक्शंस return
और bind
इन फंक्शनलर्स के लिए लागू किया जा सकता है लेकिन मोनाड के कानूनों को संतुष्ट नहीं करेगा। दूसरे शब्दों में, ये फ़ंक्शनलर्स मोनड्स नहीं हैं क्योंकि एक विशिष्ट संरचना गायब है (लेकिन यह समझना आसान नहीं है कि वास्तव में क्या गायब है)। एक उदाहरण के रूप में, फ़नकार में एक छोटा परिवर्तन इसे एक सनक में बना सकता है: data Maybe a = Nothing | Just a
एक सन्यासी है। इसी तरह का एक अन्य फ़नकार data P12 a = Either a (a, a)
भी एक सन्यासी है।
बहुपद संन्यासियों के लिए निर्माण
सामान्य तौर पर, यहां कुछ निर्माण हैं जो Monad
बहुपद प्रकारों से वैध एस का उत्पादन करते हैं। इन सभी निर्माणों में, M
एक मठ है:
type M a = Either c (w, a)
w
कोई भी मोनोड कहां है
type M a = m (Either c (w, a))
जहां m
कोई भी साधु है और w
कोई भी भिक्षु है
type M a = (m1 a, m2 a)
कहाँ m1
और m2
कोई भी सन्यासी हैं
type M a = Either a (m a)
जहां m
किसी भी इकाई है
पहला निर्माण है WriterT w (Either c)
, दूसरा निर्माण है WriterT w (EitherT c m)
। तीसरे निर्माण monads के एक घटक के लिहाज से उत्पाद है: pure @M
के घटक-वार उत्पाद के रूप में परिभाषित किया गया है pure @m1
और pure @m2
, और join @M
पार उत्पाद डेटा को छोड़ते हुए (जैसे द्वारा परिभाषित किया गया है m1 (m1 a, m2 a)
करने के लिए मैप किया गया है m1 (m1 a)
टपल के दूसरे भाग को छोड़ते हुए से):
join :: (m1 (m1 a, m2 a), m2 (m1 a, m2 a)) -> (m1 a, m2 a)
join (m1x, m2x) = (join @m1 (fmap fst m1x), join @m2 (fmap snd m2x))
चौथे निर्माण के रूप में परिभाषित किया गया है
data M m a = Either a (m a)
instance Monad m => Monad M m where
pure x = Left x
join :: Either (M m a) (m (M m a)) -> M m a
join (Left mma) = mma
join (Right me) = Right $ join @m $ fmap @m squash me where
squash :: M m a -> m a
squash (Left x) = pure @m x
squash (Right ma) = ma
मैंने जाँच की है कि सभी चार निर्माण वैध भिक्षुओं का उत्पादन करते हैं।
मैं अनुमान लगाता हूं कि बहुपद मठों के लिए कोई अन्य निर्माण नहीं हैं। उदाहरण के लिए, फ़नकार Maybe (Either (a, a) (a, a, a, a))
को इनमें से किसी भी निर्माण के माध्यम से प्राप्त नहीं किया जाता है और इसलिए यह अस्वच्छ नहीं है। हालांकि, Either (a, a) (a, a, a)
क्योंकि यह तीन monads के उत्पाद isomorphic को है monadic है a
, a
, और Maybe a
। इसके अलावा, Either (a,a) (a,a,a,a)
क्योंकि इसके बारे में उत्पाद isomorphic को है monadic है a
और Either a (a, a, a)
।
ऊपर दिखाए गए चार निर्माण हमें किसी भी संख्या के किसी भी उत्पाद के किसी भी राशि को प्राप्त करने की अनुमति देंगे a
, उदाहरण के लिए Either (Either (a, a) (a, a, a, a)) (a, a, a, a, a))
और इसी तरह। ऐसे सभी प्रकार के निर्माणकर्ताओं के पास (कम से कम एक) Monad
उदाहरण होगा।
यह देखा जाना चाहिए, निश्चित रूप से, ऐसे साधुओं के लिए कौन से उपयोग के मामले मौजूद हो सकते हैं। एक और मुद्दा यह है कि Monad
1-4 निर्माण के माध्यम से प्राप्त उदाहरण सामान्य रूप से अद्वितीय नहीं हैं। उदाहरण के लिए, टाइप कंस्ट्रक्टर type F a = Either a (a, a)
को Monad
दो तरीकों से एक उदाहरण दिया जा सकता है: निर्माण 4 में मोनड का उपयोग करके (a, a)
, और निर्माण 3 का उपयोग आइसोमॉर्फिज्म द्वारा किया जाता है Either a (a, a) = (a, Maybe a)
। फिर, इन कार्यान्वयनों के लिए उपयोग के मामलों को खोजना तुरंत स्पष्ट नहीं है।
एक सवाल बना हुआ है - एक मनमाना बहुपद डेटा प्रकार दिया गया है, यह कैसे पहचाना जाए कि उसका कोई Monad
उदाहरण है। मुझे नहीं पता कि कैसे साबित करना है कि बहुपद मोनाड्स के लिए कोई अन्य निर्माण नहीं हैं। मुझे नहीं लगता कि इस प्रश्न का उत्तर देने के लिए कोई सिद्धांत अभी तक मौजूद है।
* -> *
) जिसके लिए कोई उपयुक्त नहीं हैfmap
?