2016-10-19 8 views
7

मैं जावास्क्रिप्ट में अपने फ़ंक्शन इंस्टेंस को कार्यान्वित करके Applicative s और Monads की मेरी समझ में सुधार करने की कोशिश कर रहा हूं। हास्केल का मेरा ज्ञान सीमित है और मुझे उम्मीद है कि मेरा प्रश्न बिल्कुल समझ में आता है।फ़ंक्शन इंस्टेंस के बाइंड/>> = की व्याख्या कैसे करें?

यहाँ जावास्क्रिप्ट में fmap, <*> और >>=Functor, Applicative और Monad typeclasses के लिए की मेरी कार्यान्वयन हैं:

:

const fmap = f => g => x => f(g(x)); // B combinator 
const apply = f => g => x => f(x) (g(x)); // S combinator 
const bind = f => g => x => g(f(x)) (x); // ? 

मुझे यकीन है कि है कि क्या bind हास्केल कार्यान्वयन के सही अनुवाद है नहीं कर रहा हूँ

(>>=) :: (r -> a) -> (a -> (r -> b)) -> r -> b 

instance Monad ((->) r) where 
f >>= k = \ r -> k (f r) r 

प्रदान किया गया कि bind सही है, इसका अर्थ कैसे है? मुझे पता है कि Applicative प्रभावशाली गणनाओं का अनुक्रम कर सकता है। मुझे यह भी पता है कि Monad इसके अलावा आप पिछले एक के परिणाम के अनुसार एक अगला प्रभाव निर्धारित करने की अनुमति देता है।

  • apply:

    मैं दृश्यों (जावास्क्रिप्ट में उत्सुक मूल्यांकन आदेश) देख सकते हैं f(x) ... g(result of f): f(x) ... g(x) ... lambda(result of g) ... lambda

  • bind का परिणाम ... lambda(x) ... lambda

हालांकि का परिणाम है, bind मज़ा कथन बहुत अजीब लग रहा है। f और g अन्य तरीकों से घोंसला क्यों हैं? इस कार्यान्वयन में विशिष्ट Monad व्यवहार (पिछले एक के अनुसार अगला प्रभाव निर्धारित करता है) कैसा है? वास्तव में g(f(x)) (x) फ़्लिप किए गए तर्कों के साथ एक फ़ंक्शन संरचना की तरह दिखता है, जहां g एक बाइनरी फ़ंक्शन है।

जब मैं apply/bind को एक यूनरी और बाइनरी फ़ंक्शन के साथ लागू करता हूं, तो वे एक ही परिणाम प्राप्त करते हैं। यह ज्यादा समझ में नहीं आता है।

+0

'बाइंड' (जिसे जेएस में 'चेन' के नाम से जाना जाता है) के उपयोगी अनुप्रयोग के लिए [इस उदाहरण] (http://stackoverflow.com/q/40026018/1048572) पर एक नज़र डालें – Bergi

उत्तर

5

फ़ंक्शंस के लिए मोनैड इंस्टेंस में मानों में कुछ निश्चित प्रकार r के लिए r -> a टाइप करें। (>>=) को दिए गए फ़ंक्शन (a -> (r -> b)) आपको वर्तमान मान से परिणाम देने के लिए अगला फ़ंक्शन चुनने की अनुमति देता है (एक फ़ंक्शन r -> a)। f r में a और k (f r) टाइप r -> b है जो लागू करने के लिए अगला कार्य है।

आपके कोड में g(f(x)) इसलिए एक ऐसा फ़ंक्शन है जो r प्रकार के एक तर्क की अपेक्षा करता है। bind का कॉलर पिछले फ़ंक्शन द्वारा दिए गए मान के आधार पर इस फ़ंक्शन को चुन सकता है उदा।

var inc = x => x + 1; 
var f = bind(inc)(function(i) { 
    if(i <= 5) { return x => x * 2; } 
    else { return x => x * 3; } 
}); 

समारोह x एक इनपुट के रूप दिया जाएगा और inc(x) उदा का परिणाम के आधार पर गणना में अगले चरण के लिए चुन सकते हैंली की जवाब देने के लिए

f(2) //4; 
f(5) //15; 
+0

धन्यवाद, यह इतना स्पष्ट है अभी व! जब मैं जावास्क्रिप्ट में हास्केल मुहावरों को स्थानांतरित करने का प्रयास करता हूं तो मुझे अक्सर एक ही समस्या का सामना करना पड़ता है: हास्केल मुहावरे के बारे में बहुत सारे ज्ञान उनके आवेदन में छिपा हुआ है, न कि केवल उनके कार्यान्वयन या हस्ताक्षर प्रकारों में। – ftor

+0

अब अगला गणना पिछले परिणाम पर निर्भर करती है, लेकिन यह पूरी तरह से इस परिणाम को अनदेखा करती है। क्या यह तरीका 'बाइंड' आमतौर पर काम करता है या आपके उदाहरण के लिए विशिष्ट है? सभी प्रश्नों के लिए क्षमा करें! – ftor

+0

@ftor - क्षमा करें, उत्तर गलत था और आपका संपादन गलत फ़िक्स था। 'बाइंड' केवल अगले फ़ंक्शन को चुनने के लिए 'f (x) 'का उपयोग करता है लेकिन इसमें मूल इनपुट प्रदान करता है। – Lee

4

कुछ फ़ुटनोट:

हालांकि, bind समारोह बहुत अजीब लग रहा है। f और g अन्य तरीकों से घोंसला क्यों हैं?

क्योंकि bind पीछे की तरफ है। (>>=) तुलना करें और अपनी फ़्लिप संस्करण :

(>>=) :: Monad m => m a -> (a -> m b) -> m b 
(=<<) :: Monad m => (a -> m b) -> m a -> m b 

या, अपने विशिष्ट उदाहरण में:

(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b) 
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b) 

