{-# LANGUAGE LambdaCase #-}
टाइपक्लास के उदाहरणों के रूप में कार्य?
मेरे पास कई तरीकों से विफलता को एन्कोड करने वाले कार्यों का एक समूह है।
f :: A -> Bool
रिटर्न विफलता परFalse
विफलता परg :: B -> Maybe B'
रिटर्नNothing
h :: C -> Either Error C'
रिटर्नLeft ...
विफलता पर
मैं श्रृंखला के लिए Maybe
इकाई के रूप में एक ही तरीके से इन आपरेशनों हैं: उदाहरण के लिए , इसलिए चेनिंग फ़ंक्शन को यह जानने की आवश्यकता है कि प्रत्येक फ़ंक्शन अगले पर जाने से पहले विफल रहा है या नहीं। इस के लिए मैं इस वर्ग ने लिखा है:
class Fail a where
isFail :: a -> Bool
instance Fail() where
isFail() = False
instance Fail Bool where -- a
isFail = not
instance Fail (Maybe a) where -- b
isFail = not . isJust
instance Fail (Either a b) where -- c
isFail (Left _) = True
isFail _ = False
हालांकि, यह संभव है कि कार्यों कि अनुरूप नहीं है मौजूद हैं:
f' :: A -> Bool
रिटर्न विफलता परTrue
विफलता परg' :: B -> Maybe Error
रिटर्नJust Error
(Nothing
सफलता पर)h' :: C -> Either C' Error
विफलता पर
ये बस उन्हें कार्यों है कि उन्हें बदलने, उदाहरण के लिए के साथ लपेटकर द्वारा ठीक किया जा सकता है:
f'' = not . f'
।g'' = (\case Nothing -> Right(); Just e -> Left e) . g'
h'' = (\case Left c -> Right c; Right e -> Left e) . h'
हालांकि, श्रृंखलन समारोह के उपयोगकर्ता गठबंधन f
, g
, h
, f'
, g'
, और h'
और उन्हें बस काम करने में सक्षम हो जाता है। वह नहीं जानता कि फ़ंक्शन के रिटर्न प्रकार को तब तक परिवर्तित करने की आवश्यकता है जब तक कि वह प्रत्येक संयोजन के अर्थशास्त्र को देखता न हो, और जांच करें कि क्या वे Fail
के दायरे में हैं जो उनके पास हैं। औसत उपयोगकर्ता के लिए यह भी कठिन और बहुत सूक्ष्म है, विशेष रूप से उपयोगकर्ता को सही उदाहरण चुनने के लिए बाईपास करने के प्रकार के साथ।
ये कार्य इस ज्ञान के साथ नहीं बनाए गए थे कि उनका उपयोग कैसे किया जाएगा। तो मैं एक प्रकार data Result a b = Fail a | Success b
बना सकता हूं और प्रत्येक फ़ंक्शन के चारों ओर रैपर बना सकता हूं।उदाहरण के लिए:
fR = (\case True -> Sucess(); False -> Fail()) . f
f'R = (\case False -> Sucess(); True -> Fail()) . f'
gR = (\case Just a -> Sucess a; Nothing -> Fail()) . g
g'R = (\case Nothing -> Sucess(); Just e -> Fail e) . g'
hR = (\case Left e -> Fail e; Right a -> Sucess a) . h
h'R = (\case Right e -> Fail e; Left a -> Sucess a) . h'
बहरहाल, यह गंदा लगता है। हम जो कर रहे हैं वह सिर्फ f
, g
, h
, f'
, g'
, और h'
संयोजन संयोजन के संदर्भ में उपयोग किया जाता है। क्या ऐसा करने का अधिक सीधा तरीका है? क्या मैं वास्तव में चाहते हैं Fail
typeclass का जो उदाहरण प्रत्येक कार्य के लिए इस्तेमाल किया जाना चाहिए, यानी, f
→ a
, g
→ b
, h
→ c
, और f'
(ऊपर typeclass उदाहरणों को दिए गए नामों का प्रयोग करके), कहने का एक तरीका है → a'
, g'
→ b'
, h'
→ c'
"अवैध" कार्यों के लिए है, जहां a'
, b'
, और c'
निम्नलिखित उदाहरणों (जो पिछले अभियानों ओवरलैप के रूप में परिभाषित कर रहे हैं, ताकि आप उन्हें नाम से लेने के लिए सक्षम होना चाहिए था किसी भी तरह):
instance Fail Bool where -- a'
isFail = id
instance Fail (Maybe a) where -- b'
isFail = isJust
instance Fail (Either a b) where -- c'
isFail (Right _) = True
isFail _ = False
हालांकि टाइपक्लास के माध्यम से इसे जरूरी नहीं है। शायद टाइपक्लास के अलावा ऐसा करने का कोई तरीका है?
यदि आप उन्हें एक मोनड ('डू' नोटेशन के साथ) की तरह एक साथ श्रृंखला बनाना चाहते हैं तो आप उन्हें सभी को एक ही प्रकार में बदलने की आवश्यकता है जिसके बाद आप एक मोनाड उदाहरण बना सकते हैं। आप बताते हैं कि आप टाइप सिस्टम को केवल यह समझने के लिए चाहते हैं कि बिना किसी संदर्भ या संदर्भ के विफलता के द्वारा फ़ंक्शन का क्या अर्थ है। सिद्धांत रूप में, मेरे पास असीमित संख्या में फ़ंक्शंस हो सकते हैं जो प्रत्येक विफलता का प्रतिनिधित्व करने वाला एक अलग इंटीजर लौटाता है, संकलक को यह पता होना चाहिए कि एक विशिष्ट इंटीजर विफलता कब होता है? यह केवल संदर्भ के रूप में एक मूल्य है। आप संकलक से आपके प्रोग्राम को लिखने की उम्मीद नहीं कर सकते हैं, अन्यथा हम सभी एग्डा का उपयोग करेंगे। – bheklilr
हाँ, मैं जरूरी नहीं कि यह एक मोनड बनाना चाहता है, लेकिन यह समान होगा। मैं संकलक से यह नहीं जानता कि कौन से पूर्णांक विफल हैं, मैं किसी भी तरह से संकेत देना चाहता हूं कि कौन से पूर्णांक 'f' के लिए विफलता हैं, और 'f2' के लिए एक अलग सेट इंगित करते हैं, और इसी तरह। उदाहरण के लिए, पायथन में मैं टाइपक्लास उदाहरणों के कुछ समकक्षों के लिए एक वैश्विक चर मैपिंग फ़ंक्शन कर सकता हूं। फिर यह संकलन समय के बजाय रनटाइम पर क्रैश होगा यदि उपयोगकर्ता द्वारा उपयोग किए जाने वाले कुछ फ़ंक्शन से कोई मैपिंग नहीं है। लेकिन यह अभी भी सुरक्षित होगा। –