สำรวจว่าแนวคิดเชิงสัญลักษณ์ของ John McCarthy และไอเดียการออกแบบของ Lisp — รายการ การเรียกซ้ำ และการเก็บขยะ — ส่งผลต่อ AI และการเขียนโปรแกรมสมัยใหม่อย่างไร

นี่ไม่ใช่การพาทัวร์พิพิธภัณฑ์ของ “AI เก่า” แต่เป็นบทเรียนประวัติศาสตร์เชิงปฏิบัติสำหรับใครก็ตามที่สร้างซอฟต์แวร์—โปรแกรมเมอร์ ทีมเทค และผู้สร้างผลิตภัณฑ์—เพราะไอเดียของ John McCarthy เปลี่ยนวิธีที่เราคิดว่า ภาษาโปรแกรมมีไว้เพื่ออะไร
Lisp ไม่ได้เป็นแค่ไวยากรณ์ใหม่ มันเป็นเดิมพันว่าซอฟต์แวร์สามารถจัดการกับแนวคิดได้ (ไม่ใช่แค่ตัวเลข) และการเลือกการออกแบบภาษาสามารถเร่งงานวิจัย การวนปรับผลิตภัณฑ์ และระบบนิเวศเครื่องมือได้ทั้งหมด
วิธีที่มีประโยชน์ในการอ่านมรดกของ McCarthy คือมองเป็นคำถามที่ยังสำคัญจนถึงวันนี้: เราจะเปลี่ยนความตั้งใจเป็นระบบที่รันได้โดยตรงได้มากแค่ไหน—โดยไม่จมอยู่กับโบยเลอร์เพลต ความฝืด หรือความซับซ้อนโดยไม่ตั้งใจ? คำถามนี้สะท้อนจาก REPL ของ Lisp จนถึงเวิร์กโฟลว์สมัยใหม่แบบ “แชทเป็นแอป”
John McCarthy ไม่ได้ถูกจดจำแค่เพราะช่วยเปิดสาขาการวิจัย AI แต่เพราะยืนยันในชนิดเฉพาะของ AI: ระบบที่สามารถ จัดการแนวคิด ไม่ใช่แค่คำนวณคำตอบ ในกลางทศวรรษ 1950 เขาจัด Dartmouth Summer Research Project (ซึ่งมีการเสนอคำว่า “artificial intelligence”) และต่อมาได้มีอิทธิพลต่อการทำงานด้าน AI ที่ MIT และ Stanford แต่ผลงานที่คงทนที่สุดอาจเป็นคำถามที่เขายังผลักดันอยู่: ถ้าเราสามารถแสดงการเหตุผลเป็นโปรแกรมล่ะ?
ความสำเร็จของการคำนวณในยุคแรก ๆ มักเป็นเชิงตัวเลข: ตารางลูกกระสุน การจำลองด้านวิศวกรรม การเพิ่มประสิทธิภาพ และสถิติ ปัญหาเหล่านี้เหมาะกับเลขคณิต
McCarthy มุ่งสู่สิ่งที่ต่างออกไป การคิดของมนุษย์มักทำงานกับแนวคิดอย่าง “ถ้า”, “เพราะว่า”, “เป็นของ”, “เป็นชนิดของ” และ “ทุกสิ่งที่ตรงตามเงื่อนไขเหล่านี้” ซึ่งไม่ได้แทนได้อย่างเป็นธรรมชาติด้วยค่าทศนิยม
แนวทางของ McCarthy ถือว่าความรู้เป็น สัญลักษณ์ (ชื่อ ความสัมพันธ์ หมวดหมู่) และถือว่าการคิดคือ การเปลี่ยนแปลงตามกฎ เหนือสัญลักษณ์เหล่านั้น
ภาพระดับสูง: วิธีเชิงตัวเลขตอบคำถามว่า “เท่าไหร่?” ขณะที่วิธีเชิงสัญลักษณ์พยายามตอบ “มันคืออะไร?” และ “อะไรที่สามารถสรุปได้จากสิ่งที่เรารู้?”
เมื่อเชื่อว่าการเหตุผลสามารถทำให้เป็นโปรแกรมได้ คุณก็ต้องการภาษาที่สามารถแทนนิพจน์เช่นกฎ คำสั่งเชิงตรรกะ และความสัมพันธ์ซ้อนกันได้อย่างสบาย ๆ — แล้วประมวลผลมัน
Lisp ถูกสร้างเพื่อจุดมุ่งหมายนี้ แทนที่จะบังคับให้แนวคิดเข้าไปในโครงสร้างข้อมูลที่ตายตัว Lisp ทำให้เป็นเรื่องธรรมชาติที่จะให้โค้ดและความรู้มีรูปร่างที่คล้ายกัน การเลือกนี้ไม่ใช่แค่สไตล์วิชาการ — มันเป็นสะพานเชิงปฏิบัติระหว่าง การบรรยายความคิด กับ การรันขั้นตอนปฏิบัติ ซึ่งเป็นสะพานที่ McCarthy ต้องการให้ AI ข้าม
เมื่อ McCarthy และนักวิจัย AI ยุคแรกพูดว่า “สัญลักษณ์” พวกเขาไม่ได้หมายถึงคณิตศาสตร์ลึกลับ สัญลักษณ์ เป็นเพียงป้ายที่มีความหมาย: ชื่อเช่น customer, คำเช่น hungry, หรือแท็กเช่น IF และ THEN สัญลักษณ์สำคัญเพราะช่วยให้โปรแกรมทำงานกับ แนวคิด (หมวด ความสัมพันธ์ กฎ) แทนที่จะทำงานกับตัวเลขเปล่า ๆ เท่านั้น
วิธีคิดง่าย ๆ: สเปรดชีตยอดเยี่ยมเมื่อโลกของคุณเป็นคอลัมน์และการคำนวณ แต่ระบบเชิงสัญลักษณ์ยอดเยี่ยมเมื่อโลกของคุณมีทั้งกฎ หมวดหมู่ ข้อยกเว้น และโครงสร้าง
ในโปรแกรมหลายแห่ง ความต่างระหว่าง 42 กับ "age" ไม่ใช่ชนิดข้อมูล—แต่เป็นสิ่งที่ค่าดังกล่าว แทน สัญลักษณ์ให้คุณสิ่งที่คุณเทียบ เก็บ และรวมกันได้โดยไม่เสียความหมาย
นั่นทำให้เป็นธรรมชาติเพื่อแทนสิ่งอย่าง “ปารีสเป็นเมือง” หรือ “ถ้าแบตใกล้หมด ให้หาที่ชาร์จ”
เพื่อทำอะไรกับสัญลักษณ์ได้ คุณต้องการโครงสร้าง Lisp ทำให้เป็นที่นิยมของโครงสร้างที่ง่ายมาก: รายการ รายการคือกลุ่มเรียงลำดับของไอเทม และไอเทมเหล่านั้นสามารถเป็นรายการได้เอง ด้วยความคิดนี้อย่างเดียว คุณสามารถแทนประโยค ฟอร์ม และความรู้รูปทรงต้นไม้ได้
นี่คือตัวอย่างแนวคิดเล็ก ๆ (แสดงในสไตล์คล้าย Lisp):
(sentence (subject robot) (verb needs) (object power))
อ่านออกเกือบเหมือนภาษาอังกฤษ: ประโยคประกอบด้วย subject, verb, และ object เพราะมันมีโครงสร้าง โปรแกรมจึงสามารถดึง (subject robot) หรือแทนที่ (object power) ด้วยอย่างอื่นได้
เมื่อข้อมูลอยู่ในโครงสร้างเชิงสัญลักษณ์ งานคลาสสิกของ AI จะเข้าถึงได้ง่ายขึ้น:
จุดเปลี่ยนสำคัญคือโปรแกรมไม่ได้แค่คำนวณ มันกำลังจัดการชิ้นส่วนความรู้ที่มีความหมายในรูปแบบที่มันตรวจสอบและแปลงได้
การตัดสินใจออกแบบของ Lisp ไม่ได้อยู่เพียงในมหาวิทยาลัย มันกระทบวิธีที่ผู้คนสร้างเครื่องมือและความเร็วในการสำรวจแนวคิด:
ลักษณะเหล่านี้มักสร้างระบบนิเวศที่การทดลองมีราคาถูก ต้นแบบกลายเป็นผลิตภัณฑ์ได้ไว ทีมปรับตัวเมื่อความต้องการเปลี่ยน
Lisp เริ่มจากปัญหาการออกแบบเชิงปฏิบัติ: จะเขียนโปรแกรมที่ ทำงานกับสัญลักษณ์ ได้อย่างเป็นธรรมชาติเหมือนการทำงานกับตัวเลขได้อย่างไร?
McCarthy ไม่ได้พยายามสร้าง "เครื่องคิดเลขที่ดีกว่า" เขาต้องการภาษาที่นิพจน์เช่น (is (parent Alice Bob)) สามารถถูกเก็บ ตรวจสอบ แปลง และเหตุผลได้ง่ายพอ ๆ กับ (+ 2 3)
ลำดับความสำคัญคือทำให้ข้อมูลสัญลักษณ์แทนและจัดการง่าย นั่นนำไปสู่การมุ่งเน้นที่รายการและโครงสร้างต้นไม้ เพราะเหมาะกับสิ่งที่มนุษย์ใช้เพื่อแสดงความหมาย: ประโยค กฎเชิงตรรกะ หมวดหมู่ซ้อน และความสัมพันธ์
อีกเป้าหมายคือรักษาคอร์ของภาษาที่เล็กและสอดคล้อง เมื่อภาษามี "กรณีพิเศษ" น้อยลง คุณใช้เวลาน้อยลงในการจำกฎและมากขึ้นในการประกอบไอเดีย Lisp เลือกบล็อกก่อสร้างเพียงเล็กน้อยที่สามารถนำมาประกอบเป็นนามธรรมขนาดใหญ่ได้
อินไซด์สำคัญคือโปรแกรมและข้อมูลสามารถมีโครงสร้างชนิดเดียวกันได้ ง่าย ๆ: ถ้าข้อมูลของคุณเป็นรายการซ้อน โปรแกรมของคุณก็อาจเป็นรายการซ้อนเช่นกัน
นั่นหมายความว่าคุณสามารถ:
Lisp ยังส่งเสริมทัศนะว่า: ภาษาไม่จำเป็นต้องเป็นแบบ one-size-fits-all พวกมันสามารถออกแบบรอบโดเมนปัญหา—เช่น การเหตุผล การค้นหา และการแทนความรู้—และยังคงมีอิทธิพลต่อการเขียนโปรแกรมทั่วไปได้เป็นเวลาหลายทศวรรษ
S-expressions (ย่อมาจาก symbolic expressions) คือแนวคิดสำคัญของ Lisp: วิธีเดียวที่สม่ำเสมอในการแทนโค้ดและข้อมูลเป็นรายการซ้อน
โดยสังเขป S-expression คือวงเล็บล้อมรายการ—บางไอเทมเป็นอะตอม (เช่น ชื่อและตัวเลข) และบางไอเทมเป็นรายการเอง กฎ "รายการข้างในรายการ" คือใจความทั้งหมด
เพราะโครงสร้างเป็นเอกภาพ โปรแกรม Lisp ถูกสร้างจากบล็อกก่อสร้างเดียวกันตั้งแต่บนลงล่าง การเรียกฟังก์ชัน ชิ้นข้อมูลแบบคอนฟิก และโครงสร้างโปรแกรมต่างก็สามารถแสดงเป็นรายการได้
ความสม่ำเสมอนั้นให้ผลทันที:
แม้คุณจะไม่เขียน Lisp คำเรียนรู้นี้ก็คือ: เมื่อระบบสร้างจากรูปแบบที่คาดเดาได้ไม่กี่แบบ คุณใช้เวลาในการแก้ปัญหาพิเศษน้อยลงและสร้างได้มากขึ้น
S-expressions กระตุ้นให้เกิดการประกอบเพราะชิ้นเล็ก ๆ ที่อ่านง่ายจะรวมกันเป็นชิ้นใหญ่ได้อย่างเป็นธรรมชาติ เมื่อโปรแกรมของคุณเป็นเพียง "รายการซ้อน" การรวมไอเดียมักหมายถึงการซ้อนนิพจน์หนึ่งในอีกนิพจน์หนึ่งหรือประกอบรายการจากชิ้นที่นำกลับมาใช้ได้
สิ่งนี้ผลักดันให้คุณเขียนฟังก์ชันเล็ก ๆ ที่ทำสิ่งเดียว แล้วต่อกันเพื่อแสดงเจตนาที่ใหญ่กว่า
ข้อเสียที่ชัดคือความไม่คุ้นเคย สำหรับผู้เริ่มต้น ไวยากรณ์ที่มีวงเล็บหนาแน่นดูแปลก
แต่ข้อดีคือความคาดเดาได้: เมื่อคุณเข้าใจกฎการซ้อน คุณจะเห็นโครงสร้างของโปรแกรมได้อย่างน่าเชื่อถือ—และเครื่องมือก็เช่นกัน ความชัดเจนนี้เป็นเหตุผลสำคัญที่ S-expressions ส่งผลไกลเกินกว่า Lisp เอง
การเรียกซ้ำเข้าใจง่ายที่สุดผ่านอุปมาในชีวิตประจำวัน: เก็บห้องรกโดยแบ่งเป็นห้องเล็ก ๆ คุณไม่พยายามแก้ทุกอย่างในครั้งเดียว คุณหยิบของหนึ่งชิ้น วางที่ที่มันควรอยู่ แล้วทำซ้ำกับสิ่งที่เหลือ ขั้นตอนเรียบง่าย พลังอยู่ที่การทำซ้ำจนกว่าจะไม่มีอะไรเหลือให้ทำ
Lisp ส่งเสริมนิสัยนี้เพราะข้อมูลส่วนใหญ่สร้างจากรายการ: รายการมี "สิ่งแรก" และ "ที่เหลือ" รูปร่างนี้เหมาะกับการคิดแบบเรียกซ้ำอย่างยิ่ง
เมื่อต้องประมวลรายการ คุณจัดการกับองค์ประกอบแรก แล้วประยุกต์ตรรกะเดียวกันกับส่วนที่เหลือ เมื่อรายการว่าง คุณหยุด—นั่นเป็นโมเมนต์ "ไม่มีอะไรเหลือให้ทำ" ที่ชัดเจนซึ่งทำให้การเรียกซ้ำรู้สึกนิยามได้แทนที่จะลึกลับ
สมมติคุณต้องการผลรวมของรายการตัวเลข
นั่นคือทั้งหมด คำจำกัดความอ่านเหมือนภาษาอังกฤษ และโครงสร้างโปรแกรมสะท้อนแนวคิด
AI เชิงสัญลักษณ์มักแทนนิพจน์เป็นโครงสร้างต้นไม้ (ตัวดำเนินการกับซับนิพจน์) การเรียกซ้ำเป็นวิธีธรรมชาติในการ "เดิน" ต้นไม้นั้น: ประเมินซีกซ้ายด้วยวิธีเดียวกับซีกขวา และทำต่อจนกว่าจะถึงค่าที่เรียบง่าย
รูปแบบเหล่านี้ช่วยหล่อหลอมการเขียนโปรแกรมเชิงฟังก์ชันในภายหลัง: ฟังก์ชันเล็ก ๆ กรณีฐานชัดเจน และการแปลงข้อมูลที่ง่ายต่อการคิดตาม แม้นอก Lisp นิสัยการแยกงานเป็น "ทำสเต็ปเดียว แล้วทำซ้ำกับที่เหลือ" ก็ช่วยให้โค้ดสะอาดและผลข้างเคียงน้อยลง
โปรแกรมเมอร์ยุคแรกมักต้องจัดการหน่วยความจำด้วยมือ: จองพื้นที่ ติดตามว่าใครเป็นเจ้าของ และจำได้ว่าต้องคืนพื้นที่เมื่อไหร่ งานนั้นไม่เพียงแต่ชะลอการพัฒนา มันสร้างบั๊กชนิดพิเศษที่หายากและยากจะทำซ้ำ: การรั่วไหลของหน่วยความจำ และพอยน์เตอร์ลอยที่ทำให้โปรแกรมล่มหลังจากเวลานาน
John McCarthy แนะนำการเก็บขยะสำหรับ Lisp เพื่อให้โปรแกรมเมอร์มุ่งที่ ความหมาย แทนการทำบัญชี
ในระดับสูง GC หาองค์ประกอบหน่วยความจำที่โปรแกรมไม่สามารถเข้าถึงได้อีกแล้ว—ค่าที่ไม่มีอะไรจะใช้ต่อ—แล้วคืนพื้นที่นั้น
แทนที่จะถามว่า “เราได้ free ทุกออบเจ็กต์หนึ่งครั้งหรือไม่?” GC เปลี่ยนเป็นคำถามว่า “ออบเจ็กต์นี้ยังเข้าถึงได้หรือไม่?” ถ้าโปรแกรมเข้าถึงมันไม่ได้ มันถือว่าเป็นขยะ
งาน AI เชิงสัญลักษณ์ Lisp มักสร้างรายการ ต้นไม้ และผลกลางจำนวนมาก การจัดการหน่วยความจำด้วยมือจะทำให้การทดลองกลายเป็นการต่อสู้กับการจัดการทรัพยากร
GC เปลี่ยนประสบการณ์การทำงานประจำวัน:
ไอเดียสำคัญคือฟีเจอร์ภาษาสามารถเป็น ตัวคูณทีม: เวลาที่เสียไปในการดีบักปัญหาการคอร์รัปชันน้อยลง หมายถึงเวลาที่ใช้พัฒนาตรรกะจริง ๆ มากขึ้น
การตัดสินใจของ McCarthy ไม่ได้หยุดที่ Lisp ระบบต่อมาหลายระบบนำ GC ไปใช้ (และเวอร์ชันต่าง ๆ) เพราะผลตอบแทนมักคุ้มค่า: Java, C#, Python, JavaScript runtimes, และ Go ต่างใช้ garbage collection เพื่อทำให้การพัฒนาระดับใหญ่ปลอดภัยและเร็วขึ้น—แม้ในกรณีที่ให้ความสำคัญกับประสิทธิภาพ
ใน Lisp, นิพจน์ คือชิ้นโค้ดที่เขียนในรูปร่างสม่ำเสมอ (มักเป็นรายการ) การประเมิน คือกระบวนการตัดสินว่านิพจน์นั้น หมายความว่าอะไร และ ผลิตอะไร ขึ้น
ตัวอย่างเช่น เมื่อคุณเขียน "บวกตัวเลขเหล่านี้" หรือนิพจน์ที่เรียกฟังก์ชันด้วยอินพุต เครื่องประมวลผลจะทำตามกฎชุดเล็ก ๆ เพื่อแปลงนิพจน์นั้นเป็นผลลัพธ์ คิดว่ามันเป็นกรรมการของภาษา: ตัดสินว่าจะทำอะไร ลำดับใด และเมื่อไหร่จะหยุด
ก้าวสำคัญของ McCarthy ไม่ใช่แค่คิดไวยากรณ์ใหม่—แต่คือการเก็บ "เครื่องกำหนดความหมาย" ให้กะทัดรัดและสม่ำเสมอ เมื่อ evaluator สร้างจากกฎชัดเจนไม่กี่ข้อ จะเกิดสองสิ่งดี:
ความสม่ำเสมอนี้เป็นเหตุผลหนึ่งที่ Lisp เป็นสนามทดลองสำหรับไอเดียใน AI เชิงสัญลักษณ์: นักวิจัยสามารถลองแทนตัวแทนและโครงสร้างควบคุมใหม่ ๆ ได้รวดเร็ว โดยไม่ต้องรอทีมคอมไพเลอร์ออกแบบใหม่
มาโครคือวิธีของ Lisp ที่ให้คุณอัตโนมัติรูปแบบโค้ดที่ซ้ำกัน ไม่ใช่แค่ค่าที่ซ้ำ เช่น ฟังก์ชันช่วยหลีกเลี่ยงการทำซ้ำการคำนวณ มาโครช่วยหลีกเลี่ยงการทำซ้ำรูปแบบโค้ดทั่วไป—เช่น “ทำ X แล้วก็ล็อกมัน” หรือ “กำหนด DSL เล็ก ๆ สำหรับกฎ”
ผลเชิงปฏิบัติคือ Lisp สามารถสร้างความสะดวกใหม่ ๆ จากภายในได้ หลายเครื่องมือสมัยใหม่สะท้อนแนวคิดนี้—ระบบเทมเพลต ตัวสร้างโค้ด และฟีเจอร์เมตาโปรแกรมมิง—เพราะพวกมันสนับสนุนเป้าหมายเดียวกัน: การทดลองเร็วและเจตนาที่ชัดเจน
ถ้าคุณอยากรู้ว่าทัศนคตินี้มีอิทธิพลต่อเวิร์กโฟลว์การพัฒนาอย่างไร ดูบทความที่เกี่ยวข้อง: "The REPL and Fast Feedback Loops"
ส่วนสำคัญของเสน่ห์ของ Lisp ไม่ได้อยู่แค่ที่ภาษา แต่มาจากวิธีการทำงาน Lisp ทำให้ REPL เป็นที่นิยม: Read–Eval–Print Loop ในคำง่าย ๆ มันเหมือนการคุยกับคอมพิวเตอร์ คุณพิมพ์นิพจน์ ระบบรันมันทันที พิมพ์ผล แล้วรออินพุตถัดไป
แทนที่จะเขียนโปรแกรมทั้งก้อน คอมไพล์ มัน แล้วไล่หาจุดที่พัง คุณสามารถลองไอเดียทีละเล็กทีละน้อย นิยามฟังก์ชัน ทดสอบด้วยอินพุตไม่กี่ค่า แก้ไข แล้วทดสอบอีกครั้ง—ทั้งหมดในไม่กี่วินาที
จังหวะนี้สนับสนุนการทดลอง ซึ่งสำคัญอย่างยิ่งสำหรับงานวิจัย AI ยุคแรกที่คุณมักไม่รู้แนวทางที่ถูกต้องตั้งแต่แรก
ฟีดแบ็กเร็วทำให้ "เดิมพันใหญ่" กลายเป็น "เช็กย่อย" สำหรับการวิจัย มันช่วยให้สำรวจสมมติฐานและตรวจสอบผลกลางได้ง่ายขึ้น
สำหรับการต้นแบบผลิตภัณฑ์ มันลดต้นทุนการวนปรับ: คุณสามารถตรวจสอบพฤติกรรมด้วยข้อมูลจริงได้เร็ว สังเกตกรณีขอบได้ก่อน และปรับฟีเจอร์โดยไม่ต้องรอคิวบิวด์นาน
นี่คือเหตุผลที่เครื่องมือสมัยใหม่ที่เน้น vibe-coding น่าสนใจ: พวกมันบีบอัดวงจรฟีดแบ็กอย่างมาก ตัวอย่างเช่น Koder.ai ใช้หน้าแชท (มีสถาปัตยกรรมแบบตัวแทนด้านหลัง) เพื่อเปลี่ยนความตั้งใจของผลิตภัณฑ์ให้เป็นโค้ดเว็บ แบ็กเอนด์ หรือมือถือที่ใช้งานได้อย่างรวดเร็ว—ทำให้ลูป "ลอง → ปรับ → ลองอีกครั้ง" รู้สึกใกล้เคียงกับ REPL มากกว่าพายพัฒนาปกติ
ไอเดีย REPL ปรากฏในวันนี้ได้แก่:
เครื่องมือต่างกัน แต่หลักการเดียวกัน: ย่นระยะทางระหว่างการคิดกับการเห็น
ทีมจะได้ประโยชน์จากเวิร์กโฟลว์แบบ REPL เมื่อพวกเขากำลังสำรวจความต้องการไม่แน่นอน สร้างฟีเจอร์ที่หนักข้อมูล ออกแบบ API หรือตรวจจุดบั๊กที่ซับซ้อน ถ้างานเกี่ยวข้องกับการเรียนรู้รวดเร็ว—เกี่ยวกับผู้ใช้ ข้อมูล หรือกรณีขอบ—การฟีดแบ็กเชิงโต้ตอบไม่ใช่หรูหรา แต่มันเป็นตัวคูณ
Lisp ไม่ได้ “ชนะ” โดยกลายเป็นไวยากรณ์ที่ทุกคนใช้ แต่ชนะโดยการหว่านไอเดียที่กลายเป็นเรื่องปกติข้ามระบบนิเวศหลายแห่ง
แนวคิดที่ Lisp ถือเป็นค่าดีฟอลต์ — ฟังก์ชันเป็นค่าหนึ่ง การใช้การดำเนินการระดับสูง และการประกอบนามธรรม — ปรากฏแพร่หลายในปัจจุบัน แม้ภาษาไม่เหมือน Lisp ก็สนับสนุนการแปลงแบบ map/filter นิสัยข้อมูลไม่เปลี่ยน และการคิดแบบเรียกซ้ำ (บ่อยครั้งผ่าน iterator หรือ fold)
การเปลี่ยนจิตวิทยาคือ: มองการแปลงข้อมูลเป็นไปป์ไลน์ และมองพฤติกรรมเป็นสิ่งที่คุณสามารถส่งต่อได้
Lisp ทำให้โปรแกรมง่ายต่อการแทนเป็นข้อมูล ทัศนะนี้ปรากฏวันนี้ในวิธีที่เราสร้างและจัดการ ASTs สำหรับคอมไพเลอร์ เครื่องฟอร์แมต ลินเตอร์ และตัวสร้างโค้ด เมื่อคุณทำงานกับ AST คุณกำลังทำงานใกล้เคียงกับ "โค้ดเป็นข้อมูล" แม้โครงสร้างจะเป็น JSON โหนดประเภท หรือกราฟไบต์โค้ด
แนวทางเชิงสัญลักษณ์เดียวกันขับเคลื่อนการอัตโนมัติที่ใช้งานได้จริง: รูปแบบการตั้งค่า ระบบเทมเพลต และพายป์ไลน์บิวด์ล้วนอาศัยการแทนแบบมีโครงสร้างที่เครื่องมือสามารถตรวจสอบ แปลง และตรวจสอบได้
ภาษาในตระกูล Lisp สมัยใหม่ (ในความหมายกว้าง: Lisp ยุคปัจจุบันและเครื่องมือแรงบันดาลใจจาก Lisp) ยังคงมีอิทธิพลต่อการออกแบบ DSL ภายในทีม—ภาษาเล็ก ๆ สำหรับการทดสอบ การปรับใช้ การจัดการข้อมูล หรือ UI
นอก Lisp ระบบมาโคร ไลบรารีเมตาโปรแกรมมิง และเฟรมเวิร์กตัวสร้างโค้ดพยายามผลลัพธ์เดียวกัน: ขยายภาษาให้พอดีกับปัญหา
ข้อสรุปเชิงปฏิบัติ: รสนิยมไวยากรณ์เปลี่ยนได้ แต่ไอเดียที่ทนทาน—โครงสร้างเชิงสัญลักษณ์ ฟังก์ชันที่ประกอบได้ และความสามารถขยาย—ยังคงให้ประโยชน์ต่อเนื่อง
Lisp มีชื่อเสียงแกว่งไปมาระหว่าง “อัจฉริยะ” กับ “อ่านยาก” ซึ่งมักมาจากความประทับใจมือสองมากกว่าประสบการณ์จริง ความจริงค่อนข้างธรรมดา: Lisp ทำทางเลือกที่ทรงพลังในบริบทที่เหมาะสม แต่ไม่สะดวกในบางสถานการณ์
สำหรับผู้เริ่มต้น ไวยากรณ์ของ Lisp อาจรู้สึกเหมือนมอง "ด้านใน" ของโปรแกรม มากกว่าผิวที่ขัดเกลา ความไม่สบายนี้มีจริง โดยเฉพาะถ้าคุณชินกับภาษาที่ไวยากรณ์แยกคอนสตรักต์ต่าง ๆ ให้เห็นชัด
แต่ในประวัติศาสตร์ โครงสร้างของ Lisp คือประเด็น: โค้ดและข้อมูลมีรูปร่างเดียวกัน ซึ่งทำให้โปรแกรมง่ายต่อการแปลง สร้าง และวิเคราะห์ เมื่อมี editor ที่ดี โค้ด Lisp มักถูกอ่านจากรูปร่างมากกว่าการนับวงเล็บ
สเตริโอไทป์ทั่วไปคือ Lisp ช้า ในประวัติศาสตร์ บางไดอะเลกต์อาจช้ากว่าภาษาระดับล่าง และฟีเจอร์ไดนามิกอาจเพิ่มโอเวอร์เฮด
แต่ไม่ถูกต้องที่จะมองว่า “Lisp” มีโปรไฟล์ประสิทธิภาพเดียว ระบบ Lisp หลายรุ่นรองรับการคอมไพล์ การประกาศชนิด และการปรับแต่งอย่างจริงจัง กรอบคิดที่มีประโยชน์กว่าคือ: คุณต้องการการควบคุมการจัดวางหน่วยความจำ ความหน่วงที่คาดการณ์ได้ หรือ throughput ดิบมากแค่ไหน—และการใช้งาน Lisp ของคุณรองรับความต้องการนั้นหรือไม่
อีกข้อวิจารณ์ที่ยุติธรรมคือความเข้ากันได้ของระบบนิเวศ ขึ้นกับไดอะเลกต์ Lisp และโดเมน ไลบรารี เครื่องมือ และกลุ่มผู้สมัครอาจเล็กกว่าสแต็กหลัก สิ่งนี้สำคัญเมื่อต้องส่งของเร็วกับทีมกว้าง
แทนที่จะตัดสิน Lisp จากสเตริโอไทป์ ให้ประเมินไอเดียพื้นฐานแยกจากกัน: โครงสร้างแบบสม่ำเสมอ การพัฒนาเชิงโต้ตอบ และมาโครเป็นเครื่องมือสำหรับสร้างนามธรรมตามโดเมน แม้คุณจะไม่ส่งระบบ Lisp จริง ๆ ไอเดียเหล่านี้สามารถทำให้วิธีคิดเกี่ยวกับการออกแบบภาษาและการเขียนโค้ดของคุณดีขึ้น
McCarthy ไม่ได้ทิ้งเราไว้เพียงภาษาทางประวัติศาสตร์—เขาทิ้งนิสัยที่ยังทำให้ซอฟต์แวร์แก้ไข อธิบาย และขยายได้ง่ายขึ้น
ก่อนเลือกไลบรารีหรือสถาปัตยกรรม ให้หยิบฟีเจอร์จริง—เช่น “กฎส่วนลด” หรือ “การกำหนดเส้นทางตั๋วสนับสนุน”—แล้ว วาดมันเป็นต้นไม้ จากนั้นเขียนต้นไม้เป็นรายการซ้อน (หรือ JSON) ถามว่า: โหนดคืออะไร ใบคืออะไร และคุณต้องการทรานส์ฟอร์มอะไรบ้าง?
แม้ไม่ใช้ Lisp คุณก็สามารถนำทัศนคตินี้: สร้างการแทนแบบ AST, ใช้การสร้างโค้ดสำหรับงานเชื่อมต่อซ้ำ ๆ, และมาตรฐานไปที่ไปป์ไลน์แบบ "parse → transform → evaluate" ทีมหลายแห่งได้ประโยชน์โดยทำให้ตัวแทนกลางชัดเจน
ถ้าคุณชอบหลักการ REPL แต่ต้องส่งฟีเจอร์ในสแต็กกระแสหลัก ก็สามารถยืมจิตวิญญาณผ่านเครื่องมือ: วงจรการวนปรับที่แน่น แคปเจอร์สแน็ปช็อต/ย้อนกลับ และการวางแผนชัดเจนก่อนการรัน Koder.ai ตัวอย่างเช่น มีโหมดวางแผนพร้อมสแน็ปช็อตและการย้อนกลับเพื่อให้การวนปรับเร็วแต่ปลอดภัย—เป็นเงาเชิงปฏิบัติของหลักการ Lisp: เปลี่ยนเร็ว แต่ควบคุมได้
อิทธิพลที่ยั่งยืนของ McCarthy คือ: การโปรแกรมทรงพลังขึ้นเมื่อเราทำให้การเหตุผลเองกลายเป็นสิ่งที่โปรแกรมได้—และรักษาทางจากไอเดียสู่ระบบที่รันได้ให้ตรงที่สุดเท่าที่จะเป็นไปได้.
การคิดเชิงสัญลักษณ์แทนที่จะแทนค่าด้วยตัวเลขโดยตรง จะเป็นการแทนแนวคิดและความสัมพันธ์อย่างตรงไปตรงมา (เช่น “customer”, “is-a”, “depends-on”, “if…then…”), แล้วใช้กฎและการทรานส์ฟอร์มกับการแทนเหล่านั้น
มันมีประโยชน์เมื่อปัญหาของคุณเต็มไปด้วยโครงสร้าง ข้อยกเว้น และความหมาย (เช่น เครื่องยนต์กฎ กำหนดแผน คอมไพเลอร์ การตั้งค่า กฎเวิร์กโฟลว์) มากกว่าการคำนวณเลขเพียงอย่างเดียว.
McCarthy ผลักดันมุมมองที่ว่า การเหตุผลสามารถถูกแสดงออกเป็นโปรแกรมได้ — ไม่ใช่แค่การคำนวณเท่านั้น.
มุมมองนี้ส่งผลต่อ:
รายการ (lists) เป็นวิธีที่เรียบง่ายและยืดหยุ่นในการเป็น “สิ่งที่ประกอบด้วยส่วนย่อย” เพราะสมาชิกในรายการสามารถเป็นรายการได้เอง ทำให้เกิด โครงสร้างแบบต้นไม้ โดยธรรมชาติ
นั่นทำให้ทำได้ง่ายที่จะ:
S-expressions ให้คุณมี รูปร่างเดียวที่สม่ำเสมอ สำหรับโค้ดและข้อมูล: รายการแบบซ้อน
ความสม่ำเสมอนั้นมักทำให้ระบบง่ายขึ้นเพราะ:
มาโครเป็นการอัตโนมัติสำหรับ รูปแบบโค้ดที่ซ้ำกัน ไม่ใช่แค่การคำนวณที่ซ้ำกัน
ใช้มาโครเมื่อคุณต้องการ:
ถ้าคุณต้องการตรรกะที่นำกลับมาใช้ใหม่เพียงอย่างเดียว ฟังก์ชันมักเป็นตัวเลือกที่ดีกว่า.
การเก็บขยะ (garbage collection, GC) จะค้นหาและคืนพื้นที่หน่วยความจำที่โปรแกรมไม่สามารถเข้าถึงได้อีกต่อไป ซึ่งช่วยลดข้อผิดพลาดหลายชนิด (พอยน์เตอร์ลอย หลุดคู่)
มันมีประโยชน์เป็นพิเศษเมื่อโปรแกรมสร้างโครงสร้างชั่วคราวจำนวนมาก (รายการ/ต้นไม้/AST) เพราะคุณสามารถต้นแบบและรีแฟกเตอร์ได้โดยไม่ต้องออกแบบนโยบายความเป็นเจ้าของหน่วยความจำตั้งแต่แรก
REPL ย่อจาก Read–Eval–Print Loop ซึ่งย่อช่วงเวลา "คิด → ลอง → สังเกต" ให้สั้นลง คุณสามารถนิยามฟังก์ชัน รัน ทดสอบ และแก้ไขได้ในไม่กี่วินาที
เพื่อรับประโยชน์เดียวกันในสแต็กที่ไม่ใช่ Lisp:
อ่านที่เกี่ยวข้อง: บทความ "The REPL and Fast Feedback Loops"
ไอเดียจาก Lisp แพร่หลายไปสู่การทำงานทั่วไป:
map/filter, การประกอบ)แม้คุณจะไม่ส่ง Lisp ในงานจริง คุณก็น่าจะใช้ อยู่แล้วในชีวิตประจำวัน
ข้อแลกเปลี่ยนและความเข้าใจผิดที่พบจริงได้แก่:
แนวทางปฏิบัติ: ประเมินไอเดียพื้นฐาน (โครงสร้างสม่ำเสมอ การพัฒนาเชิงโต้ตอบ มาโคร) ตามโดเมนและข้อจำกัด แทนการตัดสินจากชื่อเสียงเพียงอย่างเดียว.
ลองทำแบบฝึกหัด 10 นาทีนี้:
สิ่งนี้มักเปิดเผยจุดที่ "โค้ดเป็นข้อมูล" รูปแบบรันไทม์สำหรับกฎ หรือ DSL จะช่วยให้ระบบเรียบง่ายขึ้น