อธิบายใน 5 นาที: Monads ใน JavaScript ธรรมดา
แม้จะมีภาพหน้าปกที่ดูน่ากลัว แต่ฉันจะพยายามอธิบายพระโดยใช้คณิตศาสตร์ให้ยากที่สุดเท่าที่จะทำได้ ไม่มีการกล่าวถึงทฤษฎีหมวดหมู่ ไม่มี Kleisli ไม่มีแม้แต่ Curry แม้ว่าจะมีNaN.
ในคำพูดของ Douglas Crockford ผู้ยิ่งใหญ่:
นอกจากจะดีและมีประโยชน์แล้ว มันยังถูกสาปอีกด้วย และคำสาปของ Monad คือเมื่อคุณได้รับสิ่งศักดิ์สิทธิ์ เมื่อคุณเข้าใจ - "โอ้ นั่นคือสิ่งที่มันเป็น" - คุณจะสูญเสียความสามารถในการอธิบายให้คนอื่นฟัง
ฉันมีทฤษฎีหนึ่ง — นี่เป็นเพราะในบรรดาบทความที่ยอดเยี่ยมเกี่ยวกับเรื่องนี้ ซึ่งให้คำอธิบายที่ดีเกี่ยวกับทฤษฎีทางคณิตศาสตร์ที่อยู่เบื้องหลัง Monads และวิธีที่พวกเขาควรนำไปใช้ (พร้อมกับตัวอย่างที่สวยงาม!) มีสิ่งหนึ่งที่ผิด:
ฉันต้องการสิ่งเหล่านั้นเพื่ออะไร
ก่อนที่เราจะพยายามค้นหาข้อสังเกตหนึ่งข้อ เมื่อไม่นานมานี้ ฉันอ่านเจอว่าคุณไม่ควรพยายามทำความเข้าใจเกี่ยวกับพระโดยอิงจากสิ่งใดก็ตามที่ไม่ได้ขึ้นอยู่กับการอธิบายทางคณิตศาสตร์ที่อยู่เบื้องหลังพวกเขาและตำแหน่งของพวกเขาในทฤษฎีหมวดหมู่ สำหรับผู้ที่สนใจ: มีบทความดีๆ ที่ครอบคลุมหัวข้อนั้น เช่นบทความนี้หรือบทความนี้หรือบทความที่นำ Monads เข้าสู่การเขียนโปรแกรมตั้งแต่ปี 1992 เนื่องจากฉันไม่ต้องการพูดซ้ำที่นี่จริงๆ โปรดอ่าน (หรืออย่างน้อยก็สแกน) ตอนนี้และกลับมาที่นี่ในภายหลัง (แม้ว่าฉันเชื่อว่าไม่จำเป็นต้องเข้าใจว่าจะเกิดอะไรขึ้นต่อไป)
ตกลงตอนนี้เรามีสิ่งนั้นแล้ว - โมนาดคืออะไร? วิธีที่ง่ายที่สุดในการพูดก็คือ — มันห่อหุ้มค่าบางอย่างไว้ ในแง่ของการเขียนโปรแกรมเชิงฟังก์ชัน monad คือfunctorซึ่งเป็นโครงสร้างที่อนุญาตให้ใช้ฟังก์ชันกับมัน เป็นชั้นพิเศษของสิ่งที่เป็นนามธรรมระหว่างค่าและการประมวลผลอะไรก็ตามที่เราต้องการใส่ค่าลงไป แต่นั่นไม่ได้บอกอะไรเราเลย
มาดู monad ที่ง่ายที่สุดที่คุณอาจจินตนาการได้: การนำIdentitymonad ไปใช้:
const Identity = (value) => ({
value: () => value,
map: (fn) => Identity(fn(value)),
});
ลองดูตัวอย่างที่ง่ายที่สุด:
const addTax = (value) => value * 1.1;
const cartValue = Identity(100);
const cartValueWithTax = cartValue
.map(addTax) // At this point this is Identity(110)
.value(); // Equal to 110 as a number
Identitymonad มี - เช่นเดียวกับฟังก์ชันidentityในไลบรารีการเขียนโปรแกรมเชิงฟังก์ชัน - เป็นตรรกะที่ค่อนข้างโปร่งใส เป็นตัวยึดตำแหน่ง monad เช่นเดียวกับidentityฟังก์ชันตัวยึดตำแหน่ง การใช้ มูลค่าของเราได้ผลดีสำหรับสถานการณ์ข้างต้น แต่ลองคิดดูว่าจะเกิดอะไรขึ้นหากมูลค่าของรถเข็น ของaddTaxเราเท่ากับ undefinedด้วยวิธีการที่ยอดเยี่ยมของ JavaScriptเราจะได้รับไฟล์NaN.
โดยปกติ เพื่อหลีกเลี่ยงปัญหานี้ วิธีที่ใช้งานง่ายที่สุดคือเพิ่มการตรวจสอบค่าให้กับaddTaxฟังก์ชัน นี่เป็นแนวทางที่ผิด มันบดบังวัตถุประสงค์ของการทำงานและทำให้บริสุทธิ์น้อยลง ฟังก์ชันaddTaxควรทำเพียงสิ่งเดียวและสิ่งเดียวเท่านั้น: add.Tax
ตกลง, wiseguy - คุณอาจพูดว่า - เราควรคำนึงถึงundefinedคุณค่าอย่างไร? นั่นคือสิ่งที่เรามี monads สำหรับ เราต้องการรักษาฟังก์ชัน ให้ บริสุทธิ์ เรายังต้องการให้ตรรกะของเราทำงานแตกต่างกันไปตามค่าที่เราส่งผ่านไปยังฟังก์ชัน สถานที่ที่ดีที่สุดในการกำหนดพฤติกรรมนั้นคือfunctor !
มาดูกันว่า Monad ที่ได้รับความนิยมมากที่สุดคือ: Maybe. นี่อาจเป็นการใช้งานขั้นพื้นฐาน (ฉันออกจากวิธีการปกติที่คุณอาจพบใน monad ofเพื่อความชัดเจน):
const Maybe = (value) => ({
value: () => value,
map: (fn) => value === undefined || value === null
? Maybe(null)
: Maybe(fn(value)),
});
const primitiveCart = 100;
const undefinedCart = undefined;
const nullishCart = null;
const maybeCart = Maybe(100);
const maybeUndefinedCart = Maybe(undefined);
const maybeNullishCart = Maybe(null);
addTax(primitiveCart); // boring, 110
addTax(undefinedCart); // NaN
addTax(nullishCart); // 0 - thanks, JavaScript!
maybeCart.map(addTax).value(); // 110
maybeUndefinedCart.map(addTax).value(); // null
maybeNullishCart.map(addTax).value(); // null
แน่นอนว่านี่เป็นเพียงรอยขีดข่วนของความเป็นไปได้มากมายที่การใช้ monads นำมา สมมติว่าเราต้องการทักทายแขกทุกคนที่เข้ามาในโรงแรมของเรา:
const greet = (name) => `Hello, ${name}!`;
ลองมาดูตัวอย่างพื้นฐานอีกตัวอย่างหนึ่ง — the Optionalmonad:
const Optional = (value) => ({
value: () => value,
orElse: (alternativeValue) => value
? Optional(value)
: Optional(alternativeValue),
map: (fn) => Optional(fn(value)),
});
const firstGuest = "John";
const anonymousGuest = undefined;
greet(firstGuest); // "Hello, John!"
greet(anonymousGuest); // "Hello, undefined" - this is a bit embarrasing
const OptionalWithStrangerFallback = (name) => Optional(name)
.orElse("stranger");
const firstGuestOptional = OptionalWithStrangerFallback(firstGuest);
const anonymousGuestOptional = OptionalWithStrangerFallback(anonymousGuest);
// I really hope you know where this is going at this point
firstGuestOptional.map(greet).value(); "Hello, John!"
anonymousGuestOptional.map(greet).value(); "Hello, stranger!"
ฉันหวังเป็นอย่างยิ่งว่าสิ่งนี้จะทำให้สิ่งต่าง ๆ กระจ่างขึ้น ถ้าไม่โปรดแจ้งให้เราทราบในความคิดเห็น! นอกจากนี้ หากคุณต้องการอ่านบทความเพิ่มเติมเกี่ยวกับ JavaScript, การเขียนโปรแกรมเชิงฟังก์ชัน, คอมพิวเตอร์วิทัศน์, สถาปัตยกรรม, เรขาคณิต, มีม, ความเป็นผู้นำด้านเทคนิค หรือสิ่งอื่นๆ ที่กล่าวมาข้างต้น อย่าลืมติดตามฉันที่นี่หรือบนLinkedIn !





































![รายการที่เชื่อมโยงคืออะไร? [ส่วนที่ 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)