व्यवहार में जब तक हम से कैसे (>>=), वाक्य रचना बोल की वजह से अधिक बार (>>=) का उपयोग करते हैं, उधार देता इसे लिखने का सबसे स्वाभाविक तरीका है, जो कि सैद्धांतिक दृष्टिकोण से, पाइपलाइन मोनैड्स के निर्माण के लिए अक्सर उपयोग किया जाता है। विशेष रूप से, समानताएं और fmap/(<$>) और (<*>) के साथ मतभेद और अधिक स्पष्ट कर रहे हैं:

(<$>) :: Functor f  => (a -> b) -> f a -> f b 
(<*>) :: Applicative f => f (a -> b) -> f a -> f b 
(=<<) :: Monad f  => (a -> f b) -> f a -> f b 

जब मैं एक एकल और एक द्विआधारी समारोह के साथ apply/bind लागू होते हैं, वे एक ही परिणाम उपज। यह ज्यादा समझ में नहीं आता है।

यह फ़ंक्शन उदाहरणों के बारे में एक आकस्मिक तथ्य है। की ओर से विशेष हस्ताक्षर पक्ष रखते हैं:

(<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b) 
(=<<) :: (a -> (r -> b)) -> (r -> a) -> (r -> b) 

MonadApplicative से परे चला जाता साधन प्रदान पिछले परिणाम के अनुसार अगले प्रभाव का निर्धारण करने के (के रूप में "पिछले प्रभाव" के लिए विरोध द्वारा - Applicative कर सकते हैं कि पहले से ही)। प्रभाव, इस मामले में, एक ऐसा फ़ंक्शन होता है जो r प्रकार के तर्क के मानों को उत्पन्न करता है। अब, चूंकि कई तर्कों (यानी फ़ंक्शंस जो फ़ंक्शन लौटाते हैं) के साथ फ़ंक्शन फ़्लिप किए जा सकते हैं, ऐसा होता है कि (r -> (a -> b)) और (a -> (r -> b)) (flip के बीच कोई महत्वपूर्ण अंतर नहीं हो सकता है), जो Monad उदाहरण (->) r के बराबर समकक्ष बनाता है Applicative पर एक।

+0

बहुत उपयोगी, धन्यवाद! – ftor

+1

@ftor आपका स्वागत है। मेरे जवाब पर फिर से देखकर, मैंने देखा कि मैंने आपके प्रश्न को बहुत जल्दी पढ़कर एक महत्वपूर्ण मिश्रण को अनदेखा कर दिया था।आपने कहा कि 'मोनाद' और 'आवेदक' के बीच का अंतर यह है कि 'मोनाड' के साथ आप "पिछले एक के अनुसार अगला प्रभाव" निर्धारित कर सकते हैं। 'आवेदक 'पहले से ही अनुमति देता है, हालांकि। 'मोनाड' जोड़ क्या पिछले * परिणामों * से प्रभाव निर्धारित कर रहा है (यानी मोनैड ए => ए -> एम बी' में 'ए' के ​​अनुरूप, मज़ेदार में अंतर्निहित मूल्य)। – duplode

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