2012-10-16 4 views
16

मैं वर्तमान में Learn you a Haskell में हूं, और मैं Functor टाइपक्लास पर अनुभाग तक पहुंच गया हूं। कहा गया अनुभाग में लेखक इस उदाहरण के उदाहरण देता है कि कक्षा के उदाहरणों को कैसे अलग किया जा सकता है (उदाहरण के लिए Maybe, एक कस्टम Tree प्रकार इत्यादि) इसे देखकर, मैंने निर्णय लिया (मज़ेदार और अभ्यास के लिए) Data.Set प्रकार के लिए एक उदाहरण लागू करने का प्रयास करें ; इस सब में, Data.Set.map को अनदेखा कर रहा है। ,किसी वर्ग के उदाहरण में क्लास बाधा को कैसे प्रभावित करता है जिसके लिए एक ठोस प्रकार के बजाय एक प्रकार का कन्स्ट्रक्टर की आवश्यकता होती है?

instance Functor Set.Set where 
    fmap f empty = Set.empty 
    fmap f s = Set.fromList $ map f (Set.elems s) 

लेकिन चूंकि मैं समारोह fromList इस में इस्तेमाल किया प्रकार के लिए बुला एक वर्ग बाधा में लाता है का उपयोग करने के होती हैं:

वास्तविक उदाहरण ही सुंदर सीधी-सपाट है, और मैं के रूप में यह लिखा था Set, Ord होने के लिए के रूप में एक संकलक त्रुटि द्वारा समझाया गया है:

Error occurred 
ERROR line 4 - Cannot justify constraints in instance member binding 
*** Expression : fmap 
*** Type   : Functor Set => (a -> b) -> Set a -> Set b 
*** Given context : Functor Set 
*** Constraints : Ord b 

देखें: Live Example

मैं त्रि उदाहरण पर एक बाधा डालना, या fmap पर एक प्रकार का हस्ताक्षर जोड़ना, लेकिन न तो सफल हुआ (दोनों संकलक त्रुटियां भी थीं।)

इस तरह की स्थिति को देखते हुए, एक बाधा कैसे पूरी हो सकती है और संतुष्ट हो सकती है? क्या कोई संभावित तरीका है?

अग्रिम धन्यवाद! :)

उत्तर

15

दुर्भाग्यवश, कोई मानक Functor कक्षा के साथ ऐसा करने का आसान तरीका है। यही कारण है कि Set डिफ़ॉल्ट रूप से Functor उदाहरण के साथ नहीं आता है: आप एक नहीं लिख सकते हैं।

यह एक समस्या है, और कुछ सुझाव दिए गए हैं (उदाहरण के लिए Functor कक्षा को अलग तरीके से परिभाषित करना), लेकिन मुझे नहीं पता कि इस पर सर्वोत्तम सहमति कैसे है या नहीं।

मेरा मानना ​​है कि एक दृष्टिकोण constraint kinds का उपयोग कर नए Functor वर्ग के अतिरिक्त बाधाओं उदाहरणों वस्तु के बारे में जैसे सोचना पड़ सकता है Functor वर्ग के पुनर्लेखन के लिए है। यह आपको निर्दिष्ट करेगा कि Set में Ord कक्षा से प्रकार शामिल होना चाहिए।

एक और दृष्टिकोण केवल बहु-पैरामीटर वर्गों का उपयोग करता है। मुझे केवल Monad कक्षा के लिए ऐसा करने के बारे में आलेख मिल सकता है, लेकिन का Set भाग बनाना Functor का हिस्सा बनाने के समान समस्याएं पैदा करता है। इसे Restricted Monads कहा जाता है।

class Functor' f a b where 
    fmap' :: (a -> b) -> f a -> f b 

instance (Ord a, Ord b) => Functor' Data.Set.Set a b where 
    fmap' = Data.Set.map 

अनिवार्य रूप से, सभी तुम यहाँ क्या कर रहे हैं प्रकार में Set भी वर्ग का हिस्सा बना रही है:

यहां बहु पैरामीटर वर्गों का उपयोग के बुनियादी सार कुछ इस तरह हो रहा है । यह तब आपको बाध्य करने देता है जब आप उस वर्ग का उदाहरण लिखते हैं तो ये प्रकार क्या हो सकते हैं।

Functor का यह संस्करण दो एक्सटेंशन की आवश्यकता है: MultiParamTypeClasses और FlexibleInstances।(आपको Set के लिए एक उदाहरण परिभाषित करने में सक्षम होने के लिए कक्षा और दूसरे एक्सटेंशन को परिभाषित करने में सक्षम होने के लिए पहले एक्सटेंशन की आवश्यकता है।)

Haskell : An example of a Foldable which is not a Functor (or not Traversable)? इस बारे में अच्छी चर्चा है।

+6

एक कंस्ट्रेन्ड functor वर्गों के साथ समस्या यह है कि हम सत्ता का एक बहुत खो देते हैं। विशेष रूप से आवेदक functors के साथ, हम अक्सर उन कार्यों में रखना चाहते हैं। हालांकि, कई मामलों में उन वर्गों के सामान्य उदाहरण प्रदान करना असंभव है जिन्हें हम कार्यों में रुचि रखते हैं। – hammar

2

यह असंभव है। Functor कक्षा का उद्देश्य यह है कि यदि आपके पास Functor f => f a है, तो आप जो भी चाहें a को प्रतिस्थापित कर सकते हैं। वर्ग को आपको या तो इसे वापस करने के लिए बाध्य करने की अनुमति नहीं है। चूंकि Set की आवश्यकता है कि इसके तत्व कुछ बाधाओं को पूरा करते हैं (और वास्तव में यह कार्यान्वयन विवरण नहीं है बल्कि वास्तव में सेट की एक आवश्यक संपत्ति है), यह Functor की आवश्यकताओं को पूरा नहीं करता है।

जैसा कि किसी अन्य उत्तर में बताया गया है, Functor जैसी कक्षा विकसित करने के तरीके जो आपको इस तरह से बाधित करते हैं, लेकिन यह वास्तव में एक अलग वर्ग है, क्योंकि यह कक्षा के उपयोगकर्ता को कम गारंटी देता है (आप नहीं करते हैं विभिन्न प्रकार के प्रकारों पर लागू होने के बदले में, जो भी प्रकार पैरामीटर आप चाहते हैं उसके साथ इसका उपयोग करें)। यही कारण है कि, प्रकार की संपत्ति को परिभाषित करने का क्लासिक ट्रेडऑफ: जितना अधिक प्रकार आप इसे संतुष्ट करना चाहते हैं, उतना कम उन्हें संतुष्ट करने के लिए मजबूर होना चाहिए।

(जहां यह पता चलता है की एक और दिलचस्प उदाहरण MonadPlus वर्ग है। विशेष रूप से, हर मामले MonadPlus TC के लिए आप एक उदाहरण Monoid (TC a) कर सकते हैं, लेकिन आप हमेशा दूसरी तरह के आसपास नहीं जा सकते। इसलिए Monoid (Maybe a) उदाहरण अलग है MonadPlus Maybe उदाहरण से, क्योंकि पूर्व a सीमित कर सकते हैं लेकिन बाद नहीं कर सकता।)

0

You can do this using a CoYoneda Functor.

{-# LANGUAGE GADTs #-} 

data CYSet a where 
    CYSet :: (Ord a) => Set.Set a -> (a -> b) -> CYSet b 

liftCYSet :: (Ord a) => Set.Set a -> CYSet a 
liftCYSet s = CYSet s id 

lowerCYSet :: (Ord a) => CYSet a -> Set.Set a 
lowerCYSet (CYSet s f) = Set.fromList $ map f $ Set.elems s 

instance Functor CYSet where 
    fmap f (CYSet s g) = CYSet s (f . g) 

main = putStrLn . show 
    $ lowerCYSet 
    $ fmap (\x -> x `mod` 3) 
    $ fmap abs 
    $ fmap (\x -> x - 5) 
    $ liftCYSet $ Set.fromList [1..10] 
-- prints "fromList [0,1,2]" 
संबंधित मुद्दे

 संबंधित मुद्दे