TypeScript के साथ Functor, Applicative Functor और Monad को समझना
(evan-moon.github.io)पाठ
- Functor के
mapसे हल न होने वाली दो समस्याओं से शुरुआत करते हुए—कंटेनर के अंदर फंक्शन के फँस जाने की समस्या और composition के समय context nesting की समस्या—TypeScript कोड के जरिए Applicative Functor और Monad तक पहुँचने की प्रक्रिया समझाई गई है - 1988 में Eugenio Moggi ने प्रोग्राम को A → B की बजाय A → T(B) के रूप में मॉडल किया, इस पृष्ठभूमि से चर्चा शुरू होती है
flatMap = map + joinजैसी संरचना और इसे सुरक्षित रूप से इस्तेमाल करने के लिए तीन नियमों—associativity, left identity, right identity—पर चर्चा की गई है- Monad को "endomorphism category में monoid object" क्यों कहा जाता है, इसे integer addition के monoid के मुकाबले समझाया गया है
- यह भी बताया गया है कि Promise monadic तरीके से काम करता है, लेकिन सख्त गणितीय अर्थ में Monad नहीं है
Functor की सीमाएँ: map से जो नहीं हो सकता
- Curried function को
mapसे apply करने पर परिणामMaybe<(b: number) => number>जैसा हो जाता है, यानी फंक्शन कंटेनर के अंदर फँस जाता हैmapकेवल कंटेनर के बाहर के function को ही ले सकता है, इसलिए अंदर फँसे function को किसी दूसरे value पर apply करने का तरीका नहीं होता
- Functor लौटाने वाले दो functions को compose करने पर
Maybe<Maybe>जैसी context nesting हो जाती है- जैसे-जैसे चरण बढ़ते हैं, यह
Maybe<Maybe<Maybe<...>>>की अनंत nesting में बदल सकता है
- जैसे-जैसे चरण बढ़ते हैं, यह
Applicative Functor: कंटेनर के अंदर के function को apply करना
applyoperation के जरिए कंटेनर के अंदर फँसे function को दूसरे कंटेनर के value पर apply किया जा सकता हैapply: T<(A → B)> → T<A> → T<B>
pureoperation के जरिए pure value को कंटेनर में डाला जाता है- सीमा: किन कंटेनरों को compose करना है, यह पहले से तय होना चाहिए
- पिछले computation के परिणाम को देखकर अगला computation तय करने वाली dynamic sequential dependency को व्यक्त नहीं किया जा सकता
Monad: nesting को flatten करने वाले operation का आविष्कार
joinoperationT<T<A>> → T<A>के रूप में double container को single container में flatten कर देता है- JavaScript का
Array.prototype.flatयही काम करता है
- JavaScript का
- व्यवहार में
map + joinको मिलाकर बनेflatMapका उपयोग किया जाता हैflatMap: T<A> → (A → T<B>) → T<B>mapजहाँA → Bलेता है, वहींflatMapA → T<B>लेता है, इसलिए परिणाम एक ही layer में बना रहता है
flatMap के तीन नियम
- associativity rule:
T(T(T(A)))जैसी triple nesting को flatten करते समय, अंदर से flatten करें या बाहर से, परिणाम समान होना चाहिएm.flatMap(f).flatMap(g) === m.flatMap(x => f(x).flatMap(g))
- left identity rule:
pureसे value डालकर तुरंतflatMapकरें, तो परिणाम function को सीधे apply करने जैसा ही होना चाहिएpure(a).flatMap(f) === f(a)
- right identity rule:
flatMapमेंpureदेने पर वही मूल कंटेनर वापस मिलना चाहिएm.flatMap(pure) === m
"endomorphism category में monoid object" को खोलकर समझना
- प्रोग्रामिंग में Functor type world से type world की ओर जाता है, इसलिए वह endofunctor है
- ऐसे endofunctors को ही objects मानकर endofunctor category बनाई जा सकती है
- monoid की शर्तें (binary operation + associativity + identity element) इसमें रखने पर:
- binary operation =
join - identity element =
pure - यह संरचना integer addition के monoid से ठीक-ठीक मेल खाती है
- binary operation =
Promise Monad क्यों नहीं है
thenreturn value के अनुसारmapऔरflatMapको मिलाकर संभालता हैPromise<Promise>जैसी स्थिति runtime में रहने नहीं दी जाती और तुरंत एक single layer में merge हो जाती है- व्यवहारिक रूप से यह सुविधाजनक है, लेकिन गणितीय Monad laws को संतुष्ट नहीं करता
2 टिप्पणियां
कृपया Comonad को भी कवर करें!
अरे... इस पर सोचूँगा हाहाहा