ฟังก์ชันและตัวแมปแบบเจเนอริก
เขียนฟังก์ชัน map ที่ใช้ได้กับคอนเทนเนอร์ทุกชนิด
ฟังก์ชันและตัวแมปแบบเจเนอริก เป็นบทเรียน TypeScript Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน TypeScript Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน
Functor แบบทั่วไป
ตอนนี้เราจะใช้การเข้ารหัสตามจุดประสงค์ของมัน: map แบบทั่วไป ที่ทำงานกับคอนเทนเนอร์ที่ลงทะเบียนไว้ชนิดใดก็ได้ อินเทอร์เฟซ Functor ซึ่งกำหนดพารามิเตอร์ด้วยตัวระบุทรัพยากร จะประกาศเมธอดหนึ่งตัว
interface Functor<F extends URIS> {
readonly URI: F;
map<A, B>(fa: Kind<F, A>, f: (a: A) => B): Kind<F, B>;
}อินสแตนซ์ของอาร์เรย์
อินสแตนซ์หนึ่งตัวจะนำ map ไปใช้กับตัวระบุทรัพยากรหนึ่งตัว อินสแตนซ์ของอาร์เรย์ใช้เมธอดอาร์เรย์ในตัวเพื่อทำการแมป ชนิด Kind<"Array", A> ของมันคลี่ออกมาเป็น A[]
const arrayFunctor: Functor<"Array"> = {
URI: "Array",
map: (fa, f) => fa.map(f)
};การใช้อินสแตนซ์ของอาร์เรย์
การเรียก map บนอินสแตนซ์ของอาร์เรย์จะแปลงสมาชิกแต่ละตัว โดยยังคงชนิดคอนเทนเนอร์อาร์เรย์ไว้
const doubled = arrayFunctor.map([1, 2, 3], n => n * 2);
// doubled: number[] -> [2, 4, 6]ชนิดออปชัน
กำหนดออปชันให้เป็นค่าหรือ null แล้วลงทะเบียนออปชันนั้น map จะใช้ฟังก์ชันเฉพาะเมื่อมีค่าอยู่ มิฉะนั้นจะส่งต่อ null
interface URItoKind<A> { Option: A | null }
type Option<A> = A | null;อินสแตนซ์ของออปชัน
อินสแตนซ์ของออปชันจะคงคอนเทนเนอร์ออปชันไว้: ฟังก์ชันจะถูกใช้กับค่าที่อยู่ภายใน และ null จะยังคงเป็น null
const optionFunctor: Functor<"Option"> = {
URI: "Option",
map: (fa, f) => (fa === null ? null : f(fa))
};การใช้อินสแตนซ์ของออปชัน
ตอนนี้รูปแบบ map เดียวกันทำงานกับคอนเทนเนอร์ที่แตกต่างไปโดยสิ้นเชิง ค่าที่มีอยู่จะถูกแปลง ส่วนค่าที่ไม่มีอยู่จะคงเดิม
const a = optionFunctor.map(5, n => n + 1); // 6
const b = optionFunctor.map(null, n => n + 1); // nullนามธรรมหนึ่งแบบ หลายคอนเทนเนอร์
นี่คือผลลัพธ์ที่ต้องการ arrayFunctor และ optionFunctor ใช้อินเทอร์เฟซ Functor เดียวกัน โค้ดที่เขียนบน Functor<F> จึงทำงานกับทั้งสองชนิดได้โดยไม่ต้องแก้ไข
function bumpAll<F extends URIS>(
F: Functor<F>,
fa: Kind<F, number>
): Kind<F, number> {
return F.map(fa, n => n + 1);
}การเรียกฟังก์ชันทั่วไป
bumpAll ไม่รู้และไม่สนใจว่าคอนเทนเนอร์ที่ได้รับคือชนิดใด เพียงส่งอินสแตนซ์กับข้อมูลเข้าไป แล้วผลลัพธ์จะคงชนิดคอนเทนเนอร์ไว้
const arr = bumpAll(arrayFunctor, [1, 2]); // number[] -> [2, 3]
const opt = bumpAll(optionFunctor, 9); // number | null -> 10กฎของ Functor
Functor ที่ถูกต้องต้องปฏิบัติตามกฎสองข้อ: การแมปฟังก์ชันเอกลักษณ์ต้องไม่เปลี่ยนแปลงอะไร และการแมปฟังก์ชันสองตัวตามลำดับต้องให้ผลเท่ากับการแมปองค์ประกอบของฟังก์ชัน ทั้งอินสแตนซ์ของอาร์เรย์และออปชันข้างต้นปฏิบัติตามกฎเหล่านี้
// map(fa, x => x) === fa
// map(map(fa, f), g) === map(fa, x => g(f(x)))การเพิ่มอินสแตนซ์เพิ่มเติม
เนื่องจากนามธรรมนี้เปิดให้ขยายได้ คอนเทนเนอร์ใหม่จึงเชื่อมต่อเข้ามาได้เพียงลงทะเบียนตัวระบุทรัพยากรและจัดเตรียมอินสแตนซ์ ต้นไม้ ผลลัพธ์ หรืองาน ก็จะทำการแมปได้ด้วยโค้ดทั่วไปแบบเดียวกัน
// Register URI, implement Functor<"Tree">,
// and bumpAll works on trees too - no edits to bumpAllเหตุผลที่เรื่องนี้สำคัญ
Functor ทั่วไปคือจุดเริ่มต้นของนามธรรมเชิงฟังก์ชันใน TypeScript เช่น แอปพลิเคทีฟ, Monad และการท่องผ่าน แต่ละอย่างเป็นอินเทอร์เฟซเหนือ Kind<F, A> ที่มีอินสแตนซ์แยกตามคอนเทนเนอร์ ตอนนี้คุณเข้าใจกลไกที่ทำให้ fp-ts และ Effect เป็นไปได้แล้ว
interface Monad<F extends URIS> extends Functor<F> {
of<A>(a: A): Kind<F, A>;
chain<A, B>(fa: Kind<F, A>, f: (a: A) => Kind<F, B>): Kind<F, B>;
}ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจของคุณเกี่ยวกับ Functor ทั่วไป
ทบทวน
คุณเขียน map ที่ใช้ได้กับคอนเทนเนอร์ทั่วไปแล้ว
Functor<F>ประกาศmapเหนือKind<F, A>- อินสแตนซ์ของอาร์เรย์และออปชันนำไปใช้กับตัวระบุทรัพยากรของตน
- โค้ดทั่วไปอย่าง
bumpAllทำงานกับคอนเทนเนอร์ที่ลงทะเบียนไว้ชนิดใดก็ได้ - กฎของ Functor ช่วยให้อินสแตนซ์ทำงานได้อย่างถูกต้อง นามธรรมที่มีความสามารถมากขึ้นจะต่อยอดจากสิ่งนี้
บทเรียนที่ 24 ถัดไป: การสร้างตัวแยกวิเคราะห์ที่ปลอดภัยด้านชนิดข้อมูล
คำถามที่พบบ่อย
บทเรียน “ฟังก์ชันและตัวแมปแบบเจเนอริก” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ฟังก์ชันและตัวแมปแบบเจเนอริก” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส TypeScript Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส TypeScript Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ฟังก์ชันและตัวแมปแบบเจเนอริก”
เขียนฟังก์ชัน map ที่ใช้ได้กับคอนเทนเนอร์ทุกชนิด คุณปฏิบัติ TypeScript Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน TypeScript Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน TypeScript Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ฟังก์ชันและตัวแมปแบบเจเนอริก” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน TypeScript Academy นี้ได้ไหม
ได้ บทเรียน TypeScript Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ปัญหา HKT ใน TypeScript
- การกำหนดตัวสร้างชนิดข้อมูล
- รูปแบบ HKT แบบน้ำหนักเบา
- ฟังก์ชันและตัวแมปแบบเจเนอริก