2012-04-24 20 views
20
में functor के उदाहरण के रूप में समारोह के बारे में उलझन

functor में FMAP के प्रकार है:Haskell

fmap :: Functor f => (a -> b) -> f a -> f b 

यह की तरह लग रहा है, पहले समारोह (एक -> ख) लागू पिता के पैरामीटर के लिए का एक परिणाम बनाने के लिए टाइप बी, तो यह करने के लिए च लागू होते हैं, और परिणाम अमेरिकन प्लान

का उपयोग कर हो सकता है कि एक उदाहरण के लिए है:

fmap show (Just 1) 
result is : Just "1" 

ही यह कहते हुए:

Just (show 1) 

लेकिन जब - पहले (>) एक functor के रूप में (Control.Monad.Instances में)

import Control.Monad.Instances 
(fmap show Just) 1 
result is : "Just 1" 

है कि प्रयोग किया जाता है, बस लागू है, तो शो लागू किया जाता है। एक और उदाहरण में, परिणाम समान है:

fmap (*3) (+100) 1 
result is 303 

क्यों नहीं * 3 पहले, फिर +100?

उत्तर

22

functor में FMAP के प्रकार है:

fmap :: Functor f => (a -> b) -> f a -> f b 

यह कैसा दिखाई देता पहला समारोह लागू (एक -> ख) पिता के पैरामीटर के लिए टाइप बी का एक परिणाम बनाने के लिए है, तो यह करने के लिए च लागू , और परिणाम एफबी

यह fmap का प्रकार है, लेकिन उस प्रकार का अर्थ आपकी व्याख्या गलत है।

आपको लगता है कि f a में एक पैरामीटर है, और यह कि पैरामीटर a टाइप किया गया है।

पर विचार करें xs :: [a]:

  • शायद xs = []
  • शायद xs = [x1]
  • शायद xs = [x1, x2]
  • ...

प्रकारf a एक ही प्रकार के पैरामीटर a साथ एक functor f है। लेकिन मूल्य प्रकार f a आवश्यक रूप से फॉर्म F x नहीं लेते हैं, जैसा कि आप उपरोक्त पहले और तीसरे मामलों में देख सकते हैं।

अब विचार करना fmap f xs:

  • शायद fmap f xs = []
  • शायद fmap f xs = [f x1]
  • शायद fmap f xs = [f x1, f x2]
  • ...

हम आवश्यक रूप से सभी (पहला मामला) पर f लागू नहीं है! या हम इसे एक से अधिक (तीसरा मामला) लागू कर सकते हैं।

हम a की चीजों को प्रतिस्थापित करते हैं, b प्रकार की चीजों के साथ। लेकिन हम बड़ी संरचना को बरकरार रखते हैं --- कोई नया तत्व जोड़ा नहीं जाता है, कोई तत्व हटा नहीं जाता है, उनका ऑर्डर अपरिवर्तित रहता है।


अब मज़ेदार (c ->) के बारे में सोचें। (याद रखें, एक मज़ेदार केवल एक प्रकार का पैरामीटर लेता है, इसलिए (->) पर इनपुट तय किया गया है।)

क्या c -> a में a भी शामिल है? इसमें कोई भी a एस नहीं हो सकता है, लेकिन जब हम इसे c देते हैं तो यह किसी भी तरह पतली हवा से बाहर जा सकता है। लेकिन fmap का परिणाम c -> b है: हमें केवल c के साथ प्रस्तुत किए जाने पर हमें b प्रदान करना होगा।

तो हम fmap f x = \y -> f (x y) कह सकते हैं।

इस मामले में, हम मांग पर f आवेदन कर रहे हैं --- हर बार जब हम वापस लौटते हैं तो लागू होता है, f भी लागू होता है।

+1

हाँ, आपका जवाब बहुत अच्छा है! मैंने एक बड़ी गलती की। आपका बहुत बहुत धन्यवाद। –

+0

मैं एक ठोस पैरामीटर के साथ "प्रकार पैरामीटर" भ्रमित –

2
fmap :: Functor f => (a -> b) -> f a -> f b 

याद रखें कि f एक प्रकार का कन्स्ट्रक्टर भी हो सकता है। मैं इसे (सबसे सरल मामलों के लिए) लेता हूं कि फ़ंक्शन af में लिपटे प्रकार के कुछ प्रकार लेता है और इसे में a -> b फ़ंक्शन का उपयोग करके कुछ प्रकार के b में परिवर्तित करता है।

दूसरे उदाहरण में, आप (fmap show Just) 1 कर रहे हैं। इस प्रकार का

Prelude> :t fmap show Just 
fmap show Just :: (Show a, Functor ((->) a)) => a -> String 

की है यह, पिछले एक

Prelude> :t fmap show (Just 1) 
fmap show (Just 1) :: Maybe String 

अंतर यह है कि पहले एक Just में एक प्रकार निर्माता है के विपरीत है जबकि Just 1 एक प्रकार का एक उदाहरण है। fmap उचित रूप से सामान्य है कि इसका अर्थ दोनों के लिए है।

+1

"याद रखें कि एफ एक प्रकार का कन्स्ट्रक्टर भी हो सकता है" आप शायद "जरूरी" के बजाय "भी" कर सकते हैं। –

+0

'जस्ट' एक प्रकार का कन्स्ट्रक्टर नहीं है, यह एक मूल्य या डेटा कन्स्ट्रक्टर है। 'शायद' एक प्रकार का कन्स्ट्रक्टर है। –

5

fmap(->) के लिए fmap = (.) जैसा परिभाषित किया गया है। तो, (fmap f g) x(f . g) xf (g x) है। आपके मामले में (*3) ((+100) 1), जो 3 * (100 + 1) के बराबर है जिसके परिणामस्वरूप 303 है।

26

fmap(->) r (यानी फ़ंक्शन) के लिए उदाहरण वास्तव में केवल रचना है। the source itself से:

instance Functor ((->) r) where 
    fmap = (.) 

तो, अपने उदाहरण में, हम बस fmap(.) से बदल सकते हैं, और कुछ परिवर्तनों

fmap (*3) (+100) 1 => 
(.) (*3) (+100) 1 => 
(*3) . (+100) $ 1 => -- put (.) infix 
(*3) (1 + 100)  => -- apply (+100) 
(1 + 100) * 3   -- apply (*3) 

है, कार्यों के लिए fmap उन्हें बाएं से दाएं तैयार करता (वास्तव में भी ऐसा ही (.) के रूप में, जो समझदार है क्योंकि यह (.) है)।

इसे एक और तरीके से देखने के लिए ((डबल) पुष्टि के लिए!), हम प्रकार हस्ताक्षर का उपयोग कर सकते हैं:,

-- general fmap 
fmap :: Functor f => (a -> b) -> f a -> f b 

-- specialised to the function functor (I've removed the last pair of brackets) 
fmap :: (a -> b) -> (r -> a) -> r -> b 

तो पहले प्रकार r (तीसरा तर्क) का मूल्य) r -> a समारोह द्वारा प्रकार a (के एक मूल्य के रूप में तब्दील करने की आवश्यकता है ताकि a -> b समारोह इसे b (परिणाम) के प्रकार में बदल सकते हैं।

+0

धन्यवाद, यह एक अच्छी स्पष्ट परिभाषा है! –

+1

हां, एफएमएपी :: (ए -> बी) -> (आर -> ए) -> आर -> बी, यह बहुत समझाता है, धन्यवाद –

14

यह को की आवश्यकता है ताकि प्रकारों को काम करने के तरीके को परिभाषित किया जा सके। आपके कहे अनुसार, fmap के प्रकार है: हम वास्तव में (c ->) रूप में यह लिख करना चाहते हैं, यानी कार्य:

fmap :: Functor f => (a -> b) -> f a -> f b 

के मामले पर विचार करें जब functor f((->) c)

(नोट है चलो c से, लेकिन हास्केल हमें ऐसा करने की अनुमति नहीं है।)

फिर f a वास्तव में 012 के लिए ((->) c a), जो (c -> a) के बराबर है है, और इसी प्रकार, इसलिए हमने:

fmap :: (a -> b) -> (c -> a) -> (c -> b) 

अर्थात हम दो कार्य लेने की जरूरत:

  • f :: a -> b
  • g :: c -> a

और एक नया कार्य का निर्माण

  • h :: c -> b

लेकिन वहाँ सिर्फ एक ही रास्ता है कि करना है: आप g पहले लागू करने के लिए प्रकार a के बारे में कुछ पाने के लिए, और फिर f लागू प्रकार b के बारे में कुछ है, जिसका अर्थ कि आप को परिभाषित करने के लिए है प्राप्त करने के लिए

instance Functor ((->) c) where 
    fmap f g = \x -> f (g x) 

या, और अधिक संक्षेप,

instance Functor ((->) c) where 
    fmap = (.) 
0

फ़ंक्शन प्रकार बनाने के लिए, आपको (->) के लिए 2 प्रकार के पैरामीटर की आवश्यकता है, यह एकल इनपुट तर्क प्रकार और रिटर्न प्रकार है।

एक फ़ैक्टर केवल 1 प्रकार पैरामीटर ले सकता है, इसलिए आपको इनपुट तर्क प्रकार को कम करना होगा (क्योंकि यह बाएं से दाएं से पहला है), जिससे फ़ंक्शन का रिटर्न प्रकार प्रकार का पैरामीटर बन जाता है functor।

तो फ़ंक्शन (फ़ंक्शन) ए-> बी के लिए, आपको काम करने के लिए एक-> xxx के अलावा b-> xxx के फ़ंक्शन एफएफ को fmap देना होगा, और इसका मतलब है कि फ़ंक्शन एफएफ केवल तभी लागू किया जा सकता है ए-> बी लागू होता है।

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