ข้อควรจำ: การเขียนโปรแกรมเชิงฟังก์ชันไม่ใช่การเขียนโปรแกรมด้วยฟังก์ชัน! - -
23.4 การเขียนโปรแกรมเชิงฟังก์ชัน
23.4.1 การเขียนโปรแกรมเชิงฟังก์ชันคืออะไร
? ถ้าถามตรงๆจะพบว่าเป็นแนวคิดที่อธิบายได้ไม่ง่าย ทหารผ่านศึกหลายคนที่มีประสบการณ์หลายปีในสาขาการเขียนโปรแกรมไม่สามารถอธิบายได้อย่างชัดเจนว่า Functional Programming กำลังศึกษาอยู่ Functional Programming เป็นสาขาที่ไม่คุ้นเคยสำหรับโปรแกรมเมอร์ที่คุ้นเคยกับการเขียนโปรแกรมเชิงขั้นตอน แนวคิดเรื่องการปิด การต่อเนื่อง และการเคอร์รีนั้นดูไม่คุ้นเคยสำหรับเรามาก แต่สิ่งที่คุ้นเคยก็ไม่มีอะไรเหมือนกัน แม้ว่าการเขียนโปรแกรมเชิงฟังก์ชันจะมีต้นแบบทางคณิตศาสตร์ที่สวยงามซึ่งการเขียนโปรแกรมเชิงขั้นตอนไม่สามารถเทียบเคียงได้ แต่ก็ลึกลับมากที่มีเพียงผู้ที่มีปริญญาเอกเท่านั้นที่สามารถเชี่ยวชาญได้
เคล็ดลับ: ส่วนนี้ค่อนข้างยาก แต่ไม่ใช่ทักษะที่จำเป็นในการเรียนรู้ JavaScript หากคุณไม่ต้องการใช้ JavaScript เพื่อทำงานที่ทำเสร็จแล้วใน Lisp หรือไม่ต้องการเรียนรู้ทักษะลึกลับของ การเขียนโปรแกรมเชิงฟังก์ชัน คุณสามารถข้ามไปได้ และเข้าสู่บทต่อไปของการเดินทางของคุณ
กลับมาที่คำถาม Functional Programming คืออะไร? คำตอบนั้นยาว…
กฎข้อแรกของการเขียนโปรแกรมเชิงฟังก์ชัน: ฟังก์ชันเป็นประเภทแรก
ประโยคนี้จะเข้าใจได้อย่างไร? ประเภทที่ 1 ที่แท้จริงคืออะไร? ลองดูแนวคิดทางคณิตศาสตร์ต่อไปนี้:
สมการไบนารี F(x, y) = 0, x, y เป็นตัวแปร เขียนเป็น y = f(x), x คือพารามิเตอร์, y คือค่าที่ส่งคืน, f มาจาก x ถึง y ความสัมพันธ์ของการแมปเรียกว่าฟังก์ชัน หากมี G(x, y, z) = 0 หรือ z = g(x, y) g คือความสัมพันธ์ในการโยงจาก x, y ถึง z และยังเป็นฟังก์ชันด้วย หากพารามิเตอร์ x และ y ของ g เป็นไปตามความสัมพันธ์ก่อนหน้า y = f(x) เราจะได้ z = g(x, y) = g(x, f(x)) ซึ่งมีความหมายสองประการ x) เป็นฟังก์ชันบน x และพารามิเตอร์ของฟังก์ชัน g ประการที่สอง g เป็นฟังก์ชันที่มีลำดับสูงกว่า f
ด้วยวิธีนี้ เราใช้ z = g(x, f(x)) เพื่อแสดงคำตอบที่เกี่ยวข้องของสมการ F(x, y) = 0 และ G(x, y, z) = 0 ซึ่งเป็นฟังก์ชันวนซ้ำ . นอกจากนี้เรายังสามารถแสดง g ในรูปแบบอื่นได้ จำไว้ z = g(x, y, f) เพื่อที่เราจะได้สรุปฟังก์ชัน g ให้เป็นฟังก์ชันที่มีลำดับสูงกว่า เมื่อเปรียบเทียบกับรุ่นก่อนหน้า ข้อดีของการแทนค่าแบบหลังคือ มันเป็นแบบจำลองทั่วไปมากกว่า เช่น คำตอบที่เกี่ยวข้องของ T(x,y) = 0 และ G(x,y,z) = 0 เราก็เช่นกัน สามารถเขียนได้ในรูปแบบเดียวกัน (ให้ f=t) ในระบบภาษานี้ที่รองรับการวนซ้ำของการแปลงวิธีแก้ไขปัญหาให้เป็นฟังก์ชันลำดับที่สูงกว่า ฟังก์ชันนี้เรียกว่า "ประเภทแรก"
ฟังก์ชั่นใน JavaScript นั้นเป็น "ประเภทแรก" อย่างชัดเจน นี่คือตัวอย่างทั่วไป:
Array.prototype.each = ฟังก์ชั่น (ปิด)
-
return this.length ? [ปิด(นี้[0])].concat(this.slice(1).each(ปิด)) : [];
}
นี่เป็นรหัสเวทย์มนตร์จริงๆ ซึ่งให้การเล่นเต็มรูปแบบกับเสน่ห์ของสไตล์การทำงาน มีเพียงฟังก์ชันและสัญลักษณ์ในโค้ดทั้งหมด เป็นรูปแบบที่เรียบง่ายและทรงพลังอย่างไร้ขีดจำกัด
[1,2,3,4].each(function(x){return x * 2}) ได้รับ [2,4,6,8] ในขณะที่ [1,2,3,4].each(function(x ){return x-1}) ได้รับ [0,1,2,3]
สาระสำคัญของการทำงานและการมุ่งเน้นเชิงวัตถุคือ "เต่าเป็นไปตามธรรมชาติ" หากเชิงวัตถุคือการจำลองโลกแห่งความเป็นจริง นิพจน์เชิงฟังก์ชันก็คือการจำลองโลกทางคณิตศาสตร์ ในแง่หนึ่ง ระดับของนามธรรมนั้นสูงกว่าเชิงวัตถุ เนื่องจากระบบทางคณิตศาสตร์มีคุณสมบัติที่ไม่มีใครเทียบได้ในธรรมชาติโดยธรรมชาติ ของนามธรรม
กฎข้อที่สองของการเขียนโปรแกรมเชิงฟังก์ชัน: การปิดเป็นเพื่อนที่ดีที่สุดของการเขียนโปรแกรมเชิงฟังก์ชัน
การปิดดังที่เราได้อธิบายไปแล้วในบทที่แล้ว มีความสำคัญมากสำหรับการเขียนโปรแกรมเชิงฟังก์ชัน คุณสมบัติที่ใหญ่ที่สุดคือคุณสามารถเข้าถึงสภาพแวดล้อมภายนอกได้โดยตรงจากเลเยอร์ภายในโดยไม่ต้องผ่านตัวแปร (สัญลักษณ์) สิ่งนี้นำความสะดวกสบายอย่างมากมาสู่โปรแกรมการทำงานภายใต้การซ้อนหลายรายการ นี่คือตัวอย่าง:
(ฟังก์ชั่น externalFun(x)
-
ฟังก์ชันส่งคืน InnerFun(y)
-
กลับ x * y;
-
})(2)(3);
กฎข้อที่สามของการเขียนโปรแกรมเชิงฟังก์ชัน: ฟังก์ชันสามารถเป็น Currying ได้
Currying คืออะไร เป็นแนวคิดที่น่าสนใจ เริ่มจากคณิตศาสตร์กันก่อน: เราบอกว่า ลองพิจารณาสมการอวกาศสามมิติ F(x, y, z) = 0 ถ้าเราจำกัด z = 0 เราจะได้ F(x, y, 0) = 0 ซึ่งเขียนแทนด้วย F '(ค, ย) เห็นได้ชัดว่า F' เป็นสมการใหม่ ซึ่งแสดงถึงการฉายภาพสองมิติของเส้นโค้งปริภูมิสามมิติ F(x, y, z) บนระนาบ z = 0 แสดงว่า y = f(x, z) ให้ z = 0 เราจะได้ y = f(x, 0) แสดงว่า y = f'(x) เราบอกว่าฟังก์ชัน f' เป็นคำตอบแบบ Currying ของ f .
ตัวอย่างของ JavaScript Currying มีดังต่อไปนี้:
ฟังก์ชั่นเพิ่ม(x, y)
-
ถ้า(x!=null && y!=null) ส่งคืน x + y;
อย่างอื่นถ้า(x!=null && y==null) ฟังก์ชันส่งคืน(y)
-
กลับ x + y;
-
อย่างอื่นถ้า(x==null && y!=null) ฟังก์ชันส่งคืน(x)
-
กลับ x + y;
-
-
var a = เพิ่ม (3, 4);
var b = เพิ่ม(2);
var c = b(10);
ในตัวอย่างข้างต้น b=add(2) ส่งผลให้มีฟังก์ชัน Currying ของ add() ซึ่งเป็นฟังก์ชันของพารามิเตอร์ y เมื่อ x = 2 โปรดทราบว่าฟังก์ชันนี้ใช้ด้านบนด้วย ของการปิด
ที่น่าสนใจคือ เราสามารถสรุป Currying ให้กับฟังก์ชันใดๆ ได้ เช่น
ฟังก์ชัน Foo(x, y, z, w)
-
var args = อาร์กิวเมนต์;
if(Foo.length < args.length)
ฟังก์ชันส่งคืน()
-
กลับ
args.callee.apply(Array.apply([], args).concat(Array.apply([], อาร์กิวเมนต์)));
-
อื่น
กลับ x + y – z * w;
}
กฎข้อที่สี่ของการเขียนโปรแกรมเชิงฟังก์ชัน: การประเมินล่าช้าและความต่อเนื่อง
//TODO: ลองคิดดูอีกครั้งที่นี่
23.4.2 ข้อดีของ
การทดสอบหน่วย
การเขียนโปรแกรมฟังก์ชันทุกสัญลักษณ์ของการโปรแกรมฟังก์ชันที่เข้มงวดคือการอ้างอิงถึงผลลัพธ์ปริมาณหรือนิพจน์โดยตรง และไม่มีฟังก์ชันใดมีผลข้างเคียง เนื่องจากค่าไม่เคยถูกแก้ไขที่ไหนสักแห่ง และไม่มีฟังก์ชันใดที่จะแก้ไขปริมาณนอกขอบเขตที่ฟังก์ชันอื่นใช้ (เช่น สมาชิกคลาสหรือตัวแปรร่วม) ซึ่งหมายความว่าผลลัพธ์ของการประเมินฟังก์ชันเป็นเพียงค่าที่ส่งคืนเท่านั้น และสิ่งเดียวที่ส่งผลต่อค่าที่ส่งคืนคือพารามิเตอร์ของฟังก์ชัน
นี่คือความฝันอันเปียกชื้นของผู้ทดสอบหน่วย สำหรับแต่ละฟังก์ชันในโปรแกรมที่กำลังทดสอบ คุณเพียงแค่ต้องสนใจพารามิเตอร์ของฟังก์ชันนั้น โดยไม่ต้องพิจารณาลำดับการเรียกใช้ฟังก์ชัน หรือตั้งค่าสถานะภายนอกอย่างระมัดระวัง สิ่งที่คุณต้องทำคือส่งพารามิเตอร์ที่แสดงถึงกรณีขอบ หากทุกฟังก์ชันในโปรแกรมผ่านการทดสอบหน่วย คุณจะมั่นใจในคุณภาพของซอฟต์แวร์เป็นอย่างมาก แต่การเขียนโปรแกรมที่จำเป็นไม่สามารถมองโลกในแง่ดีได้ ใน Java หรือ C++ การตรวจสอบค่าที่ส่งคืนของฟังก์ชันเพียงอย่างเดียวนั้นไม่เพียงพอ เราต้องตรวจสอบสถานะภายนอกที่ฟังก์ชันอาจมีการแก้ไขด้วย
การดีบัก
หากโปรแกรมการทำงานไม่ทำงานอย่างที่คุณคาดหวัง การดีบักก็เป็นเรื่องง่าย เนื่องจากจุดบกพร่องในโปรแกรมการทำงานไม่ได้ขึ้นอยู่กับเส้นทางของโค้ดที่ไม่เกี่ยวข้องกับจุดเหล่านั้นก่อนดำเนินการ ปัญหาที่คุณพบจึงสามารถทำซ้ำได้เสมอ ในโปรแกรมที่จำเป็น จุดบกพร่องจะปรากฏขึ้นและหายไป เนื่องจากฟังก์ชันของฟังก์ชันนั้นขึ้นอยู่กับผลข้างเคียงของฟังก์ชันอื่นๆ และคุณอาจค้นหาเป็นเวลานานในทิศทางที่ไม่เกี่ยวข้องกับการเกิดจุดบกพร่อง แต่ไม่มีผลลัพธ์ใดๆ นี่ไม่ใช่กรณีของโปรแกรมฟังก์ชัน - ถ้าผลลัพธ์ของฟังก์ชันผิด ไม่ว่าคุณจะดำเนินการอะไรก่อนหน้านี้ ฟังก์ชันก็จะส่งคืนผลลัพธ์ที่ผิดเหมือนเดิมเสมอ
เมื่อคุณสร้างปัญหาขึ้นใหม่ การค้นหาสาเหตุของปัญหาจะง่ายดายและอาจทำให้คุณมีความสุขด้วยซ้ำ ขัดจังหวะการทำงานของโปรแกรมนั้นและตรวจสอบสแต็ก เช่นเดียวกับการเขียนโปรแกรมที่จำเป็น พารามิเตอร์ของการเรียกใช้ฟังก์ชันแต่ละรายการบนสแต็กจะถูกนำเสนอให้คุณเห็น แต่ในโปรแกรมที่จำเป็น พารามิเตอร์เหล่านี้ยังไม่เพียงพอ นอกจากนี้ ฟังก์ชันยังขึ้นอยู่กับตัวแปรสมาชิก ตัวแปรโกลบอล และสถานะของคลาส (ซึ่งขึ้นอยู่กับหลายตัวแปร) ในการเขียนโปรแกรมเชิงฟังก์ชัน ฟังก์ชันจะขึ้นอยู่กับพารามิเตอร์เท่านั้น และข้อมูลนั้นอยู่ใต้สายตาของคุณ! นอกจากนี้ ในโปรแกรมที่จำเป็น การตรวจสอบค่าที่ส่งคืนของฟังก์ชันไม่สามารถแน่ใจได้ว่าฟังก์ชันทำงานอย่างถูกต้อง คุณต้องตรวจสอบสถานะของอ็อบเจ็กต์หลายสิบรายการที่อยู่นอกขอบเขตของฟังก์ชันนั้นเพื่อยืนยัน ด้วยโปรแกรมการทำงาน สิ่งที่คุณต้องทำคือดูค่าที่ส่งคืน!
ตรวจสอบพารามิเตอร์และค่าส่งคืนของฟังก์ชันตามสแต็ก ทันทีที่คุณพบผลลัพธ์ที่ไม่สมเหตุสมผล ให้ป้อนฟังก์ชันนั้นและปฏิบัติตามทีละขั้นตอน ทำซ้ำขั้นตอนนี้จนกว่าคุณจะพบจุดที่เกิดข้อบกพร่อง
โปรแกรมฟังก์ชันแบบขนานสามารถดำเนินการแบบขนานได้โดยไม่ต้องแก้ไขใดๆ ไม่ต้องกังวลกับการหยุดชะงักและส่วนสำคัญเพราะคุณไม่เคยใช้การล็อค! ไม่มีข้อมูลในโปรแกรมการทำงานที่ถูกแก้ไขสองครั้งโดยเธรดเดียวกัน ไม่ต้องพูดถึงสองเธรดที่ต่างกัน ซึ่งหมายความว่าสามารถเพิ่มเธรดได้อย่างง่ายดายโดยไม่ต้องคิดซ้ำ โดยไม่ก่อให้เกิดปัญหาเดิมๆ ที่สร้างปัญหาให้กับแอปพลิเคชันแบบขนาน
หากเป็นกรณีนี้ ทำไมทุกคนถึงไม่ใช้ Functional Programming ในแอปพลิเคชันที่ต้องการการทำงานแบบขนานสูง พวกเขากำลังทำอย่างนั้น Ericsson ออกแบบภาษาการทำงานที่เรียกว่า Erlang และใช้ในสวิตช์โทรคมนาคมที่ต้องการความทนทานต่อข้อผิดพลาดและความสามารถในการปรับขนาดที่สูงมาก หลายคนได้ค้นพบข้อดีของ Erlang และเริ่มใช้งานแล้ว เรากำลังพูดถึงระบบควบคุมโทรคมนาคม ซึ่งต้องการความน่าเชื่อถือและความสามารถในการปรับขนาดมากกว่าระบบทั่วไปที่ออกแบบมาสำหรับวอลล์สตรีท ในความเป็นจริงระบบ Erlang ไม่น่าเชื่อถือและขยายได้ JavaScript ก็คือ ระบบ Erlang นั้นแข็งแกร่งมาก
เรื่องราวเกี่ยวกับความขนานไม่ได้หยุดอยู่แค่นั้น แม้ว่าโปรแกรมของคุณจะเป็นแบบเธรดเดียว แต่คอมไพเลอร์โปรแกรมที่ใช้งานได้ยังคงสามารถปรับให้ทำงานบน CPU หลายตัวได้ โปรดดูรหัสต่อไปนี้:
String s1 = someLongOperation1();
สตริง s2 = ค่อนข้างยาวการดำเนินงาน2();
String s3 = concatenate(s1, s2);
ในภาษาการเขียนโปรแกรมเชิงฟังก์ชัน คอมไพลเลอร์จะวิเคราะห์โค้ดเพื่อระบุฟังก์ชันที่อาจใช้เวลานานซึ่งสร้างสตริง s1 และ s2 จากนั้นจึงรันพร้อมกัน สิ่งนี้เป็นไปไม่ได้ในภาษาที่จำเป็น โดยที่แต่ละฟังก์ชันอาจแก้ไขสถานะนอกขอบเขตของฟังก์ชัน และฟังก์ชันที่ตามมาอาจขึ้นอยู่กับการแก้ไขเหล่านี้ ในภาษาเชิงฟังก์ชัน การวิเคราะห์ฟังก์ชันโดยอัตโนมัติและการระบุตัวเลือกที่เหมาะสมสำหรับการดำเนินการแบบขนานนั้นง่ายดายพอ ๆ กับฟังก์ชันอัตโนมัติในบรรทัด! ในแง่นี้ การเขียนโปรแกรมเชิงฟังก์ชันถือเป็น "การพิสูจน์ในอนาคต" (แม้ว่าฉันไม่ชอบใช้คำศัพท์ทางอุตสาหกรรม แต่ฉันก็จะยกเว้นในครั้งนี้) ผู้ผลิตฮาร์ดแวร์ไม่สามารถทำให้ CPU ทำงานเร็วขึ้นได้อีกต่อไป ดังนั้น พวกเขาจึงเพิ่มความเร็วของคอร์โปรเซสเซอร์ และได้รับความเร็วเพิ่มขึ้นสี่เท่าเนื่องจากการขนานกัน แน่นอนว่าพวกเขาลืมบอกด้วยว่าเงินพิเศษที่เราใช้ไปนั้นใช้กับซอฟต์แวร์เพื่อแก้ไขปัญหาแบบขนานเท่านั้น ซอฟต์แวร์ที่จำเป็นและซอฟต์แวร์ที่ใช้งานได้ 100% สามารถทำงานแบบขนานได้โดยตรงบนเครื่องเหล่านี้ในสัดส่วนเล็กน้อย
การปรับใช้โค้ดที่กำลังร้อนแรง
ซึ่งจำเป็นต้องติดตั้งการอัปเดตบน Windows และการรีสตาร์ทคอมพิวเตอร์เป็นสิ่งที่หลีกเลี่ยงไม่ได้ และมากกว่าหนึ่งครั้ง แม้ว่าจะติดตั้งเครื่องเล่นสื่อเวอร์ชันใหม่ก็ตาม Windows XP ช่วยปรับปรุงสถานการณ์นี้ได้อย่างมาก แต่ก็ยังไม่เหมาะ (วันนี้ฉันใช้งาน Windows Update ในที่ทำงาน และตอนนี้ไอคอนที่น่ารำคาญมักจะแสดงอยู่ในถาดเว้นแต่ฉันจะรีบูทเครื่อง) ระบบ Unix ทำงานในโหมดที่ดีกว่าเสมอ เมื่อติดตั้งการอัปเดต จำเป็นต้องหยุดเฉพาะส่วนประกอบที่เกี่ยวข้องกับระบบ แทนที่จะหยุดระบบปฏิบัติการทั้งหมด ถึงกระนั้นก็ตาม สิ่งนี้ก็ยังไม่น่าพอใจสำหรับแอปพลิเคชันเซิร์ฟเวอร์ขนาดใหญ่ ระบบโทรคมนาคมจะต้องทำงาน 100% ตลอดเวลา เพราะหากการโทรฉุกเฉินล้มเหลวในขณะที่ระบบกำลังอัปเดต อาจส่งผลให้เสียชีวิตได้ ไม่มีเหตุผลที่บริษัทใน Wall Street ต้องปิดบริการในช่วงสุดสัปดาห์เพื่อติดตั้งการอัปเดต
สถานการณ์ในอุดมคติคือการอัปเดตโค้ดที่เกี่ยวข้องโดยไม่ต้องหยุดส่วนประกอบใดๆ ของระบบเลย สิ่งนี้เป็นไปไม่ได้ในโลกที่มีความจำเป็น พิจารณาว่าเมื่อรันไทม์อัปโหลดคลาส Java และแทนที่คำจำกัดความใหม่ อินสแตนซ์ทั้งหมดของคลาสนี้จะไม่พร้อมใช้งานเนื่องจากสถานะที่บันทึกไว้สูญหาย เราอาจเริ่มเขียนโค้ดควบคุมเวอร์ชันที่น่าเบื่อเพื่อแก้ไขปัญหานี้ จากนั้นทำให้อินสแตนซ์ทั้งหมดของคลาสนี้กลายเป็นอนุกรม ทำลายอินสแตนซ์เหล่านี้ จากนั้นสร้างอินสแตนซ์เหล่านี้ขึ้นใหม่ด้วยคำจำกัดความใหม่ของคลาสนี้ จากนั้นโหลดข้อมูลที่ต่อเนื่องกันก่อนหน้านี้ และหวังว่าการโหลด รหัสจะย้ายข้อมูลนั้นไปยังอินสแตนซ์ใหม่อย่างถูกต้อง ยิ่งไปกว่านั้น รหัสการย้ายจะต้องเขียนใหม่ด้วยตนเองสำหรับการอัปเดตแต่ละครั้ง และต้องใช้ความระมัดระวังอย่างยิ่งเพื่อป้องกันการทำลายความสัมพันธ์ระหว่างออบเจ็กต์ ทฤษฎีนั้นง่าย แต่การฝึกฝนไม่ใช่เรื่องง่าย
สำหรับโปรแกรมเชิงฟังก์ชัน สถานะทั้งหมด เช่น พารามิเตอร์ที่ส่งไปยังฟังก์ชัน จะถูกบันทึกไว้บนสแต็ก ทำให้การปรับใช้งานที่กำลังร้อนเป็นเรื่องง่าย! ที่จริงแล้ว สิ่งที่เราต้องทำคือสร้างความแตกต่างระหว่างโค้ดที่ใช้งานได้กับเวอร์ชันใหม่ จากนั้นจึงปรับใช้โค้ดใหม่ ส่วนที่เหลือจะดำเนินการโดยอัตโนมัติด้วยเครื่องมือภาษา! หากคุณคิดว่านี่เป็นนิยายวิทยาศาสตร์ โปรดคิดใหม่อีกครั้ง เป็นเวลาหลายปีที่วิศวกรของ Erlang ได้อัปเดตระบบที่ทำงานอยู่โดยไม่ขัดจังหวะ
การใช้เหตุผลและการเพิ่มประสิทธิภาพของเครื่องช่วย
คุณสมบัติที่น่าสนใจของภาษาเชิงฟังก์ชันคือสามารถให้เหตุผลทางคณิตศาสตร์ได้ เนื่องจากภาษาเชิงฟังก์ชันเป็นเพียงการนำระบบที่เป็นทางการไปใช้ การดำเนินการทั้งหมดที่ทำบนกระดาษจึงสามารถนำไปใช้กับโปรแกรมที่เขียนด้วยภาษานี้ได้ คอมไพเลอร์สามารถใช้ทฤษฎีทางคณิตศาสตร์เพื่อแปลงโค้ดชิ้นหนึ่งให้เป็นโค้ดที่เทียบเท่ากันแต่มีประสิทธิภาพมากกว่า [7] ฐานข้อมูลเชิงสัมพันธ์ได้รับการปรับให้เหมาะสมประเภทนี้มาหลายปีแล้ว ไม่มีเหตุผลว่าทำไมเทคนิคนี้จึงไม่สามารถนำไปใช้กับซอฟต์แวร์ทั่วไปได้
นอกจากนี้ คุณสามารถใช้เทคนิคเหล่านี้เพื่อพิสูจน์ว่าบางส่วนของโปรแกรมของคุณถูกต้อง และอาจสร้างเครื่องมือเพื่อวิเคราะห์โค้ดของคุณและสร้าง Edge Case โดยอัตโนมัติสำหรับการทดสอบหน่วยอีกด้วย ฟังก์ชันการทำงานนี้ไม่มีประโยชน์ต่อระบบที่แข็งแกร่ง แต่หากคุณกำลังออกแบบเครื่องกระตุ้นหัวใจหรือระบบควบคุมการจราจรทางอากาศ เครื่องมือนี้ก็เป็นสิ่งที่ขาดไม่ได้ หากแอปพลิเคชันที่คุณเขียนไม่ใช่งานหลักในอุตสาหกรรม เครื่องมือประเภทนี้สามารถช่วยให้คุณมีไพ่เหนือกว่าคู่แข่งของคุณได้
23.4.3 ข้อเสียของการเขียนโปรแกรมเชิงฟังก์ชัน
ผลข้างเคียงของการปิด
ในการเขียนโปรแกรมเชิงฟังก์ชันที่ไม่เข้มงวด การปิดสามารถแทนที่สภาพแวดล้อมภายนอกได้ (เราได้เห็นแล้วในบทที่แล้ว) ซึ่งนำมาซึ่งผลข้างเคียง และเมื่อผลข้างเคียงดังกล่าวเกิดขึ้นบ่อยครั้ง และเมื่อใด สภาพแวดล้อมที่โปรแกรมรันมีการเปลี่ยนแปลงบ่อยครั้ง ข้อผิดพลาดกลายเป็นเรื่องยากที่จะติดตาม
//สิ่งที่ต้องทำ:
แบบฟอร์มแบบเรียกซ้ำ
แม้ว่าการเรียกซ้ำมักจะเป็นรูปแบบการแสดงออกที่กระชับที่สุด แต่ก็ไม่เป็นไปตามสัญชาตญาณเหมือนกับการวนซ้ำแบบไม่เรียกซ้ำ
//TODO:
จุดอ่อนของค่าล่าช้า
//TODO: