मुझे लगता है कि आप इसे थोड़ा अधिक सोच रहे हैं। एक बिफंक्टर बस दो पैरामीटर फंक्टर की तरह है। गिब्बन और ओलिविरा का विचार बिफुनक्टरों का सिर्फ एक आवेदन है, जैसे कि रिकर्सन स्कीम के मानक चिड़ियाघर केवल मज़दूरों का एक आवेदन है।
class Bifunctor f where
bimap :: (a -> c) -> (b -> d) -> f a b -> f c d
Bifunctor
रों * -> * -> *
का एक प्रकार है और दोनों मानकों covariantly से अधिक मैप किया जा सकता। इसकी तुलना नियमित रूप से Functor
एस से करें, जिसमें केवल एक पैरामीटर (f :: * -> *
) है जिसे कॉन्वरेन्टली मैप किया जा सकता है।
उदाहरण के लिए, Either
के सामान्य Functor
उदाहरण के बारे में सोचें। यह आपको दूसरे प्रकार के पैरामीटर पर fmap
पर अनुमति देता है - Right
मान मैप किए जाते हैं, Left
मान वे रहते हैं।
instance Functor (Either a) where
fmap f (Left x) = Left x
fmap f (Right y) = Right (f y)
हालांकि, इसकी Bifunctor
उदाहरण आप योग के दोनों हिस्सों को मैप करने के लिए अनुमति देता है।
instance Bifunctor Either where
bimap f g (Left x) = Left (f x)
bimap f g (Right y) = Right (g y)
इसी तरह tuples के लिए
: (,)
के Functor
उदाहरण आप केवल दूसरे घटक मैप करने के लिए अनुमति देता है, लेकिन Bifunctor
आप दोनों भागों मैप करने के लिए अनुमति देता है।
instance Functor ((,) a) where
fmap f (x, y) = (x, f y)
instance Bifunctor (,) where
bimap f g (x, y) = (f x, g y)
ध्यान दें कि Maybe
, जो आप उल्लेख किया है, bifunctors के ढांचे में फिट नहीं करता है, क्योंकि यह केवल एक पैरामीटर है।
Fix
के सवाल पर, एक bifunctor की नियत बिन्दु आप इस तरह के सबसे अधिक कंटेनर की तरह संरचनाओं के रूप में जो एक functorial प्रकार पैरामीटर है पुनरावर्ती प्रकार, चिह्नित करने के लिए अनुमति देता है। चलिए एक उदाहरण के रूप में सूचियों का उपयोग करते हैं।
newtype Fix f = Fix { unFix :: f (Fix f) }
data ListF a r = Nil_ | Cons_ a r deriving Functor
type List a = Fix (ListF a)
, मानक functorial Fix
का प्रयोग के रूप में मैं ऊपर है, वहाँ List
के लिए Functor
का एक उदाहरण का कोई सामान्य व्युत्पत्ति है, क्योंकि Fix
के बारे में List
के a
पैरामीटर में कुछ भी पता नहीं है। यही है, मैं instance Something f => Functor (Fix f)
जैसे कुछ भी नहीं लिख सकता क्योंकि Fix
में गलत प्रकार है।मैं सूचियों के लिए एक map
हाथ क्रैंक करने के लिए है, शायद cata
का उपयोग कर:
map :: (a -> b) -> List a -> List b
map f = cata phi
where phi Nil_ = Fix Nil_
phi Cons_ x r = Fix $ Cons_ (f x) r
Fix
की bifunctorial संस्करण Functor
का एक उदाहरण की अनुमति देता है। Fix
Fix f a
की रिकर्सिव घटना में प्लग करने के लिए बाईफंक्टर के पैरामीटर में से एक का उपयोग करता है और दूसरा परिणामस्वरूप डाटाटाइप के फंक्शनल पैरामीटर के लिए खड़ा होता है।
newtype Fix f a = Fix { unFix :: f a (Fix f a) }
instance Bifunctor f => Functor (Fix f) where
fmap f = Fix . bimap f (fmap f) . unFix
तो हम लिख सकते हैं:
deriveBifunctor ''ListF
type List = Fix ListF
और मिल Functor
उदाहरण मुक्त करने के लिए:
map :: (a -> b) -> List a -> List b
map = fmap
बेशक
, यदि आप एक से अधिक के साथ पुनरावर्ती संरचनाओं का सामान्य रूप से काम करना चाहते हैं पैरामीटर तो आपको त्रि-फ़ैक्टर, क्वाड-फ़ैक्टर, आदि को सामान्यीकृत करने की आवश्यकता है ... यह स्पष्ट रूप से टिकाऊ नहीं है, और बहुत सारे काम (अधिक उन्नत प्रोग्रामिंग भाषाओं में) को मो डिजाइन करने में रखा गया है प्रकारों के प्रकार के लिए लचीला सिस्टम फिर से।
क्या मैं पूछ सकता हूं कि प्रोग्रामिंग भाषाओं के किस तरह के काम में? क्या आप कुछ सुलभ कर सकते हैं? मैं सोच रहा हूं कि 'क्लास कोविरिएंट (एन :: नेट) पी' जैसे कुछ को परिभाषित करना संभव हो सकता है कि 'पी' अपने' एनएच 'पैरामीटर में कॉन्वर्सेंट है, लेकिन मुझे पूरा यकीन नहीं है कि यह कैसा दिखता है । – dfeuer
स्पष्ट स्पष्टीकरण के लिए धन्यवाद! मैं बैफनक्टरों को अनावश्यक वाक्य रचनात्मक चीनी के रूप में सोच रहा था, लेकिन दो मानकों को लेने के लिए मानचित्र को अधिभारित करने का आपका उदाहरण दर्शाता है कि वे वास्तव में कितने सरल रूप से अर्थात् हैं। हालांकि, अंत में आपकी टिप्पणी में आप जिस चीज का जिक्र कर रहे थे, उससे भी मैं चिंतित हूं। ओकैमल में पॉलिमॉर्फिक फ़ैक्टर नहीं हैं? –
@ डीफ्यूअर ओह, मैं सिर्फ "ब्रह्मांड" के नक्षत्र के संदर्भ में था - स्टाइल डेटाटाइप विवरण जो डीटी भाषाओं में विकसित किए गए हैं। –