มีคำตอบที่ดีมาก ฉันจะพยายามมีส่วนร่วมในการอภิปราย
ในหัวข้อของการประกาศการเขียนโปรแกรมเชิงตรรกะใน Prolog มีหนังสือที่ดี "หัตถกรรมของเปิดฉาก" โดยริชาร์ดโอคีฟ มันเกี่ยวกับการเขียนโปรแกรมที่มีประสิทธิภาพโดยใช้ภาษาการเขียนโปรแกรมที่ช่วยให้คุณเขียนโปรแกรมที่ไม่มีประสิทธิภาพมาก ในหนังสือเล่มนี้ในขณะที่พูดถึงการใช้งานที่มีประสิทธิภาพของอัลกอริทึมหลาย (ในบท "วิธีการเขียนโปรแกรม") ผู้เขียนใช้วิธีการดังต่อไปนี้:
- กำหนดปัญหาเป็นภาษาอังกฤษ
- เขียนวิธีแก้ปัญหาการทำงานที่เปิดเผยเท่าที่จะทำได้ โดยปกตินั่นหมายถึงสิ่งที่คุณมีในคำถามของคุณเพียงแก้ไข Prolog
- จากนั้นทำตามขั้นตอนเพื่อปรับแต่งการใช้งานเพื่อให้เร็วขึ้น
การสังเกตที่แจ่มแจ้งที่สุด (สำหรับฉัน) ฉันสามารถทำในขณะที่ทำงานทางของฉันผ่านสิ่งเหล่านี้:
ใช่เวอร์ชันสุดท้ายของการนำไปใช้นั้นมีประสิทธิภาพมากกว่าข้อกำหนด "แบบเปิดเผย" ที่ผู้เขียนเริ่มต้นขึ้น มันยังคงมีความชัดเจนกระชับและเข้าใจง่าย สิ่งที่เกิดขึ้นระหว่างนั้นคือทางออกสุดท้ายที่จับคุณสมบัติของปัญหาที่การแก้ปัญหาเริ่มต้นลืมเลือน
กล่าวอีกนัยหนึ่งในขณะที่ใช้งานโซลูชันเราได้ใช้ความรู้เกี่ยวกับปัญหามากที่สุดเท่าที่จะทำได้ เปรียบเทียบ:
ค้นหาการเรียงลำดับของรายการที่องค์ประกอบทั้งหมดอยู่ในลำดับจากน้อยไปหามาก
ที่:
การรวมสองรายการที่เรียงลำดับจะส่งผลให้เกิดรายการเรียงลำดับ เนื่องจากอาจมีรายการย่อยที่เรียงลำดับแล้วให้ใช้สิ่งเหล่านี้เป็นจุดเริ่มต้นแทนที่จะเป็นรายการย่อยที่มีความยาว 1
เล็ก ๆ น้อย ๆ : ความหมายเหมือนที่คุณให้ไว้เป็นที่น่าสนใจเพราะมันเป็นเรื่องทั่วไปมาก อย่างไรก็ตามฉันไม่สามารถหลบหนีจากความรู้สึกที่ตั้งใจเพิกเฉยต่อความจริงที่ว่าการเรียงสับเปลี่ยนนั้นเป็นปัญหา combinatorial นี่คือสิ่งที่เรารู้อยู่แล้ว! นี่ไม่ใช่การวิจารณ์เพียงแค่การสังเกต
สำหรับคำถามจริง: จะก้าวไปข้างหน้าอย่างไร วิธีหนึ่งคือการให้ความรู้มากเกี่ยวกับปัญหาที่เราประกาศกับคอมพิวเตอร์
พยายามที่ดีที่สุดของฉันรู้ว่าจริงๆการแก้ปัญหาจะนำเสนอในหนังสือร่วมประพันธ์โดยอเล็กซานเด Stepanov, "องค์ประกอบของการเขียนโปรแกรม"และ"จากคณิตศาสตร์ทั่วไปการเขียนโปรแกรม" ฉันเศร้าที่ไม่ได้สรุปงานทุกอย่างในหนังสือเหล่านี้ อย่างไรก็ตามวิธีการในการกำหนดอัลกอริธึมไลบรารีและโครงสร้างข้อมูลที่มีประสิทธิภาพ (หรือดีที่สุด) ภายใต้ข้อกำหนดที่ทราบคุณสมบัติทั้งหมดที่เกี่ยวข้องของอินพุตล่วงหน้า ผลลัพธ์สุดท้ายคือ:
- การแปลงที่กำหนดชัดเจนแต่ละครั้งคือการปรับแต่งข้อ จำกัด ที่มีอยู่แล้ว (คุณสมบัติที่เป็นที่รู้จัก)
- เราให้คอมพิวเตอร์ตัดสินใจว่าการแปลงใดจะเหมาะสมที่สุดตามข้อ จำกัด ที่มีอยู่
ทำไมมันถึงยังไม่เกิดขึ้นวิทยาศาสตร์คอมพิวเตอร์เป็นสาขาที่เล็กมากและเรายังคงเผชิญกับความซาบซึ้งในความแปลกใหม่ของมันเกือบทั้งหมด
PS
เพื่อให้คุณได้ลิ้มรสสิ่งที่ฉันหมายถึงโดย "การปรับใช้งาน": ยกตัวอย่างเช่นปัญหาง่าย ๆ ในการรับองค์ประกอบสุดท้ายของรายการใน Prolog วิธีแก้ปัญหาที่ประกาศที่ยอมรับคือ:
last(List, Last) :-
append(_, [Last], List).
ที่นี่ความหมายที่เปิดเผยของappend/3
คือ:
List1AndList2
คือการต่อกันของList1
และList2
เนื่องจากในอาร์กิวเมนต์ที่สองที่append/3
เรามีรายการที่มีเพียงองค์ประกอบเดียวและอาร์กิวเมนต์แรกจะถูกละเว้น (ขีดล่าง) เราจะได้รับการแยกรายการเดิมซึ่งแยกหน้ารายการ ( List1
ในบริบทของappend/3
) และเรียกร้องให้ ด้านหลัง ( List2
ในบริบทของappend/3
) เป็นรายการที่มีองค์ประกอบเดียวเท่านั้น: ดังนั้นจึงเป็นองค์ประกอบสุดท้าย
อย่างไรก็ตามการใช้งานจริงโดย SWI-Prologกล่าวว่า:
last([X|Xs], Last) :-
last_(Xs, X, Last).
last_([], Last, Last).
last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
นี่คือการประกาศอย่างดี อ่านจากบนลงล่างพูดว่า:
องค์ประกอบสุดท้ายของรายการจะใช้กับรายการองค์ประกอบอย่างน้อยหนึ่งรายการเท่านั้น องค์ประกอบสุดท้ายสำหรับคู่ของหางและส่วนหัวของรายการคือ: หัวเมื่อหางว่างเปล่าหรือสุดท้ายของหางที่ไม่ว่างเปล่า
เหตุผลที่ทำให้การใช้งานนี้มีไว้เพื่อแก้ไขปัญหาในทางปฏิบัติที่อยู่รอบตัวแบบจำลองการทำงานของ Prolog โดยหลักการแล้วมันไม่ควรสร้างความแตกต่างที่จะใช้การใช้งาน ในทำนองเดียวกันเราอาจกล่าวได้ว่า:
last(List, Last) :-
reverse(List, [Last|_]).
องค์ประกอบสุดท้ายของรายการคือองค์ประกอบแรกของรายการที่กลับรายการ
หากคุณต้องการที่จะได้รับการเติมของคุณของการอภิปรายสรุปไม่ได้เกี่ยวกับสิ่งที่เป็นสิ่งที่ดีที่เปิดเผยเปิดฉากเพียงแค่ผ่านไปบางส่วนของคำถามและคำตอบในแท็กเปิดฉากในกองมากเกิน