मैंने (f .) . g
पैटर्न के अनुसार कई कार्यों को परिभाषित किया है। उदाहरण के लिए:क्या करता है (एफ।)। हास्केल में जी मतलब है?
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
इसका क्या अर्थ है?
मैंने (f .) . g
पैटर्न के अनुसार कई कार्यों को परिभाषित किया है। उदाहरण के लिए:क्या करता है (एफ।)। हास्केल में जी मतलब है?
countWhere = (length .) . filter
duplicate = (concat .) . replicate
concatMap = (concat .) . map
इसका क्या अर्थ है?
डॉट ऑपरेटर (यानी (.)
) function composition ऑपरेटर है।
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
आप इसे देख सकते हैं प्रकार b -> c
के एक समारोह और प्रकार a -> b
का एक और समारोह लेता है और यानी प्रकार a -> c
के एक समारोह (पहली से पीछे नहीं फ़ंक्शन के परिणाम पर लागू होता है जो देता है: यह इस प्रकार परिभाषित किया गया है समारोह)।
फ़ंक्शन संरचना ऑपरेटर बहुत उपयोगी है। यह आपको एक फ़ंक्शन के आउटपुट को किसी अन्य फ़ंक्शन के इनपुट में पाइप करने की अनुमति देता है। उदाहरण के लिए आप हास्केल में एक tac प्रोग्राम लिखने के रूप में निम्नानुसार सकता है:
main = interact (\x -> unlines (reverse (lines x)))
नहीं बहुत पठनीय। समारोह रचना का उपयोग करना भले ही आप भुगतान लिख सकता है इस प्रकार है:
main = interact (unlines . reverse . lines)
आप समारोह रचना देख सकते हैं बहुत उपयोगी है लेकिन आप इसे हर जगह उपयोग नहीं कर सकते। उदाहरण के लिए आप कर सकते हैं नहीं पाइप समारोह रचना का उपयोग कर length
में filter
के उत्पादन:
countWhere = length . filter -- this is not allowed
कारण यह अनुमति नहीं है क्योंकि filter
प्रकार (a -> Bool) -> [a] -> [a]
की है। a -> b
के साथ तुलना करें हम पाते हैं कि a
(a -> Bool)
और b
प्रकार [a] -> [a]
प्रकार है। इसके परिणामस्वरूप एक प्रकार का मिलान नहीं होता है क्योंकि हास्केल length
को b -> c
(यानी ([a] -> [a]) -> c
) के प्रकार की अपेक्षा करता है। हालांकि यह वास्तव में [a] -> Int
प्रकार है।
समाधान बहुत आसान है:
countWhere f = length . filter f
हालांकि कुछ लोगों कि अतिरिक्त झूलने f
पसंद नहीं है।
countWhere = (length .) . filter
वे इस कैसे मिलता है: वे pointfree शैली में countWhere
लिखने के लिए इस प्रकार पसंद करते हैं? पर विचार करें:
countWhere f xs = length (filter f xs)
-- But `f x y` is `(f x) y`. Hence:
countWhere f xs = length ((filter f) xs)
-- But `\x -> f (g x)` is `f . g`. Hence:
countWhere f = length . (filter f)
-- But `f . g` is `(f .) g`. Hence:
countWhere f = (length .) (filter f)
-- But `\x -> f (g x)` is `f . g`. Hence:
countWhere = (length .) . filter
आप (f .) . g
देख सकते हैं बस \x y -> f (g x y)
है। इस अवधारणा को वास्तव में पुनरावृत्त किया जा सकता है:
f . g --> \x -> f (g x)
(f .) . g --> \x y -> f (g x y)
((f .) .) . g --> \x y z -> f (g x y z)
(((f .) .) .) . g --> \w x y z -> f (g w x y z)
यह सुंदर नहीं है लेकिन यह काम पूरा हो जाता है।आप countWhere
लिख सकता है के रूप में इस प्रकार के बजाय (.:)
ऑपरेटर का उपयोग करना
f .: g = (f .) . g
f .:: g = ((f .) .) . g
f .::: g = (((f .) .) .) . g
: दो कार्यों को देखते हुए आप अपने खुद के समारोह रचना ऑपरेटरों लिख सकते हैं दिलचस्प बात यह है
countWhere = length .: filter
ही आप के रूप में बिंदु मुक्त शैली में (.:)
लिख सकता है अच्छी तरह से:
f .: g = (f .) . g
-- But `f . g` is `(.) f g`. Hence:
f .: g = (.) (f .) g
-- But `\x -> f x` is `f`. Hence:
(f .:) = (.) (f .)
-- But `(f .)` is `((.) f)`. Hence:
(f .:) = (.) ((.) f)
-- But `\x -> f (g x)` is `f . g`. Hence:
(.:) = (.) . (.)
इसी प्रकार हम पाते हैं:
(.::) = (.) . (.) . (.)
(.:::) = (.) . (.) . (.) . (.)
आप देख सकते हैं (.:)
, (.::)
और (.:::)
सिर्फ (.)
की शक्तियों हों (जैसे कि वे (.)
हैं)। गणित में संख्या के लिए:
x^0 = 1
x^n = x * x^(n - 1)
इसी प्रकार के कार्यों के लिए गणित में
:
f .^ 0 = id
f .^ n = f . (f .^ (n - 1))
तो f
(.)
तो है:
(.) .^ 1 = (.)
(.) .^ 2 = (.:)
(.) .^ 3 = (.::)
(.) .^ 4 = (.:::)
हमें इस लेख के अंत के करीब लाता है यही कारण है कि। एक अंतिम चुनौती के लिए चलो pointfree शैली में निम्नलिखित समारोह लिखें:
mf a b c = filter a (map b c)
mf a b c = filter a ((map b) c)
mf a b = filter a . (map b)
mf a b = (filter a .) (map b)
mf a = (filter a .) . map
mf a = (. map) (filter a .)
mf a = (. map) ((filter a) .)
mf a = (. map) ((.) (filter a))
mf a = ((. map) . (.)) (filter a)
mf = ((. map) . (.)) . filter
mf = (. map) . (.) . filter
हम आगे इस सरल बना सकते हैं इस प्रकार है:
mf = compose map filter
:
compose f g = (. f) . (.) . g
compose f g = ((. f) . (.)) . g
compose f g = (.) ((. f) . (.)) g
compose f = (.) ((. f) . (.))
compose f = (.) ((. (.)) (. f))
compose f = ((.) . (. (.))) (. f)
compose f = ((.) . (. (.))) (flip (.) f)
compose f = ((.) . (. (.))) ((flip (.)) f)
compose = ((.) . (. (.))) . (flip (.))
compose
का उपयोग करके आप अब के रूप में mf
लिख सकते हैं
हां यह थोड़ा बदसूरत है लेकिन यह भी वास्तव में एक भयानक दिमाग-दबाने वाली अवधारणा है। अब आप \x y z -> f x (g y z)
फॉर्म compose f g
के रूप में कोई भी फ़ंक्शन लिख सकते हैं और यह बहुत साफ है।
फॉर्म का अभिव्यक्ति '(।)^I' अच्छी तरह से टाइप नहीं किया गया है, इसलिए वे वास्तव में हास्केल मान्य नहीं हैं। –
सच है। हालांकि मैंने लिखा "इसी प्रकार गणित में कार्यों के लिए:" _ और चूंकि यह एक गणितीय स्पष्टीकरण है, मुझे लगता है कि संख्याओं के बजाय कार्यों के लिए '^' का उपयोग करना ठीक है। फिर भी मैं दोनों के बीच अंतर करने के लिए ऑपरेटर को '। ^' में बदल दूंगा। –
मैं गणित में भी '(।)^I' को देखकर आश्चर्यचकित हूं। शायद ऐसी चीज के लिए एक औपचारिक ढांचा निर्भर प्रकार सिद्धांत में मौजूद है। यह दिलचस्प होगा। –
यह स्वाद का विषय है, लेकिन मुझे ऐसी शैली अप्रिय होने लगती है। सबसे पहले मैं इसका अर्थ बताऊंगा, और फिर मैं एक विकल्प सुझाता हूं जिसे मैं पसंद करता हूं।
किसी भी ऑपरेटर ?
के लिए आपको (f . g) x = f (g x)
और (f ?) x = f ? x
पता होना चाहिए। इस से हम मान सकते हैं कि
countWhere p = ((length .) . filter) p
= (length .) (filter p)
= length . filter p
तो
countWhere p xs = length (filter p xs)
मैं एक समारोह का उपयोग करना पसंद .:
(.:) :: (r -> z) -> (a -> b -> r) -> a -> b -> z
(f .: g) x y = f (g x y)
फिर countWhere = length .: filter
कहा जाता है। व्यक्तिगत रूप से मुझे यह बहुत स्पष्ट लगता है।
(.:
Data.Composition
और शायद अन्य स्थानों में भी परिभाषित किया गया है।)
आप '(। :)' को '(। :) = fmap fmap fmap' के रूप में भी परिभाषित कर सकते हैं। यह अधिक सामान्य है क्योंकि आप इसे किसी भी मजेदार के लिए उपयोग कर सकते हैं। उदाहरण के लिए आप '(* 2) कर सकते हैं।: बस [1..5]'। बेशक आपको इसे '(। :) :: (फंक्शन एफ, फंक्टर जी) => (ए -> बी) -> एफ (जी ए) -> एफ (जी बी) 'के सही प्रकार के हस्ताक्षर देने की आवश्यकता होगी। –
@AaditMShah उस मामले में, मैं '<$$> = fmap जैसे कुछ पसंद करूंगा। fmap', चूंकि '(। :) '' (->) r' के लिए विशिष्ट सम्मेलन द्वारा है, और" बाहरी "' fmap' वैसे भी '(->) आर' मज़ेदार पर है। – kqr
(च।)।जी मूल लेखक के कोड पर अच्छी तरह से छिपी हुई राय का भी हिस्सा हो सकता है। – Marton
मुझे सच में यकीन नहीं है कि इसका क्या अर्थ है। –
इसका मतलब है कि लेखक चालाक और अपठनीय कोड लिखने के लिए समाप्त हो रहा था। ;) – tibbe