กลับไปหน้าบทความ

อ่าน 30 นาที

ลิสป์ (ภาษาโปรแกรม)

Lisp (ในอดีต เรียกว่า LISP ซึ่งเป็นคำย่อของ "list processing") เป็นตระกูลของ ภาษาโปรแกรม ที่มีประวัติยาวนานและมีลักษณะเฉพาะคือการเขียน แบบพรีฟิกที่ มีวงเล็บ ครบถ้วน [ 3 ]...

ลิสป์ (ภาษาโปรแกรม)

Lisp (ในอดีต เรียกว่า LISPซึ่งเป็นคำย่อของ "list processing") เป็นตระกูลของภาษาโปรแกรมที่มีประวัติยาวนานและมีลักษณะเฉพาะคือการเขียนแบบพรีฟิกที่มีวงเล็บ ครบถ้วน [ 3 ] เดิมทีมีการกำหนดขึ้นในช่วงปลายทศวรรษ 1950 เป็นภาษาโปรแกรมระดับสูงที่ เก่าแก่เป็นอันดับสอง ที่ยังคงใช้กันอย่างแพร่หลาย รองจากFortran [ 4 ] [ 5 ] Lisp มีการเปลี่ยนแปลงไปตั้งแต่ยุคแรกเริ่ม และ มี ภาษาถิ่น มากมาย ตลอดประวัติศาสตร์ ปัจจุบัน ภาษาถิ่น Lisp ที่เป็นที่รู้จักมากที่สุดสำหรับการใช้งานทั่วไป ได้แก่Common Lisp , Scheme , RacketและClojure [ 6 ] [ 7 ] [ 8 ]

ภาษา Lisp ถูกสร้างขึ้นมาในตอนแรกในฐานะสัญกรณ์ทางคณิตศาสตร์ ที่ใช้งานได้จริง สำหรับโปรแกรมคอมพิวเตอร์ โดย ได้รับอิทธิพลจาก (แม้ว่าจะไม่ได้มาจาก) [ 9 ]สัญกรณ์ของ แคลคูลัส แลมบ์ดาของAlonzo Churchและในไม่ช้าก็กลายเป็นภาษาโปรแกรมที่ได้รับความนิยมสำหรับ การวิจัย ปัญญาประดิษฐ์ (AI) [ 10 ] ในฐานะหนึ่งในภาษาโปรแกรมยุคแรกๆ Lisp ได้บุกเบิกแนวคิดมากมายในวิทยาศาสตร์คอมพิวเตอร์รวมถึงโครงสร้างข้อมูลแบบต้นไม้การจัดการพื้นที่จัดเก็บข้อมูลอัตโนมัติการกำหนดประเภทแบบไดนามิกเงื่อนไขฟังก์ชันลำดับสูงการเรียกซ้ำ คอม ไพเลอร์ แบบโฮสต์ตัวเอง [ 11 ]และลูปอ่าน-ประเมิน-พิมพ์[ 12 ]

ชื่อLISPมาจาก "List Processor" [ 13 ]รายการเชื่อมโยงเป็นหนึ่งในโครงสร้างข้อมูล หลักของ Lisp และซอร์สโค้ด ของ Lisp ประกอบด้วยรายการ ดังนั้น โปรแกรม Lisp จึงสามารถจัดการซอร์สโค้ดเป็นโครงสร้างข้อมูลได้ ทำให้เกิด ระบบ มาโครที่ช่วยให้นักเขียนโปรแกรมสามารถสร้างไวยากรณ์ใหม่หรือภาษาเฉพาะโดเมน ใหม่ ที่ฝังอยู่ใน Lisp ได้

The interchangeability of code and data gives Lisp its instantly recognizable syntax. All program code is written as s-expressions, or parenthesized lists. A function call or syntactic form is written as a list with the function or operator's name first, and the arguments following; for instance, a function f that takes three arguments would be called as (farg1arg2arg3).

History

John McCarthy began developing Lisp in 1958 while he was at the Massachusetts Institute of Technology (MIT). He was motivated by a desire to create an AI programming language that would work on the IBM 704, as he believed that "IBM looked like a good bet to pursue Artificial Intelligence research vigorously."[14] He was inspired by Information Processing Language, which was also based on list processing, but did not use it because it was designed for different hardware and he found an algebraic language more appealing.[14] Due to these factors, he consulted on the design of the Fortran List Processing Language, which was implemented as a Fortran library. However, he was dissatisfied with it because it did not support recursion or a modern if-then-else statement (which was a new concept when Lisp was first introduced).[note 1][14]

McCarthy's original notation used bracketed "M-expressions" that would be translated into S-expressions. As an example, the M-expression car[cons[A,B]] is equivalent to the S-expression (car(consAB)). Once Lisp was implemented, programmers rapidly chose to use S-expressions, and M-expressions were abandoned.[14] M-expressions surfaced again with short-lived attempts of MLisp[15] by Horace Enea and CGOL by Vaughan Pratt.

Lisp was first implemented by Steve Russell on an IBM 704 computer using punched cards.[16] Russell was working for McCarthy at the time and realized (to McCarthy's surprise) that the Lisp eval function could be implemented in machine code.

According to McCarthy[17]

สตีฟ รัสเซลล์ บอกว่า "ดูสิ ทำไมผมไม่ลองเขียนโปรแกรมeval  นี้ ดู..." และผมก็บอกเขาว่า "ฮ่าๆ คุณกำลังสับสนระหว่างทฤษฎีกับการปฏิบัติeval นี้ มีไว้สำหรับการอ่าน ไม่ใช่สำหรับการคำนวณ" แต่เขาก็ยังทำต่อไป นั่นคือ เขาคอมไพล์evalในบทความของผมให้เป็น รหัสเครื่อง IBM 704แก้ไขข้อผิดพลาดแล้วก็โฆษณาว่าเป็นตัวแปลภาษา Lisp ซึ่งมันก็เป็นเช่นนั้นจริงๆ ดังนั้น ณ จุดนั้น ภาษา Lisp จึงมีรูปแบบอย่างที่เป็นอยู่ในปัจจุบัน ...

ผลลัพธ์ที่ได้คือตัวแปลภาษา Lisp ที่ใช้งานได้ ซึ่งสามารถใช้รันโปรแกรม Lisp หรือพูดให้ถูกต้องกว่านั้นคือ "ประเมินนิพจน์ Lisp"

มาโครภาษาแอสเซมบลีสองตัวสำหรับIBM 704กลายเป็นการดำเนินการพื้นฐานสำหรับการแยกรายการ: car ( เนื้อหาของส่วนที่อยู่ของหมายเลขรีจิสเตอร์) และcdr ( เนื้อหาของส่วนลดค่าของหมายเลขรีจิสเตอร์) [ 18 ]โดยที่ "รีจิสเตอร์" หมายถึงรีจิสเตอร์ ของ หน่วยประมวลผลกลาง (CPU) ของคอมพิวเตอร์ ภาษา Lisp ยังคงใช้ carand cdr( / k ɑːr /และ/ ˈ k ʊ d ər / ) สำหรับการดำเนินการที่ส่งคืนรายการแรกในรายการและส่วนที่เหลือของรายการตามลำดับ

McCarthy ได้เผยแพร่การออกแบบของ Lisp ในบทความในCommunications of the ACMเมื่อวันที่ 1 เมษายน พ.ศ. 2503 ในชื่อเรื่อง "Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I" [ 19 ] [ 20 ]เขาแสดงให้เห็นว่าด้วยตัวดำเนินการง่ายๆ เพียงไม่กี่ตัวและสัญกรณ์สำหรับฟังก์ชันนิรนามที่ยืมมาจาก Church เราสามารถสร้าง ภาษา Turing-completeสำหรับอัลกอริทึม ได้

คอมไพเลอร์ Lisp ตัวแรกที่สมบูรณ์ซึ่งเขียนด้วยภาษา Lisp นั้นถูกนำไปใช้ในปี 1962 โดย Tim Hart และ Mike Levin ที่ MIT และสามารถคอมไพล์ได้โดยการใช้ตัวแปลภาษา LISP ที่มีอยู่แล้วมาตีความโค้ดคอมไพเลอร์ ทำให้ได้ เอาต์พุต โค้ดเครื่องที่สามารถดำเนินการได้เร็วขึ้นถึง 40 เท่าเมื่อเทียบกับตัวแปลภาษา[ 21 ]คอมไพเลอร์นี้ได้แนะนำโมเดลการคอมไพล์แบบเพิ่มทีละขั้น ของ Lisp ซึ่งฟังก์ชันที่คอมไพล์และฟังก์ชันที่ตีความสามารถผสมผสานกันได้อย่างอิสระ ภาษาที่ใช้ในบันทึกของ Hart และ Levin นั้นใกล้เคียงกับสไตล์ Lisp สมัยใหม่มากกว่าโค้ดก่อนหน้าของ McCarthy

รูทีน การเก็บขยะได้รับการพัฒนาโดยแดเนียล เอ็ดเวิร์ดส์ นักศึกษาปริญญาโทของ MIT ก่อนปี 1962 [ 22 ]

ในช่วงทศวรรษ 1980 และ 1990 มีความพยายามอย่างมากที่จะรวมงานพัฒนาภาษา Lisp สายพันธุ์ใหม่ (ส่วนใหญ่เป็นผู้สืบทอดจากMaclispเช่นZetaLispและ NIL (New Implementation of Lisp)) ให้เป็นภาษาเดียว ภาษาใหม่นี้ คือ Common Lispซึ่งเข้ากันได้กับภาษาสายพันธุ์เดิมที่มันเข้ามาแทนที่ (หนังสือCommon Lisp the Languageระบุถึงความเข้ากันได้ของโครงสร้างต่างๆ) ในปี 1994 ANSIได้เผยแพร่มาตรฐาน Common Lisp ในชื่อ "ANSI X3.226-1994 Information Technology Programming Language Common Lisp"

ไทม์ไลน์

19581960พ.ศ. 25081970พ.ศ. 25181980พ.ศ. 25281990พ.ศ. 253820002548201020152020
 LISP 1, 1.5, LISP 2 (เลิกพัฒนาแล้ว)
 แมคลิสป์
 อินเตอร์ลิสป์
 เอ็มดีแอล
 เครื่อง Lisp Lisp
 โครงการ อาร์5อาร์เอส อาร์6อาร์เอส R7RS ขนาดเล็ก
 ไม่มี
 ZIL (ภาษาการใช้งาน Zork)
 ฟรานซ์ ลิสป์
 มิวลิสป์
 ลิสปาร์กทั่วไป มาตรฐาน ANSI
 เลอ ลิสป์
 โครงการ MIT
 เอ็กซ์แอลไอเอสพี
 ที
 เชซ สกีม
 อีแมคส์ ลิสป์
 ออโต้ลิสป์
 พิโคลิสป์
 กลเม็ด
 ยูลิสป์
 ไอเอสลิสป์
 โอเพ่นลิสป์
 โครงการ PLT แร็กเก็ต
 นิวลิสปาร์
 จีเอ็นยู ไกล์
 วิชวล LISP
 โคลจูร์
 อาร์ค
 แอลเอฟอี
 ไฮ

การเชื่อมต่อกับปัญญาประดิษฐ์

นับตั้งแต่เริ่มแรก Lisp มีความเชื่อมโยงอย่างใกล้ชิดกับ ชุมชนวิจัย ปัญญาประดิษฐ์โดยเฉพาะอย่างยิ่งบน ระบบ PDP-10 [ 23 ] Lisp ถูกใช้เป็นการนำภาษาMicro Planner มาใช้ ซึ่งใช้ในระบบ AI ชื่อดังอย่างSHRDLUในช่วงทศวรรษ 1970 เมื่อการวิจัย AI ก่อให้เกิดสาขาเชิงพาณิชย์ ประสิทธิภาพของระบบ Lisp ที่มีอยู่จึงกลายเป็นปัญหาที่เพิ่มมากขึ้น เนื่องจากโปรแกรมเมอร์จำเป็นต้องคุ้นเคยกับผลกระทบด้านประสิทธิภาพของเทคนิคและตัวเลือกต่างๆ ที่เกี่ยวข้องกับการนำ Lisp มาใช้[ 24 ]

ลำดับวงศ์ตระกูลและรูปแบบต่างๆ

ตลอดระยะเวลากว่าหกสิบปี ภาษา Lisp ได้ก่อให้เกิดรูปแบบต่างๆ มากมายบนพื้นฐานหลักของภาษา S-expression บางรูปแบบได้รับการกำหนดมาตรฐานและนำไปใช้งานโดยกลุ่มต่างๆ ที่มีลำดับความสำคัญแตกต่างกัน (ตัวอย่างเช่นCommon LispและSchemeมีหลายเวอร์ชัน) อย่างไรก็ตาม ในบางกรณี โครงการซอฟต์แวร์กำหนดภาษา Lisp โดยไม่มีมาตรฐาน และไม่มีการแบ่งแยกที่ชัดเจนระหว่างภาษาถิ่นและการใช้งาน (ตัวอย่างเช่นClojureและEmacs Lispจัดอยู่ในประเภทนี้)

ความแตกต่างระหว่างภาษาถิ่น (และ/หรือการใช้งาน) อาจเห็นได้ชัดเจน—ตัวอย่างเช่น Common Lisp ใช้คำหลักdefunในการตั้งชื่อฟังก์ชัน แต่ Scheme ใช้define[ หมายเหตุ 2 ]ภายในภาษาถิ่นที่เป็นมาตรฐาน การใช้งานที่สอดคล้องกับมาตรฐานจะรองรับภาษาหลักเดียวกัน แต่มีส่วนขยายและไลบรารีที่แตกต่างกัน บางครั้งสิ่งนี้ก็สร้างการเปลี่ยนแปลงที่เห็นได้ชัดเจนจากภาษาพื้นฐาน—ตัวอย่างเช่นGuile (การใช้งาน Scheme) ใช้define*เพื่อสร้างฟังก์ชันที่มีอาร์กิวเมนต์เริ่มต้นและ/หรืออาร์กิวเมนต์คำหลักซึ่งทั้งสองอย่างนี้ไม่ได้เป็นมาตรฐาน

ภาษาถิ่นที่มีความสำคัญทางประวัติศาสตร์

เครื่องLispในพิพิธภัณฑ์ MIT
4.3BSDจากมหาวิทยาลัยวิสคอนซินแสดงหน้าคู่มือการใช้งานFranz Lisp
  • LISP 1 [ 25 ] – การใช้งานครั้งแรก
  • LISP 1.5 [ 26 ] – เวอร์ชันที่เผยแพร่อย่างกว้างขวางครั้งแรก พัฒนาโดย McCarthy และคนอื่นๆ ที่ MIT ได้รับการตั้งชื่อเช่นนี้เพราะมีการปรับปรุงหลายอย่างจากตัวแปล "LISP 1" ดั้งเดิม แต่ไม่ใช่การปรับโครงสร้างครั้งใหญ่เหมือนLISP 2 ที่วางแผนไว้
  • Stanford LISP 1.6 [ 27 ] – เป็นรุ่นต่อจาก LISP 1.5 ที่พัฒนาที่Stanford AI Labและเผยแพร่อย่างกว้างขวางไปยังระบบPDP-10 ที่ใช้ระบบปฏิบัติการ TOPS-10 ต่อ มา Maclisp และ InterLisp ก็ทำให้ LISP ล้าสมัยไป
  • Maclisp [ 28 ] – พัฒนาขึ้นสำหรับ โครงการ MACของ MIT , MACLISP เป็นทายาทโดยตรงของ LISP 1.5 ทำงานบนระบบ PDP-10 และMulticsต่อมา MACLISP จะถูกเรียกว่า Maclisp และมักถูกเรียกว่า MacLisp คำว่า "MAC" ใน MACLISP ไม่เกี่ยวข้องกับMacintosh ของ Apple หรือMcCarthy
  • Interlisp [ 29 ] – พัฒนาที่BBN Technologiesสำหรับระบบ PDP-10 ที่ใช้ระบบปฏิบัติการ TENEXต่อมาได้รับการยอมรับเป็น Lisp "West coast" สำหรับเครื่อง Xerox Lisp ในชื่อ InterLisp-D เวอร์ชันขนาดเล็กที่เรียกว่า "InterLISP 65" ได้รับการเผยแพร่สำหรับคอมพิวเตอร์ Atari 8 บิตที่ใช้MOS Technology 6502 Maclisp และ InterLisp เป็นคู่แข่งที่แข็งแกร่ง
  • Franz Lisp – เดิมทีเป็น โครงการ ของมหาวิทยาลัยแคลิฟอร์เนีย เบิร์กลีย์ต่อมาได้รับการพัฒนาโดย Franz Inc. ชื่อนี้เป็นการดัดแปลงชื่อ " Franz Liszt " ในเชิงขำขัน และไม่ได้หมายถึงAllegro Common Lispซึ่งเป็นภาษาถิ่นของ Common Lisp ที่ Franz Inc. จำหน่ายในภายหลัง
  • muLISP – พัฒนาขึ้นครั้งแรกโดย Albert D. Rich และ David Stoutemeyer สำหรับระบบไมโครคอมพิวเตอร์ขนาดเล็ก วางจำหน่ายเชิงพาณิชย์ในปี 1979 โดยทำงานบนระบบ CP/M ที่มี RAM เพียง 64KB และต่อมาได้พอร์ตไปยัง MS-DOS การพัฒนาเวอร์ชัน MS-DOS สิ้นสุดลงในปี 1995 ซอฟต์แวร์ทางคณิตศาสตร์ "Derive" เขียนด้วย muLISP สำหรับ MS-DOS และต่อมาสำหรับ Windows จนถึงปี 2007
  • XLISPซึ่งเป็นพื้นฐานของAutoLISP
  • Standard LispและPortable Standard Lispได้รับการใช้งานและพอร์ตอย่างแพร่หลาย โดยเฉพาะอย่างยิ่งกับระบบพีชคณิตคอมพิวเตอร์ REDUCE
  • ZetaLispหรือเรียกอีกอย่างว่า Lisp Machine Lisp – ภาษาที่ใช้บนเครื่อง Lispเป็นภาษาที่สืบทอดมาจาก Maclisp โดยตรง ZetaLisp มีอิทธิพลอย่างมากต่อ Common Lisp
  • LeLispเป็นภาษาถิ่น Lisp ของฝรั่งเศส หนึ่งในตัวสร้างอินเทอร์เฟซ ตัวแรก (เรียกว่า SOS Interface [ 30 ] ) เขียนด้วย LeLisp
  • แผน (พ.ศ. 2518) [ 31 ]
  • Common Lisp (1984) ตามที่อธิบายไว้ในCommon Lisp the Language – เป็นการรวมความพยายามที่แตกต่างกันหลายประการ (ZetaLisp, Spice Lisp , NILและS-1 Lisp ) เพื่อสร้างภาษาถิ่นที่สืบทอดต่อ จาก Maclisp [ 32 ]โดยได้รับอิทธิพลจากภาษาถิ่น Scheme ด้วยเช่นกัน Common Lisp เวอร์ชันนี้สามารถใช้งานได้บนแพลตฟอร์มที่หลากหลายและได้รับการยอมรับจากหลายคนว่าเป็นมาตรฐานโดยพฤตินัย[ 33 ]จนกระทั่งมีการเผยแพร่ ANSI Common Lisp (ANSI X3.226-1994) ภาษาถิ่นย่อยที่แพร่หลายที่สุดของ Common Lisp ได้แก่Steel Bank Common Lisp (SBCL), CMU Common Lisp (CMU-CL), Clozure OpenMCL (อย่าสับสนกับ Clojure!), GNU CLisp และ Franz Lisp เวอร์ชันต่อมา ทั้งหมดนี้เป็นไปตามมาตรฐาน ANSI CL ในภายหลัง (ดูด้านล่าง)
  • ในเวอร์ชันแรก Dylanเป็นการผสมผสานระหว่าง Scheme กับ Common Lisp Object System
  • EuLisp – ความพยายามในการพัฒนาภาษา Lisp รูปแบบใหม่ที่มีประสิทธิภาพและสะอาดตามากขึ้น
  • ISLISP – ความพยายามในการพัฒนา Lisp ที่มีประสิทธิภาพและสะอาดขึ้นใหม่ ได้รับการกำหนดมาตรฐานเป็น ISO/IEC 13816:1997 [ 34 ]และต่อมาได้รับการแก้ไขเป็น ISO/IEC 13816:2007: [ 35 ]เทคโนโลยีสารสนเทศ – ภาษาโปรแกรม สภาพแวดล้อม และอินเทอร์เฟซซอฟต์แวร์ระบบ – ภาษาโปรแกรม ISLISP
  • รูปแบบ IEEE – มาตรฐาน IEEE, 1178–1990 (R1995)
  • ANSI Common LispมาตรฐานAmerican National Standards Institute (ANSI) สำหรับ Common Lisp ซึ่งสร้างขึ้นโดยคณะอนุกรรมการX3J13ได้รับมอบหมาย[ 36 ]ให้เริ่มต้นด้วยCommon Lisp: The Languageเป็นเอกสารพื้นฐาน และดำเนินการผ่าน กระบวนการ ฉันทามติ สาธารณะ เพื่อหาแนวทางแก้ไขปัญหาร่วมกันเกี่ยวกับการพกพาโปรแกรมและความเข้ากันได้ของการใช้งาน Common Lisp แม้ว่าจะเป็นมาตรฐาน ANSI อย่างเป็นทางการ แต่การนำไปใช้ การขาย การใช้งาน และอิทธิพลของ ANSI Common Lisp ก็มีให้เห็นและยังคงพบเห็นได้ทั่วโลก
  • ACL2หรือ "A Computational Logic for Applicative Common Lisp" เป็นภาษาโปรแกรมแบบประยุกต์ (ปราศจากผลข้างเคียง) ที่พัฒนามาจาก Common LISP ACL2 เป็นทั้งภาษาโปรแกรมที่สามารถจำลองระบบคอมพิวเตอร์ และเป็นเครื่องมือช่วยพิสูจน์คุณสมบัติของแบบจำลองเหล่านั้น
  • Clojureเป็นภาษา Lisp สายพันธุ์ใหม่ที่คอมไพล์เป็นJava virtual machineและเน้นเรื่องการทำงานพร้อมกัน เป็น พิเศษ
  • Game Oriented Assembly Lisp (หรือ GOAL) เป็นภาษาโปรแกรมสำหรับวิดีโอเกมที่พัฒนาโดยAndy GavinจากNaughty Dogโดยเขียนขึ้นโดยใช้ Allegro Common Lisp และถูกนำไปใช้ในการพัฒนาเกมซีรีส์ Jak and Daxter ทั้งหมด ที่พัฒนาโดย Naughty Dog

ตั้งแต่ปี 2000 จนถึงปัจจุบัน

หลังจากที่ความสนใจในภาษา Lisp ลดลงบ้างในช่วงทศวรรษ 1990 ความสนใจก็กลับมาเพิ่มขึ้นอีกครั้งหลังปี 2000 กิจกรรมใหม่ส่วนใหญ่เน้นไปที่การใช้งานCommon Lisp , Scheme , Emacs Lisp , ClojureและRacketรวมถึงการพัฒนาไลบรารีและแอปพลิเคชันแบบพกพาใหม่ๆ ด้วย

โปรแกรมเมอร์ Lisp รุ่นใหม่จำนวนมากได้รับแรงบันดาลใจจากนักเขียนเช่นPaul GrahamและEric S. Raymondให้หันมาใช้ภาษาที่คนอื่นมองว่าล้าสมัย โปรแกรมเมอร์ Lisp รุ่นใหม่มักอธิบายว่าภาษานี้เป็นประสบการณ์ที่เปิดโลกทัศน์และอ้างว่ามีประสิทธิภาพมากกว่าภาษาอื่นๆ อย่างมาก[ 37 ]การเพิ่มขึ้นของความตระหนักนี้อาจเปรียบเทียบได้กับ " ฤดูหนาวของ AI " และความนิยมของ Lisp ในช่วงกลางทศวรรษ 1990 [ 38 ]

ข้อมูล ณ ปี 2010มีการใช้งาน Common Lisp ที่ได้รับการดูแลรักษาอย่างต่อเนื่องจำนวน 11 รายการ[ 39 ]

ชุมชนโอเพนซอร์สได้สร้างโครงสร้างพื้นฐานสนับสนุนใหม่: CLikiเป็นวิกิที่รวบรวมข้อมูลที่เกี่ยวข้องกับ Common Lisp, ไดเร็กทอรี Common Lisp แสดงรายการทรัพยากร, #lisp เป็นช่อง IRC ยอดนิยมและอนุญาตให้แบ่งปันและแสดงความคิดเห็นเกี่ยวกับโค้ดตัวอย่าง (โดยได้รับการสนับสนุนจาก lisppaste ซึ่งเป็นบอท IRCที่เขียนด้วย Lisp), Planet Lisp [ 40 ]รวบรวมเนื้อหาของบล็อกต่างๆ ที่เกี่ยวข้องกับ Lisp, บน LispForum [ 41 ]ผู้ใช้พูดคุยเกี่ยวกับหัวข้อ Lisp, Lispjobs [ 42 ]เป็นบริการสำหรับการประกาศรับสมัครงาน และมีบริการข่าวรายสัปดาห์Weekly Lisp News Common-lisp.net เป็นเว็บไซต์โฮสติ้งสำหรับโครงการ Common Lisp โอเพนซอร์สQuicklisp [ 43 ]เป็นตัวจัดการไลบรารีสำหรับ Common Lisp

ครบรอบ 50 ปีของ Lisp (1958–2008) ได้รับการเฉลิมฉลองที่ LISP50@OOPSLA [ 44 ]มีการประชุมผู้ใช้ในท้องถิ่นเป็นประจำในบอสตัน แวนคูเวอร์ และฮัมบูร์ก กิจกรรมอื่นๆ ได้แก่ การประชุม European Common Lisp Meeting, European Lisp Symposium และการประชุม International Lisp Conference

ชุมชน Scheme ยังคงดูแลรักษาการใช้งานมากกว่า 20 รายการ อย่างต่อเนื่อง มีการพัฒนาการใช้งานใหม่ที่สำคัญหลายรายการ (Chicken, Gambit, Gauche, Ikarus, Larceny, Ypsilon) ในช่วงทศวรรษ 2000 มาตรฐาน Scheme ฉบับแก้ไข รายงาน 5เกี่ยวกับภาษาอัลกอริธึม Scheme [ 45 ]ได้รับการยอมรับอย่างกว้างขวางในชุมชน Scheme กระบวนการ ร้องขอการใช้งาน Schemeได้สร้างไลบรารีและส่วนขยายกึ่งมาตรฐานจำนวนมากสำหรับ Scheme ชุมชนผู้ใช้ของการใช้งาน Scheme แต่ละรายการยังคงเติบโตอย่างต่อเนื่อง กระบวนการกำหนดมาตรฐานภาษาใหม่เริ่มต้นขึ้นในปี 2003 และนำไปสู่มาตรฐาน Scheme R6RS ในปี 2007 การใช้งาน Scheme ในเชิงวิชาการสำหรับการสอนวิทยาการคอมพิวเตอร์ดูเหมือนจะลดลงบ้าง มหาวิทยาลัยบางแห่งไม่ได้ใช้ Scheme ในหลักสูตรเบื้องต้นวิทยาการคอมพิวเตอร์อีกต่อไป[ 46 ] [ 47 ]ปัจจุบัน MIT ใช้Pythonแทน Scheme สำหรับ หลักสูตร วิทยาศาสตรบัณฑิตสาขาคอมพิวเตอร์และหลักสูตรออนไลน์แบบเปิดขนาดใหญ่ MITx [ 48 ] [ 49 ]

มีภาษาถิ่นใหม่หลายภาษาของ Lisp ได้แก่Arc , Hy , Nu , Liskell และLFE (Lisp Flavored Erlang) ตัวแยกวิเคราะห์สำหรับJuliaนั้นถูกพัฒนาขึ้นด้วย Femtolisp ซึ่งเป็นภาษาถิ่นหนึ่งของScheme (Julia ได้รับแรงบันดาลใจจาก Scheme ซึ่งเป็นภาษาถิ่นหนึ่งของ Lisp อีกทีหนึ่ง)

ในเดือนตุลาคม 2019 พอล เกรแฮมได้เผยแพร่ข้อกำหนดสำหรับ Belซึ่งเป็น "ภาษาถิ่นใหม่ของ Lisp"

ภาษาถิ่นหลัก

Common LispและSchemeเป็นตัวแทนของสองกระแสหลักของการพัฒนาภาษา Lisp ภาษาทั้งสองนี้มีแนวทางการออกแบบที่แตกต่างกันอย่างมาก

Common Lispเป็นภาษาที่พัฒนาต่อจากMaclispอิทธิพลหลักมาจากLisp Machine Lisp , Maclisp, NIL , S-1 Lisp , Spice Lispและ Scheme [ 50 ] Common Lisp มีคุณสมบัติหลายอย่างของ Lisp Machine Lisp (ภาษา Lisp ขนาดใหญ่ที่ใช้ในการเขียนโปรแกรมLisp Machines ) แต่ได้รับการออกแบบให้สามารถใช้งานได้อย่างมีประสิทธิภาพบนคอมพิวเตอร์ส่วนบุคคลหรือเวิร์กสเตชันใดๆ Common Lisp เป็นภาษาโปรแกรมอเนกประสงค์ ดังนั้นจึงมีมาตรฐานภาษาขนาดใหญ่ รวมถึงชนิดข้อมูล ฟังก์ชัน มาโคร และองค์ประกอบภาษาอื่นๆ อีกมากมาย และระบบวัตถุ ( Common Lisp Object System ) นอกจากนี้ Common Lisp ยังยืมคุณสมบัติบางอย่างมาจาก Scheme เช่นขอบเขตคำศัพท์และการปิดคำศัพท์ มีการใช้งาน Lisp ทั่วไปสำหรับการกำหนดเป้าหมายแพลตฟอร์มต่างๆ เช่นLLVM [ 51 ]เครื่องเสมือน Java [ 52 ] x86-64 , PowerPC, Alpha, ARM, Motorola 68000 และ MIPS [ 53 ] และระบบปฏิบัติการ ต่างๆเช่น Windows, macOS, Linux, Solaris, FreeBSD, NetBSD, OpenBSD, Dragonfly BSD และ Heroku [ 54 ]

Schemeเป็นภาษาโปรแกรม Lisp ที่มีขอบเขตการทำงานแบบคงที่และใช้การเรียกซ้ำแบบหาง (tail-recursive) อย่างถูกต้อง คิดค้นโดยGuy L. Steele, Jr.และGerald Jay Sussmanได้รับการออกแบบให้มีความหมายที่ชัดเจนและเรียบง่ายเป็นพิเศษ และมีวิธีการสร้างนิพจน์เพียงไม่กี่วิธี Scheme ถูกออกแบบขึ้นประมาณหนึ่งทศวรรษก่อน Common Lisp จึงมีดีไซน์ที่เรียบง่ายกว่า มีชุดคุณสมบัติมาตรฐานที่น้อยกว่ามาก แต่มีคุณสมบัติการใช้งานบางอย่าง (เช่น การเพิ่มประสิทธิภาพการเรียกซ้ำแบบ หาง ( tail-call optimization ) และcontinuations เต็มรูปแบบ ) ที่ไม่ได้ระบุไว้ใน Common Lisp รูปแบบการเขียนโปรแกรมที่หลากหลาย รวมถึงแบบเชิงคำสั่ง (imperative), แบบเชิงฟังก์ชัน (functional) และการส่งข้อความ (message passing) สามารถแสดงออกได้อย่างสะดวกใน Scheme Scheme ยังคงพัฒนาอย่างต่อเนื่องด้วยชุดมาตรฐาน (Revised n Report on the Algorithmic Language Scheme) และชุดคำขอสำหรับการใช้งาน Scheme (Scheme Requests for Implementation )

Clojureเป็นภาษาถิ่นของ Lisp ที่มุ่งเป้าไปที่เครื่องเสมือน JavaและCommon Language Runtime (CLR) เครื่องเสมือน Pythonเครื่องเสมือน Ruby YARVและการคอมไพล์เป็นJavaScript เป็น หลัก มันถูกออกแบบมาให้เป็นภาษาอเนกประสงค์ที่ใช้งานได้จริง Clojure ได้รับอิทธิพลอย่างมากจากHaskellและให้ความสำคัญอย่างมากกับความไม่เปลี่ยนแปลง[ 55 ] Clojure ให้การเข้าถึงเฟรมเวิร์กและไลบรารีของ Java พร้อมคำแนะนำประเภทและการอนุมานประเภท ที่เป็นทางเลือก เพื่อให้การเรียกใช้ Java สามารถหลีกเลี่ยงการสะท้อนและเปิดใช้งานการดำเนินการพื้นฐานที่รวดเร็ว Clojure ไม่ได้ออกแบบมาให้เข้ากันได้กับภาษาถิ่น Lisp อื่นๆ[ 56 ]

นอกจากนี้ ภาษา Lisp ยังถูกใช้เป็นภาษาสคริปต์ในแอปพลิเคชันจำนวนมาก โดยภาษาที่รู้จักกันดีที่สุด ได้แก่Emacs Lispใน โปรแกรมแก้ไข Emacs , AutoLISPและVisual LispในAutoCAD , Nyquist ในAudacityและ Scheme ในLilyPondขนาดที่เล็กของตัวแปลภาษา Scheme ที่มีประโยชน์ทำให้เป็นที่นิยมเป็นพิเศษสำหรับการเขียนสคริปต์แบบฝังตัว ตัวอย่างเช่นSIODและTinySchemeซึ่งทั้งสองอย่างได้รับการฝังตัวใน โปรแกรมประมวลผลภาพ GIMPภายใต้ชื่อทั่วไปว่า "Script-fu" [ 57 ] LIBREP ซึ่งเป็นตัวแปลภาษา Lisp โดย John Harper ซึ่งเดิมทีมีพื้นฐานมาจาก ภาษา Emacs Lispได้รับการฝังตัวใน ตัว จัดการหน้าต่างSawfish [ 58 ]

ภาษาถิ่นมาตรฐาน

Lisp มีภาษาถิ่นมาตรฐานอย่างเป็นทางการ ได้แก่R6RS Scheme , R7RS Scheme , IEEE Scheme, [ 59 ] ANSI Common LispและISO ISLISP

นวัตกรรมทางภาษา

Paul Grahamระบุลักษณะสำคัญเก้าประการของ Lisp ที่แตกต่างจากภาษาที่มีอยู่ เช่นFortran : [ 60 ]

ภาษา Lisp เป็นภาษาแรกที่โครงสร้างของโค้ดโปรแกรมถูกแสดงอย่างถูกต้องและโดยตรงในโครงสร้างข้อมูลมาตรฐาน ซึ่งคุณสมบัตินี้ต่อมาถูกเรียกว่า " homoiconicity " ดังนั้น ฟังก์ชันในภาษา Lisp จึงสามารถถูกจัดการ เปลี่ยนแปลง หรือแม้แต่สร้างขึ้นภายในโปรแกรม Lisp โดยไม่ต้องมีการจัดการในระดับล่าง นี่ถือเป็นหนึ่งในข้อได้เปรียบหลักของภาษาในแง่ของพลังในการแสดงออก และทำให้ภาษานี้เหมาะสมสำหรับมาโครเชิงไวยากรณ์และการประเมินแบบวนซ้ำ

เงื่อนไขที่ใช้ไวยากรณ์if–then–elseถูกคิดค้นโดย McCarthy สำหรับโปรแกรมหมากรุกที่เขียนด้วยFortranเขาเสนอให้รวมไว้ในALGOLแต่ไม่ได้เป็นส่วนหนึ่งของ ข้อกำหนด Algol 58สำหรับ Lisp นั้น McCarthy ใช้โครงสร้างcond ที่ทั่วไปกว่า [ 61 ] Algol 60ได้นำif–then–else มาใช้ และทำให้เป็นที่นิยม

ภาษา Lisp มีอิทธิพลอย่างมากต่อAlan Kayหัวหน้าทีมวิจัยที่พัฒนาSmalltalkที่Xerox PARCและในทางกลับกัน Lisp ก็ได้รับอิทธิพลจาก Smalltalk โดยภาษา Lisp รุ่นต่อมาได้นำคุณสมบัติการเขียนโปรแกรมเชิงวัตถุ (เช่น คลาสสืบทอด, การห่อหุ้มอินสแตนซ์, การส่งข้อความ ฯลฯ) มาใช้ในช่วงทศวรรษ 1970 ระบบวัตถุ Flavorsได้แนะนำแนวคิดของการสืบทอดแบบหลายทางและmixin ระบบวัตถุ Common Lispให้การสืบทอดแบบหลายทาง มัลติเมธอดที่มีการเรียกใช้แบบหลายทางและฟังก์ชันเจเนริก ชั้นหนึ่ง ทำให้เกิดรูปแบบ การเรียกใช้แบบไดนามิกที่ยืดหยุ่นและทรงพลังระบบนี้ได้ทำหน้าที่เป็นแม่แบบสำหรับระบบวัตถุของ Lisp (รวมถึงScheme ) รุ่นต่อมาจำนวนมาก ซึ่งมักจะถูกนำไปใช้ผ่านโปรโตคอล metaobjectซึ่งเป็นการออกแบบแบบเมตาเซอร์คิวลาร์ที่สะท้อนกลับ โดยที่ระบบวัตถุถูกกำหนดในแง่ของตัวมันเอง: Lisp เป็นเพียงภาษาที่สองต่อจาก Smalltalk (และยังคงเป็นหนึ่งในไม่กี่ภาษา) ที่มีระบบ metaobject ดังกล่าว หลายปีต่อมา Alan Kay แนะนำว่าผลจากการรวมกันของคุณสมบัติเหล่านี้ ทำให้มีเพียง Smalltalk และ Lisp เท่านั้นที่สามารถถือได้ว่าเป็นระบบการเขียนโปรแกรมเชิงวัตถุที่คิดขึ้นอย่างถูกต้อง[ 62 ]

Lisp ได้นำเสนอแนวคิดของการเก็บขยะอัตโนมัติซึ่งระบบจะเดินสำรวจฮีปเพื่อค้นหาหน่วยความจำที่ไม่ได้ใช้งาน ความก้าวหน้าในอัลกอริธึมการเก็บขยะที่ซับซ้อนในปัจจุบัน เช่น การเก็บขยะแบบแบ่งรุ่น ได้รับการกระตุ้นจากการใช้งานใน Lisp [ 63 ]

เอ็ดสเกอร์ ดับเบิลยู. ไดจ์กสตรา กล่าวไว้ ใน สุนทรพจน์ รับรางวัลทัวริง ประจำปี 1972 ว่า

ด้วยหลักการพื้นฐานเพียงไม่กี่ข้อ LISP จึงแสดงให้เห็นถึงความเสถียรที่น่าทึ่ง นอกจากนั้น LISP ยังเป็นตัวกลางสำหรับแอปพลิเคชันคอมพิวเตอร์ที่ซับซ้อนที่สุดของเราจำนวนมาก LISP ถูกกล่าวติดตลกว่าเป็น "วิธีที่ชาญฉลาดที่สุดในการใช้คอมพิวเตอร์ในทางที่ผิด" ผมคิดว่าคำอธิบายนั้นเป็นคำชมที่ยอดเยี่ยม เพราะมันสื่อถึงรสชาติแห่งอิสรภาพอย่างเต็มที่: มันได้ช่วยเหลือเพื่อนมนุษย์ที่มีพรสวรรค์ที่สุดของเราหลายคนให้คิดในสิ่งที่ก่อนหน้านี้เป็นไปไม่ได้[ 64 ]

เนื่องจากความต้องการทรัพยากรของ Lisp ที่เกี่ยวข้องกับฮาร์ดแวร์คอมพิวเตอร์ยุคแรก (รวมถึงไมโครโปรเซสเซอร์ยุคแรก) ทำให้ Lisp ไม่ได้รับความนิยมมากนักนอกชุมชนAI เมื่อเทียบกับ Fortranและ ภาษา Cที่สืบทอดมาจากALGOLแต่เนื่องจากความเหมาะสมในการใช้งานที่ซับซ้อนและไดนามิก Lisp จึงกลับมาได้รับความสนใจจากสาธารณชนอีกครั้งในช่วงทศวรรษ 2010 [ 65 ]

ไวยากรณ์และความหมาย

ตัวอย่างในบทความนี้เขียนด้วยภาษาCommon Lisp (แต่ส่วนใหญ่ก็ใช้ได้กับภาษา Scheme เช่นกัน )

นิพจน์เชิงสัญลักษณ์ (นิพจน์ S)

ภาษา Lisp เป็นภาษาที่เน้นการใช้การแสดงออก (expression oriented language) แตกต่างจากภาษาอื่นๆ ส่วนใหญ่ Lisp ไม่แยกความแตกต่างระหว่าง "นิพจน์" และ"คำสั่ง"โค้ดและข้อมูลทั้งหมดเขียนในรูปของนิพจน์ เมื่อนิพจน์ถูกประเมินค่า จะได้ค่าหนึ่งค่า (อาจเป็นหลายค่า) ซึ่งสามารถนำไปใช้ในนิพจน์อื่นๆ ได้ แต่ละค่าสามารถเป็นชนิดข้อมูลใดก็ได้

บทความของ McCarthy ในปี 1958 ได้นำเสนอไวยากรณ์สองประเภท ได้แก่นิพจน์เชิงสัญลักษณ์ ( S-expressions , sexps) ซึ่งสะท้อนการแสดงผลภายในของโค้ดและข้อมูล และนิพจน์เมตา ( M-expressions ) ซึ่งแสดงฟังก์ชันของ S-expressions M-expressions ไม่ได้รับความนิยม และภาษา Lisp เกือบทั้งหมดในปัจจุบันใช้ S-expressions ในการจัดการทั้งโค้ดและข้อมูล

การใช้วงเล็บเป็นความแตกต่างที่เห็นได้ชัดที่สุดของ Lisp จากตระกูลภาษาโปรแกรมอื่นๆ ด้วยเหตุนี้ นักเรียนจึงมักตั้งฉายาให้ Lisp ว่าLost In Stupid ParenthesesหรือLots of Irritating Superfluous Parentheses [ 66 ] อย่างไรก็ตามไวยากรณ์ S-expression ก็เป็นส่วนสำคัญที่ทำให้ Lisp มีประสิทธิภาพมากเช่นกัน ไวยากรณ์นั้นเรียบง่ายและสอดคล้องกัน ซึ่งช่วยให้คอมพิวเตอร์สามารถจัดการได้ง่าย อย่างไรก็ตาม ไวยากรณ์ของ Lisp ไม่ได้จำกัดอยู่แค่การใช้วงเล็บแบบดั้งเดิมเท่านั้น มันสามารถขยายให้รวมสัญกรณ์ทางเลือกอื่นๆ ได้ ตัวอย่างเช่น XMLisp เป็นส่วนขยายของ Common Lisp ที่ใช้โปรโตคอล metaobjectเพื่อรวม S-expression เข้ากับ Extensible Markup Language ( XML )

การพึ่งพาการใช้นิพจน์ทำให้ภาษามีความยืดหยุ่นสูง เนื่องจากฟังก์ชันของ Lisp เขียนในรูปแบบของลิสต์ จึงสามารถประมวลผลได้เหมือนกับข้อมูล ทำให้เขียนโปรแกรมที่ควบคุมโปรแกรมอื่นได้ง่าย ( เมตาโปรแกรมมิง ) ภาษา Lisp หลายภาษาใช้ประโยชน์จากคุณสมบัตินี้โดยใช้ระบบมาโคร ซึ่งช่วยให้สามารถขยายภาษาได้เกือบไร้ขีดจำกัด

รายการ

ลิสต์ในภาษา Lisp เขียนโดยใช้ช่องว่าง คั่นระหว่างองค์ประกอบ และวงเล็บครอบไว้ ตัวอย่างเช่น ` list` คือลิสต์ที่มีองค์ประกอบเป็นอะตอม สามตัว ได้แก่ ` , , และ` ค่าเหล่านี้มีการกำหนดประเภทโดยปริยาย คือเป็นจำนวนเต็มสองตัวและชนิดข้อมูลเฉพาะของ Lisp ที่เรียกว่า "symbol" ตามลำดับ และไม่จำเป็นต้องประกาศเป็นชนิดข้อมูลดังกล่าว(12foo)12foo

รายการว่าง()เปล่ายังถูกแทนด้วยอะตอมพิเศษอีกด้วยnilนี่เป็นเอนทิตีเดียวในภาษาลิสป์ที่เป็นทั้งอะตอมและรายการในเวลาเดียวกัน

นิพจน์เขียนในรูปแบบรายการ โดยใช้สัญกรณ์แบบพรีฟิกองค์ประกอบแรกในรายการคือชื่อของฟังก์ชัน ชื่อของมาโคร นิพจน์แลมบ์ดา หรือชื่อของ "ตัวดำเนินการพิเศษ" (ดูด้านล่าง) ส่วนที่เหลือของรายการคืออาร์กิวเมนต์ ตัวอย่างเช่น ฟังก์ชันlistจะส่งคืนอาร์กิวเมนต์เป็นรายการ ดังนั้นนิพจน์จึงเป็นรายการ

( รายการ1 2 ( อ้างอิงfoo ))

ประเมินค่าเป็นลิสต์เครื่องหมาย "quote" ที่อยู่หน้าในตัวอย่างข้างต้น เป็น "ตัวดำเนินการพิเศษ" ซึ่งจะคืนค่าอาร์กิวเมนต์โดยไม่ต้องประเมินค่า นิพจน์ใดๆ ที่ไม่มีเครื่องหมาย quotee จะถูกประเมินค่าแบบเรียกซ้ำก่อนที่จะประเมินค่านิพจน์ที่อยู่ภายใน ตัวอย่างเช่น(12foo)foo

( รายการที่1 2 ( รายการที่3 4 ))

ประเมินค่าออกมาเป็นลิสต์อาร์กิวเมนต์ที่สามเป็นลิสต์ ซึ่งสามารถซ้อนกันได้(12(34))

ผู้ปฏิบัติงาน

ตัวดำเนินการทางคณิตศาสตร์ได้รับการปฏิบัติในลักษณะเดียวกัน นิพจน์

( + 1 2 3 4 )

มีค่าเท่ากับ 10 ค่าที่เทียบเท่าในรูปแบบการเขียนแบบอินฟิกซ์คือ " "1+2+3+4

ภาษา Lisp ไม่มีแนวคิดเรื่องตัวดำเนินการเหมือนใน ภาษาที่พัฒนามาจาก ALGOLตัวดำเนินการทางคณิตศาสตร์ใน Lisp เป็นฟังก์ชันแปรผัน (หรือn-ary ) ที่สามารถรับอาร์กิวเมนต์ได้หลายตัว ตัวดำเนินการเพิ่มค่าแบบ '++' ในแบบภาษา C บางครั้งก็ถูกนำมาใช้ภายใต้incfไวยากรณ์การตั้ง ชื่อ

( incf x )

เทียบเท่ากับ(setq x (+ x 1))การส่งคืนค่าใหม่xของ

"ตัวดำเนินการพิเศษ" (บางครั้งเรียกว่า "รูปแบบพิเศษ") เป็นโครงสร้างควบคุมของภาษา Lisp ตัวอย่างเช่น ตัวดำเนินการพิเศษifรับอาร์กิวเมนต์สามตัว ถ้าอาร์กิวเมนต์ตัวแรกไม่ใช่ค่าว่าง จะมีค่าเท่ากับอาร์กิวเมนต์ตัวที่สอง มิฉะนั้นจะมีค่าเท่ากับอาร์กิวเมนต์ตัวที่สาม ดังนั้นนิพจน์ `\n` จึงเป็นดังนี้

( ถ้าnil ( รายการ1 2 "foo" ) ( รายการ3 4 "bar" ))

ประเมินค่าได้เป็น. แน่นอนว่า วิธีนี้จะมีประโยชน์มากกว่าหากมีการแทนที่นิพจน์ที่ไม่ธรรมดาลงไปแทนที่.(34"bar")nil

นอกจากนี้ Lisp ยังมีตัวดำเนินการตรรกะand , orและnot ตัวดำเนินการ and และorจะทำการประเมินแบบลัดวงจร (short-circuit evaluation)และจะส่งคืนค่า nil และค่าที่ไม่ใช่ nil ตัวแรกตามลำดับ

( หรือ( และ"ศูนย์" nil "ไม่เคย" ) "เจมส์" 'งาน'เวลา)

จะประเมินผลเป็น "เจมส์"

นิพจน์แลมบ์ดาและการนิยามฟังก์ชัน

ตัวดำเนินการพิเศษอีกตัวหนึ่งคือlambda`false` ใช้สำหรับผูกตัวแปรกับค่าต่างๆ ซึ่งจะถูกประเมินค่าภายในนิพจน์ ตัวดำเนินการนี้ยังใช้ในการสร้างฟังก์ชันด้วย โดยอาร์กิวเมนต์ของ `false` lambdaคือรายการของอาร์กิวเมนต์ และนิพจน์หรือนิพจน์ต่างๆ ที่ฟังก์ชันจะประเมินค่า (ค่าที่ส่งคืนคือค่าของนิพจน์สุดท้ายที่ถูกประเมิน) นิพจน์

( แลมบ์ดา( อาร์กิวเมนต์) ( + อาร์กิวเมนต์1 ))

นิพจน์แลมบ์ดา จะประเมินค่าเป็นฟังก์ชันที่เมื่อนำไปใช้จะรับอาร์กิวเมนต์หนึ่งตัว ผูกค่าอาร์กิวเมนต์นั้นเข้ากับargตัวแปร และส่งคืนค่าที่มากกว่าอาร์กิวเมนต์นั้นหนึ่งค่า นิพจน์แลมบ์ดาได้รับการปฏิบัติไม่แตกต่างจากฟังก์ชันที่มีชื่อ กล่าวคือเรียกใช้ในลักษณะเดียวกัน ดังนั้น นิพจน์

(( แลมบ์ดา( อาร์กิวเมนต์) ( + อาร์กิวเมนต์1 )) 5 )

ประเมินค่าได้เป็น6. ในที่นี้ เรากำลังทำการเรียกใช้ฟังก์ชัน: เราเรียกใช้ฟังก์ชันนิรนามโดยส่งค่า 5 เข้าไป

ฟังก์ชันที่มีชื่อจะถูกสร้างขึ้นโดยการจัดเก็บนิพจน์แลมบ์ดาไว้ในสัญลักษณ์โดยใช้มาโคร defun

( defun foo ( a b c d ) ( + a b c d ))

(defunf(a)b...)กำหนดฟังก์ชันใหม่ชื่อfในสภาพแวดล้อมส่วนกลาง โดยหลักการแล้วคล้ายกับนิพจน์:

( setf ( fdefinition 'f ) #' ( lambda ( a ) ( block f b... )))

โดยที่setfเป็นมาโครที่ใช้ในการกำหนดค่าของอาร์กิวเมนต์แรกให้กับอ็อบเจ็กต์ฟังก์ชันใหม่เป็นคำจำกัดความฟังก์ชันส่วนกลางสำหรับฟังก์ชันชื่อเป็นตัวย่อของตัวดำเนินการพิเศษ ซึ่งส่งคืนอ็อบเจ็กต์ฟังก์ชันfdefinition'ffdefinitionf#'function

อะตอม

ในภาษา LISP ดั้งเดิม มีชนิดข้อมูล พื้นฐานสองชนิด ได้แก่ อะตอมและลิสต์ ลิสต์เป็นลำดับขององค์ประกอบที่มีจำนวนจำกัด โดยแต่ละองค์ประกอบเป็นได้ทั้งอะตอมหรือลิสต์ และอะตอมอาจเป็นตัวเลขหรือสัญลักษณ์ สัญลักษณ์โดยพื้นฐานแล้วคือรายการที่มีชื่อเฉพาะ เขียนเป็น สตริง ตัวอักษรและตัวเลขในซอร์สโค้ดและใช้เป็นชื่อตัวแปรหรือเป็นรายการข้อมูลในการประมวลผลเชิงสัญลักษณ์ตัวอย่างเช่น ลิสต์ประกอบด้วยสามองค์ประกอบ ได้แก่ สัญลักษณ์, ลิสต์และตัวเลข 2(FOO(BAR1)2)FOO(BAR1)

ข้อเสียและรายการต่างๆ

Cons-cell เป็นสัญลักษณ์ที่ปรากฏอยู่ทั่วไปในวรรณกรรม LISP

รายการ Lisp ถูกนำไปใช้เป็นรายการเชื่อมโยงเดี่ยว[ 67 ]แต่ละเซลล์ของรายการนี้เรียกว่าcons (ใน Scheme เรียกว่าpair ) และประกอบด้วยตัวชี้ สองตัว เรียกว่าcarและcdrซึ่งเทียบเท่ากับ ฟิลด์ dataและnextที่กล่าวถึงในบทความรายการเชื่อมโยง

ในบรรดาโครงสร้างข้อมูลมากมายที่สามารถสร้างขึ้นจากเซลล์ cons ได้ หนึ่งในโครงสร้างพื้นฐานที่สุดเรียกว่ารายการที่ถูกต้อง (proper list) รายการที่ถูกต้องอาจเป็นnilสัญลักษณ์พิเศษ (รายการว่าง) หรือ cons ที่carชี้ไปยังข้อมูล (ซึ่งอาจเป็นโครงสร้าง cons อื่น เช่น รายการ) และcdrชี้ไปยังรายการที่ถูกต้องอีกรายการหนึ่ง

ถ้าถือว่า cons ที่กำหนดเป็นหัวของลิสต์แบบเชื่อมโยงแล้ว car จะชี้ไปยังองค์ประกอบแรกของลิสต์ และ cdr จะชี้ไปยังส่วนที่เหลือของลิสต์ ด้วยเหตุนี้ ฟังก์ชัน `and` carและ ` or` cdrจึงถูกเรียกว่า `and` และ `or` firstเช่น กัน restเมื่ออ้างถึง cons ที่เป็นส่วนหนึ่งของลิสต์แบบเชื่อมโยง (แทนที่จะเป็นโครงสร้างแบบต้นไม้)

ดังนั้น รายการในภาษา Lisp จึงไม่ใช่วัตถุอะตอมิก เหมือนกับอินสแตนซ์ของคลาสคอนเทนเนอร์ใน C++ หรือ Java รายการเป็นเพียงการรวมกันของ cons ที่เชื่อมโยงกัน ตัวแปรที่อ้างถึงรายการที่กำหนดนั้นเป็นเพียงตัวชี้ไปยัง cons แรกในรายการ การท่องไปในรายการสามารถทำได้โดยการใช้คำสั่ง cdring ลงไปตามรายการ กล่าวคือ การใช้คำสั่ง cdring ต่อเนื่องกันเพื่อเยี่ยมชม cons แต่ละตัวในรายการ หรือโดยการใช้ฟังก์ชันลำดับสูง หลายฟังก์ชัน เพื่อแมปฟังก์ชันกับรายการ

เนื่องจาก conses และ lists เป็นโครงสร้างข้อมูลที่พบได้ทั่วไปในระบบ Lisp จึงมักเข้าใจผิดว่ามันเป็นโครงสร้างข้อมูลเพียงอย่างเดียวของ Lisp ที่จริงแล้ว Lisp เกือบทุกภาษา ยกเว้นภาษาที่เรียบง่ายที่สุด จะมีโครงสร้างข้อมูลอื่นๆ เช่น vectors ( arrays ), hash tables , structures และอื่นๆ อีกมากมาย

S-expression แทนรายการ

แผนภาพ กล่องและตัวชี้สำหรับรายการ (42 69 613)

นิพจน์ S ที่อยู่ในวงเล็บแสดงถึงโครงสร้างรายการเชื่อมโยง มีหลายวิธีในการแสดงรายการเดียวกันในรูปแบบนิพจน์ S cons สามารถเขียนในรูปแบบสัญกรณ์จุดคู่ได้เป็น โดยที่คือรถยนต์ และคือ cdr รายการที่ถูกต้องยาวกว่าอาจเขียนในรูปแบบสัญกรณ์จุดคู่ โดยทั่วไปจะย่อเป็นในสัญกรณ์รายการ รายการ ที่ไม่เหมาะสม[หมายเหตุ 3 ]อาจเขียนในรูปแบบผสมผสานระหว่างสองแบบ – เช่นรายการของ cons สามรายการที่มี cdr สุดท้ายคือ(นั่นคือ รายการในรูปแบบที่ระบุอย่างครบถ้วน)(a.b)ab(a.(b.(c.(d.nil))))(abcd)(abc.d)d(a.(b.(c.d)))

ขั้นตอนการประมวลผลรายการ

ภาษา Lisp มีขั้นตอนการทำงานในตัวมากมายสำหรับการเข้าถึงและควบคุมลิสต์ สามารถสร้างลิสต์ได้โดยตรงด้วยlistขั้นตอนการทำงาน ซึ่งรับอาร์กิวเมนต์ได้หลายตัว และส่งคืนลิสต์ของอาร์กิวเมนต์เหล่านั้น

( รายการ1 2 'a 3 ) ;ผลลัพธ์: (1 2 a 3)
( รายการ1 ' ( 2 3 ) 4 ) ;ผลลัพธ์: (1 (2 3) 4)

เนื่องจากวิธีการสร้างลิสต์จากคู่ consทำให้consสามารถใช้ขั้นตอนดังกล่าวเพื่อเพิ่มองค์ประกอบเข้าไปที่ด้านหน้าของลิสต์ได้consขั้นตอนนี้มีความไม่สมมาตรในการจัดการกับอาร์กิวเมนต์ที่เป็นลิสต์ เนื่องจากวิธีการสร้างลิสต์

( cons 1 ' ( 2 3 )) ;ผลลัพธ์: (1 2 3)
( cons ' ( 1 2 ) ' ( 3 4 )) ;ผลลัพธ์: ((1 2) 3 4)

กระบวนการ นี้appendจะเพิ่มลิสต์สองรายการ (หรือมากกว่า) เข้าด้วยกัน เนื่องจากลิสต์ในภาษา Lisp เป็นลิสต์แบบเชื่อมโยง การเพิ่มลิสต์สองรายการจึงมีความซับซ้อนเชิงเวลาแบบอะซิมโทติกโอ(n){\displaystyle O(n)}

( เพิ่ม' ( 1 2 ) ' ( 3 4 )) ;ผลลัพธ์: (1 2 3 4)
( เพิ่ม' ( 1 2 3 ) ' () ' ( a ) ' ( 5 6 )) ;ผลลัพธ์: (1 2 3 a 5 6)

โครงสร้างร่วมกัน

ลิสต์ในภาษา Lisp เป็นลิสต์เชื่อมโยงแบบง่าย จึงสามารถใช้โครงสร้างร่วมกันได้ กล่าวคือ ลิสต์สองลิสต์สามารถมีส่วนท้ายหรือลำดับสุดท้ายของผลลัพธ์ที่เหมือนกันได้ ตัวอย่างเช่น หลังจากดำเนินการโค้ด Common Lisp ต่อไปนี้:

( setf foo ( list 'a 'b 'c )) ( setf bar ( cons 'x ( cdr foo )))

รายการทั้งสองfooคือbarและตามลำดับ อย่างไรก็ตาม ส่วนท้ายของรายการทั้งสองมีโครงสร้างเหมือนกัน ไม่ใช่การคัดลอก เซลล์ cons ที่ชี้ไปยังและอยู่ในตำแหน่งหน่วยความจำเดียวกันสำหรับรายการทั้งสอง(abc)(xbc)(bc)bc

การใช้โครงสร้างร่วมกันแทนการคัดลอกสามารถช่วยเพิ่มประสิทธิภาพได้อย่างมาก อย่างไรก็ตาม เทคนิคนี้อาจส่งผลกระทบต่อการทำงานของฟังก์ชันที่แก้ไขลิสต์ที่ส่งเข้ามาเป็นอาร์กิวเมนต์ได้ การแก้ไขลิสต์หนึ่ง เช่น การแทนที่ด้วยcจะgooseส่งผลกระทบต่อลิสต์อื่นด้วย

( setf ( third foo ) 'goose )

การเปลี่ยนแปลงนี้fooทำให้เกิดการเปลี่ยนแปลงแต่ก็ทำให้เกิดการเปลี่ยนแปลงไปเป็น ด้วยเช่นกัน ซึ่งอาจเป็นผลลัพธ์ที่ไม่คาดคิด นี่อาจเป็นสาเหตุของข้อผิดพลาด และฟังก์ชันที่เปลี่ยนแปลงอาร์กิวเมนต์จะถูกระบุไว้ว่าเป็นฟังก์ชันที่ก่อให้เกิดความเสียหายด้วยเหตุผลนี้(abgoose)bar(xbgoose)

ผู้ที่ชื่นชอบ การเขียน โปรแกรมเชิงฟังก์ชันมักหลีกเลี่ยงฟังก์ชันที่ทำลายข้อมูล ในภาษา Scheme ซึ่งนิยมรูปแบบการเขียนโปรแกรมเชิงฟังก์ชัน ชื่อของฟังก์ชันที่ทำลายข้อมูลจะถูกทำเครื่องหมายด้วยเครื่องหมายอัศเจรีย์หรือ "bang" เพื่อเป็นการเตือน เช่น ` set car bang` set-car!(อ่านว่าset car bang ) ซึ่งจะแทนที่ตัวแปร `car` ของ `cons` ในภาษา Common Lisp ฟังก์ชันที่ทำลายข้อมูลเป็นเรื่องปกติ ฟังก์ชันที่เทียบเท่า กับ `replace car` set-car!มีชื่อว่าrplaca"replace car" อย่างไรก็ตาม ฟังก์ชันนี้ไม่ค่อยพบเห็น เนื่องจาก Common Lisp มีฟังก์ชันพิเศษ `get` setfเพื่อทำให้การกำหนดและการใช้ฟังก์ชันที่ทำลายข้อมูลทำได้ง่ายขึ้น รูปแบบการเขียนโค้ดที่พบบ่อยใน Common Lisp คือการเขียนโค้ดแบบเชิงฟังก์ชัน (โดยไม่มีการเรียกใช้ฟังก์ชันที่ทำลายข้อมูล) ในระหว่างการสร้างต้นแบบ จากนั้นจึงเพิ่มการเรียกใช้ฟังก์ชันที่ทำลายข้อมูลเพื่อเพิ่มประสิทธิภาพเมื่อทำได้อย่างปลอดภัย

แบบฟอร์มประเมินตนเองและการเสนอราคา

ภาษา Lisp จะประเมินนิพจน์ที่ผู้ใช้ป้อนเข้ามา สัญลักษณ์และลิสต์จะประเมินค่าเป็นนิพจน์อื่น (โดยปกติแล้วจะง่ายกว่า) ตัวอย่างเช่น สัญลักษณ์จะประเมินค่าเป็นค่าของตัวแปรที่มันระบุชื่ออย่างไรก็ตามรูปแบบอื่นๆ ส่วนใหญ่จะประเมินค่าเป็นตัวมันเอง หากป้อนเข้าไปใน Lisp มันจะคืนค่าเป็น(+23)555

นอกจากนี้ ยังสามารถทำเครื่องหมายเพื่อป้องกันไม่ให้มีการประเมินค่าของนิพจน์ใดๆ (เช่นเดียวกับที่จำเป็นสำหรับสัญลักษณ์และลิสต์) นี่คือบทบาทของquoteตัวดำเนินการพิเศษ หรือตัวย่อของมัน'(เครื่องหมายอัญประกาศเดี่ยว) ตัวอย่างเช่น โดยปกติแล้ว หากป้อนสัญลักษณ์ `<int>` fooจะส่งคืนค่าของตัวแปรที่เกี่ยวข้อง (หรือข้อผิดพลาด หากไม่มีตัวแปรดังกล่าว) หากต้องการอ้างถึงสัญลักษณ์ตัวอักษร ให้ป้อน `<int>` หรือโดยปกติคือ ` <int> `(quotefoo)'foo

ทั้ง Common Lisp และ Scheme ยังรองรับ ตัวดำเนินการ backquote (เรียกว่าquasiquoteใน Scheme) ซึ่งป้อนด้วย`อักขระ ( Backtick ) ซึ่งเกือบจะเหมือนกับเครื่องหมายคำพูดธรรมดา ยกเว้นว่ามันอนุญาตให้ประเมินนิพจน์และแทรกค่าลงในรายการที่อยู่ในเครื่องหมายคำพูดด้วยตัวดำเนินการunquote ด้วยเครื่องหมายจุลภาค และตัว ดำเนิน การ splice ด้วย เครื่องหมายจุลภาค หากตัวแปรมีค่าเป็นก็จะประเมินค่าเป็นในขณะที่จะประเมินค่าเป็นเครื่องหมาย backquote มักใช้ในการกำหนดการขยายมาโคร[ 68 ] [ 69 ],,@snue(barbaz)`(foo,snue)(foo(barbaz))`(foo,@snue)(foobarbaz)

ฟอร์มที่ประเมินค่าตัวเองได้และฟอร์มที่อยู่ในเครื่องหมายคำพูดนั้นเทียบเท่ากับค่าคงที่ในภาษา Lisp อาจเป็นไปได้ที่จะแก้ไขค่าของค่าคงที่ (ที่เปลี่ยนแปลงได้) ในโค้ดโปรแกรม ตัวอย่างเช่น หากฟังก์ชันส่งคืนฟอร์มที่อยู่ในเครื่องหมายคำพูด และโค้ดที่เรียกใช้ฟังก์ชันนั้นแก้ไขฟอร์มดังกล่าว อาจส่งผลต่อพฤติกรรมของฟังก์ชันในการเรียกใช้ครั้งต่อๆ ไป

( defun should-be-constant () ' ( one two three ))( let (( stuff ( should-be-constant ))) ( setf ( third stuff ) 'bizarre )) ; bad!( should-be-constant ) ; ส่งคืน (one two bizarre)

การแก้ไขรูปแบบที่อ้างอิงไว้แบบนี้โดยทั่วไปถือว่าเป็นรูปแบบที่ไม่ดี และมาตรฐาน ANSI Common Lisp ได้กำหนดไว้ว่าเป็นข้อผิดพลาด (ส่งผลให้เกิดพฤติกรรม "ไม่แน่นอน" ในไฟล์ที่คอมไพล์แล้ว เนื่องจากตัวคอมไพล์ไฟล์สามารถรวมค่าคงที่ที่คล้ายกันเข้าด้วยกัน ใส่ไว้ในหน่วยความจำที่ป้องกันการเขียน ฯลฯ)

การกำหนดรูปแบบการอ้างอิงอย่างเป็นทางการของภาษาลิสป์ได้รับการกล่าวถึงโดยดักลาส ฮอฟสตัดเตอร์ (ในGödel, Escher, Bach ) และคนอื่นๆ ว่าเป็นตัวอย่างของ แนวคิด ทางปรัชญาเรื่องการอ้างอิงตนเอง

ขอบเขตและการปิดงาน

ตระกูลภาษา Lisp มีความเห็นแตกต่างกันเกี่ยวกับการใช้ขอบเขตแบบไดนามิกหรือแบบคงที่ (หรือที่เรียกว่าขอบเขตเชิงคำศัพท์) Clojure, Common Lisp และ Scheme ใช้ขอบเขตแบบคงที่โดยค่าเริ่มต้น ในขณะที่newLISP , Picolispและภาษาที่ฝังอยู่ในEmacsและAutoCADใช้ขอบเขตแบบไดนามิก ตั้งแต่เวอร์ชัน 24.1 เป็นต้นมา Emacs ใช้ทั้งขอบเขตแบบไดนามิกและเชิงคำศัพท์

โครงสร้างรายการของรหัสโปรแกรม; การใช้ประโยชน์โดยมาโครและคอมไพเลอร์

ความแตกต่างพื้นฐานระหว่าง Lisp กับภาษาโปรแกรมอื่นๆ คือ ใน Lisp การแสดงผลโปรแกรมในรูปแบบข้อความนั้นเป็นเพียงคำอธิบายที่มนุษย์อ่านได้ของโครงสร้างข้อมูลภายในเดียวกัน (รายการเชื่อมโยง สัญลักษณ์ ตัวเลข อักขระ ฯลฯ) กับที่ระบบ Lisp พื้นฐานใช้

ภาษา Lisp ใช้สิ่งนี้ในการสร้างระบบมาโครที่มีประสิทธิภาพสูงมาก เช่นเดียวกับภาษามาโครอื่นๆ เช่น ภาษามาโครที่กำหนดโดยพรีโปรเซสเซอร์ของภาษา C (พรีโปรเซสเซอร์มาโครสำหรับ ภาษาโปรแกรม C , Objective-CและC++ ) มาโครจะส่งคืนโค้ดที่สามารถคอมไพล์ได้ อย่างไรก็ตาม ต่างจากมาโครของพรีโปรเซสเซอร์ของภาษา C มาโครเหล่านี้เป็นฟังก์ชันของ Lisp ดังนั้นจึงสามารถใช้ประโยชน์จากพลังของ Lisp ได้อย่างเต็มที่

นอกจากนี้ เนื่องจากโค้ด Lisp มีโครงสร้างเหมือนกับลิสต์ จึงสามารถสร้างมาโครได้โดยใช้ฟังก์ชันประมวลผลลิสต์ใดๆ ในภาษา กล่าวโดยสรุปคือ สิ่งใดก็ตามที่ Lisp สามารถทำกับโครงสร้างข้อมูลได้ มาโครของ Lisp ก็สามารถทำกับโค้ดได้เช่นกัน ในทางตรงกันข้าม ในภาษาอื่นๆ ส่วนใหญ่ ผลลัพธ์ของตัวแยกวิเคราะห์จะเป็นเพียงส่วนภายในของการใช้งานภาษา และโปรแกรมเมอร์ไม่สามารถจัดการได้

คุณสมบัตินี้ทำให้การพัฒนา ภาษา ที่มีประสิทธิภาพภายในภาษาอื่นทำได้ง่าย ตัวอย่างเช่น ระบบออบเจ็กต์ของ Common Lisp สามารถนำมาใช้เป็นส่วนขยายของภาษาได้อย่างเรียบร้อยโดยใช้มาโคร ซึ่งหมายความว่าหากแอปพลิเคชันต้องการกลไกการสืบทอดที่แตกต่างกัน ก็สามารถใช้ระบบออบเจ็กต์อื่นได้ นี่เป็นสิ่งที่แตกต่างอย่างสิ้นเชิงกับภาษาอื่นๆ ส่วนใหญ่ ตัวอย่างเช่น Java ไม่รองรับการสืบทอดแบบหลายทาง และไม่มีวิธีที่เหมาะสมในการเพิ่มการสืบทอดดังกล่าว

ในการใช้งาน Lisp แบบง่ายๆ โครงสร้างลิสต์นี้จะถูกตีความ โดยตรง เพื่อรันโปรแกรม ฟังก์ชันก็คือส่วนหนึ่งของโครงสร้างลิสต์ที่ตัวตีความจะวนลูปผ่านในระหว่างการประมวลผล อย่างไรก็ตาม ระบบ Lisp ที่ซับซ้อนส่วนใหญ่จะมีคอมไพเลอร์ด้วย คอมไพเลอร์จะแปลงโครงสร้างลิสต์เป็นรหัสเครื่องหรือไบต์โค้ดเพื่อการประมวลผล รหัสนี้สามารถทำงานได้เร็วเท่ากับรหัสที่คอมไพล์ในภาษาทั่วไป เช่น C

มาโครจะขยายก่อนขั้นตอนการคอมไพล์ และด้วยเหตุนี้จึงมีตัวเลือกที่น่าสนใจบางอย่าง หากโปรแกรมต้องการตารางที่คำนวณไว้ล่วงหน้า มาโครอาจสร้างตารางในระหว่างการคอมไพล์ ดังนั้นคอมไพเลอร์จึงต้องแสดงผลตารางออกมาเท่านั้น และไม่จำเป็นต้องเรียกโค้ดเพื่อสร้างตารางในระหว่างการทำงาน การใช้งาน Lisp บางอย่างยังมีกลไกeval-whenที่อนุญาตให้โค้ดมีอยู่ในระหว่างการคอมไพล์ (เมื่อมาโครต้องการ) แต่ไม่มีอยู่ในโมดูลที่ส่งออกมา[ 70 ]

การประเมินผลและวงจรการอ่าน-ประเมิน-พิมพ์

ภาษา Lisp มักใช้ร่วมกับบรรทัดคำสั่งแบบ โต้ตอบ ซึ่งอาจรวมกับสภาพแวดล้อมการพัฒนาแบบบูรณาการ (IDE) ผู้ใช้พิมพ์นิพจน์ที่บรรทัดคำสั่ง หรือสั่งให้ IDE ส่งนิพจน์เหล่านั้นไปยังระบบ Lisp ภาษา Lisp จะอ่านนิพจน์ที่ป้อนเข้ามาประเมินผล และพิมพ์ผลลัพธ์ ด้วยเหตุนี้ บรรทัดคำสั่งของ Lisp จึงเรียกว่าวงจรการอ่าน-ประเมิน-พิมพ์ ( REPL )

การทำงานพื้นฐานของ REPL มีดังนี้ นี่เป็นคำอธิบายอย่างง่ายที่ละเว้นองค์ประกอบหลายอย่างของภาษา Lisp จริงๆ เช่น การอ้างอิงข้อความและการใช้มาโคร

ฟังก์ชัน นี้readรับนิพจน์ S ที่เป็นข้อความเป็นอินพุต และแยกวิเคราะห์นิพจน์เหล่านั้นเป็นโครงสร้างข้อมูลภายใน ตัวอย่างเช่น หากคุณพิมพ์ข้อความที่พรอมต์ ฟังก์ชันจะแปลงข้อความนั้นเป็นรายการเชื่อมโยงที่มีสามองค์ประกอบ ได้แก่ สัญลักษณ์, ตัวเลข 1 และตัวเลข 2 บังเอิญว่ารายการนี้ก็เป็นโค้ด Lisp ที่ถูกต้องเช่นกัน กล่าวคือ สามารถประเมินค่าได้ เนื่องจากองค์ประกอบหลักของรายการระบุชื่อฟังก์ชัน ซึ่งก็คือการดำเนินการบวก(+12)read+

ตัว อักษร A fooจะถูกอ่านเป็นสัญลักษณ์เดี่ยว ตัวอักษร123จะถูกอ่านเป็นตัวเลขหนึ่งร้อยยี่สิบสาม"123"ตัวอักษร จะถูกอ่านเป็นสตริง "123"

ฟังก์ชัน นี้evalจะประเมินข้อมูลและส่งคืนข้อมูล Lisp อื่นๆ ตั้งแต่ศูนย์รายการขึ้นไปเป็นผลลัพธ์ การประเมินไม่จำเป็นต้องหมายถึงการตีความเสมอไป ระบบ Lisp บางระบบจะคอมไพล์ทุกนิพจน์เป็นรหัสเครื่องดั้งเดิม อย่างไรก็ตาม การอธิบายการประเมินในแง่ของการตีความนั้นทำได้ง่าย: ในการประเมินรายการที่มีชื่อฟังก์ชันอยู่evalในตัวแปรย่อย ขั้นแรกจะประเมินอาร์กิวเมนต์แต่ละตัวที่ระบุในตัวแปรย่อย จากนั้นจึงใช้ฟังก์ชันกับอาร์กิวเมนต์เหล่านั้น ในกรณีนี้ ฟังก์ชันคือการบวก และการนำไปใช้กับรายการอาร์กิวเมนต์จะให้คำตอบซึ่งเป็นผลลัพธ์ของการประเมิน(12)3

สัญลักษณ์นี้fooจะประเมินค่าเป็นค่าของสัญลักษณ์ foo ข้อมูลเช่นสตริง "123" จะประเมินค่าเป็นสตริงเดียวกัน รายการจะประเมินค่าเป็นรายการ (1 2 3)(quote(123))

หน้าที่ของprintฟังก์ชันคือการแสดงผลลัพธ์ให้ผู้ใช้เห็น สำหรับผลลัพธ์ที่เรียบง่ายเช่น3นี้ถือว่าง่ายมาก แต่ถ้าเป็นนิพจน์ที่ประเมินค่าเป็นโครงสร้างรายการ จะต้องวนprintลูปผ่านรายการนั้นและพิมพ์ออกมาเป็นนิพจน์ S

ในการสร้าง REPL ด้วยภาษา Lisp นั้น จำเป็นต้องเขียนฟังก์ชันเพียงสามฟังก์ชันนี้และฟังก์ชันวนลูปไม่สิ้นสุด (แน่นอนว่า การเขียนฟังก์ชันนี้evalจะซับซ้อนกว่า เพราะต้องเขียนตัวดำเนินการพิเศษทั้งหมด เช่นifหรือ ด้วยlambda) เมื่อทำเช่นนี้แล้ว REPL พื้นฐานก็จะมีโค้ดเพียงบรรทัดเดียว:(loop(print(eval(read))))

โดยทั่วไปแล้ว Lisp REPL ยังมีฟังก์ชันการแก้ไขข้อมูลป้อนเข้า ประวัติข้อมูลป้อนเข้า การจัดการข้อผิดพลาด และอินเทอร์เฟซสำหรับดีบักเกอร์ด้วย

โดยปกติแล้ว Lisp จะถูกประเมินผลอย่างรวดเร็วในCommon Lispอาร์กิวเมนต์จะถูกประเมินตามลำดับการประยุกต์ใช้ ('ซ้ายสุดภายในสุด') ในขณะที่ในSchemeลำดับของอาร์กิวเมนต์นั้นไม่แน่นอน ทำให้มีช่องว่างสำหรับการปรับแต่งโดยคอมไพเลอร์

โครงสร้างควบคุม

เดิมทีภาษา Lisp มีโครงสร้างควบคุมเพียงไม่กี่อย่าง แต่มีการเพิ่มโครงสร้างควบคุมอีกมากมายในระหว่างการพัฒนาของภาษา (ตัวดำเนินการเงื่อนไขดั้งเดิมของ Lisp condคือ เป็นต้นแบบของif-then-elseโครงสร้างควบคุมในภายหลัง)

โปรแกรมเมอร์ในภาษา Scheme มักจะแสดงลูปโดยใช้การเรียกซ้ำแบบหาง (tail recursion ) ความแพร่หลายของ Scheme ในวิทยาศาสตร์คอมพิวเตอร์เชิงวิชาการทำให้บางคนเชื่อว่าการเรียกซ้ำแบบหางเป็นวิธีเดียวหรือเป็นวิธีที่พบมากที่สุดในการเขียนการวนซ้ำใน Lisp แต่สิ่งนี้ไม่ถูกต้อง ภาษา Lisp ที่พบเห็นบ่อยทั้งหมดมีโครงสร้างการวนซ้ำแบบเชิงคำสั่ง ตั้งแต่doลูปของ Scheme ไปจนถึง นิพจน์ ที่ซับซ้อนของCommon Lisploopยิ่งไปกว่านั้น ประเด็นสำคัญที่ทำให้เรื่องนี้เป็นเรื่องที่เป็นกลางมากกว่าเรื่องส่วนตัวคือ Scheme กำหนดข้อกำหนดเฉพาะสำหรับการจัดการการเรียกแบบหางและด้วยเหตุนี้เหตุผลที่การใช้การเรียกซ้ำแบบหางได้รับการสนับสนุนโดยทั่วไปใน Scheme จึงเป็นเพราะการปฏิบัตินี้ได้รับการสนับสนุนอย่างชัดเจนโดยคำจำกัดความของภาษา ในทางตรงกันข้าม ANSI Common Lisp ไม่ต้องการ[ 71 ]การเพิ่มประสิทธิภาพที่เรียกกันทั่วไปว่าการกำจัดการเรียกแบบหาง ดังนั้น ข้อเท็จจริงที่ว่ารูปแบบการเรียกซ้ำแบบหางเป็นการทดแทนแบบไม่เป็นทางการสำหรับการใช้ โครงสร้าง การวนซ้ำแบบ ดั้งเดิมมากขึ้น (เช่นdoหรือ) ไม่เป็นที่นิยม[ 72 ]ใน Common Lisp ไม่ใช่แค่เรื่องของความชอบทางสไตล์เท่านั้น แต่ยังอาจเป็นเรื่องของประสิทธิภาพ (เนื่องจากการเรียกแบบหางที่เห็นได้ชัดใน Common Lisp อาจไม่สามารถคอมไพล์เป็นการกระโดดแบบง่ายๆ ได้dolist) และความถูกต้องของโปรแกรม (เนื่องจากการเรียกซ้ำแบบหางอาจเพิ่มการใช้สแต็กใน Common Lisp ซึ่งเสี่ยงต่อการเกิดสแต็กโอเวอร์โฟลว์ )loop

โครงสร้างควบคุมบางอย่างในภาษา Lisp เป็นตัวดำเนินการพิเศษซึ่งเทียบเท่ากับคำหลักทางไวยากรณ์ในภาษาอื่นๆ นิพจน์ที่ใช้ตัวดำเนินการเหล่านี้มีลักษณะภายนอกเหมือนกับการเรียกใช้ฟังก์ชัน แต่แตกต่างตรงที่อาร์กิวเมนต์ไม่จำเป็นต้องได้รับการประเมินค่า หรือในกรณีของนิพจน์การวนซ้ำ อาจถูกประเมินค่ามากกว่าหนึ่งครั้ง

แตกต่างจากภาษาโปรแกรมหลักอื่นๆ ส่วนใหญ่ ภาษา Lisp อนุญาตให้ใช้ภาษาในการสร้างโครงสร้างควบคุมได้ โครงสร้างควบคุมหลายอย่างถูกสร้างขึ้นในรูปแบบของมาโครในภาษา Lisp และโปรแกรมเมอร์ที่ต้องการทราบวิธีการทำงานของมันยังสามารถขยายมาโครเหล่านั้นได้อีกด้วย

ทั้ง Common Lisp และ Scheme ต่างก็มีตัวดำเนินการสำหรับควบคุมการไหลของโปรแกรมที่ไม่ใช่แบบโลคอล ความแตกต่างในตัวดำเนินการเหล่านี้เป็นความแตกต่างที่สำคัญที่สุดอย่างหนึ่งระหว่างสองภาษา Scheme รองรับ การทำงาน ต่อเนื่องแบบเรียกซ้ำได้โดยใช้call/ccขั้นตอน ซึ่งช่วยให้โปรแกรมสามารถบันทึก (และเรียกคืนในภายหลัง) ตำแหน่งเฉพาะในการทำงานได้ Common Lisp ไม่รองรับการทำงานต่อเนื่องแบบเรียกซ้ำได้ แต่รองรับวิธีการจัดการการทำงานต่อเนื่องแบบหลีกเลี่ยงได้หลายวิธี

บ่อยครั้งที่อัลกอริทึมเดียวกันสามารถแสดงในภาษา Lisp ได้ทั้งในรูปแบบคำสั่งหรือรูปแบบฟังก์ชัน ดังที่กล่าวไว้ข้างต้น ภาษา Scheme มักจะนิยมรูปแบบฟังก์ชัน โดยใช้การเรียกซ้ำแบบหาง (tail recursion) และ continuations เพื่อแสดงการควบคุมการไหลของโปรแกรม อย่างไรก็ตาม รูปแบบคำสั่งก็ยังเป็นไปได้เช่นกัน รูปแบบที่โปรแกรมเมอร์ Common Lisp หลายคนนิยมใช้อาจดูคุ้นเคยมากกว่าสำหรับโปรแกรมเมอร์ที่คุ้นเคยกับภาษาที่มีโครงสร้าง เช่น C ในขณะที่รูปแบบที่โปรแกรมเมอร์ Scheme นิยมใช้จะคล้ายกับภาษาฟังก์ชันบริสุทธิ์ เช่นHaskell มากกว่า

เนื่องจาก Lisp มีรากฐานมาจากการประมวลผลรายการ จึงมีฟังก์ชันลำดับสูงมากมายที่เกี่ยวข้องกับการวนซ้ำตามลำดับ ในหลายกรณีที่ภาษาอื่น ๆ จำเป็นต้องใช้ลูปแบบชัดเจน (เช่นforลูปในภาษา C) ใน Lisp สามารถทำงานเดียวกันได้ด้วยฟังก์ชันลำดับสูง (เช่นเดียวกับภาษาการเขียนโปรแกรมเชิงฟังก์ชันหลายภาษา)

ตัวอย่างที่ดีคือฟังก์ชันที่ใน Scheme เรียกว่า `initialize` mapและใน Common Lisp เรียกว่า `initialize` mapcarโดยกำหนดฟังก์ชันและลิสต์ตั้งแต่หนึ่งลิสต์ขึ้นไป ฟังก์ชันนี้mapcarจะนำฟังก์ชันไปใช้กับองค์ประกอบของลิสต์เหล่านั้นตามลำดับ และรวบรวมผลลัพธ์ไว้ในลิสต์ใหม่:

( mapcar #' + ' ( 1 2 3 4 5 ) ' ( 10 20 30 40 50 ))

ฟังก์ชัน นี้จะถูกนำไปใช้+กับองค์ประกอบแต่ละคู่ในรายการที่สอดคล้องกัน ซึ่งจะให้ผลลัพธ์ดังนี้(1122334455)

ตัวอย่าง

ต่อไปนี้เป็นตัวอย่างโค้ด Common Lisp

โปรแกรม พื้นฐาน " Hello, World! ":

( พิมพ์"สวัสดีโลก!" )

ไวยากรณ์ของภาษา Lisp เอื้อต่อการเรียกซ้ำโดยธรรมชาติ ปัญหาทางคณิตศาสตร์ เช่น การแจงนับเซตที่กำหนดโดยการเรียกซ้ำ สามารถแสดงออกมาได้ง่ายในสัญลักษณ์นี้ ตัวอย่างเช่น การหาค่าแฟกทอเรียล ของจำนวนหนึ่ง :

( defun แฟกทอเรียล( n ) ( ถ้า( ศูนย์n ) 1 ( * n ( แฟกทอเรียล( 1- n )))))

การใช้งานอีกรูปแบบหนึ่งใช้พื้นที่สแต็กน้อยกว่าเวอร์ชันก่อนหน้า หากระบบ Lisp พื้นฐานทำการปรับแต่งการเรียกซ้ำแบบหาง (tail recursion) ให้เหมาะสม :

( defun factorial ( n &optional ( acc 1 )) ( if ( zerop n ) acc ( factorial ( 1- n ) ( * acc n ))))

เปรียบเทียบตัวอย่างข้างต้นกับเวอร์ชันแบบวนซ้ำซึ่งใช้มาโครของCommon Lisp :loop

( defun factorial ( n ) ( loop for i from 1 to n for fac = 1 then ( * fac i ) finally ( return fac )))

ฟังก์ชันต่อไปนี้ใช้สำหรับกลับลำดับของลิสต์ (ฟังก์ชัน reverseในตัวของ Lisp ก็ทำเช่นเดียวกัน)

( defun -reverse ( list ) ( let (( return-value )) ( dolist ( e list ) ( push e return-value )) return-value ))

ระบบวัตถุ

ระบบและโมเดลเชิงวัตถุต่างๆ ได้ถูกสร้างขึ้นบนพื้นฐานของภาษา Lisp ควบคู่ไปกับภาษา Lisp หรือรวมอยู่ในภาษา Lisp ซึ่งรวมถึง

ระบบปฏิบัติการ

ระบบปฏิบัติการหลาย ระบบ รวมถึงระบบที่ใช้ภาษามีพื้นฐานมาจาก Lisp (ใช้คุณสมบัติ ข้อกำหนด วิธีการ โครงสร้างข้อมูล ฯลฯ ของ Lisp) หรือเขียนด้วยภาษา Lisp [ 75 ]ซึ่งรวมถึง:

Generaเปลี่ยนชื่อเป็น Open Genera [ 76 ]โดยSymbolics ; Medley เขียนด้วย Interlisp ซึ่งเดิมเป็นตระกูลระบบปฏิบัติการกราฟิกที่ทำงานบนเวิร์กสเตชันStarรุ่นหลังของXerox ; [ 77 ] [ 78 ] Mezzano; [ 79 ] Interim; [ 80 ] [ 81 ] ChrysaLisp [ 82 ]โดยนักพัฒนา TAOS ของ Tao Systems; [ 83 ]และGuix Systemสำหรับ GNU/Linux ด้วย

ดูเพิ่มเติม

เชิงอรรถ

  1. ในขณะนั้น ภาษาฟอร์ทรานมีโครงสร้าง if-then-else ที่ยอมรับหมายเลขบรรทัดเป็นเป้าหมายการกระโดด ในลักษณะเดียวกับ คำสั่ง Gotoแทนที่จะยอมรับนิพจน์ใดๆ ในบล็อก "then" และ "else"
  2. Common Lisp:(defun f (x) x)Scheme:(define f (lambda (x) x))หรือ(define (f x) x)
  3. หมายเหตุ: สิ่งที่เรียกว่า "รายการแบบจุด" เป็นเพียง "รายการที่ไม่เหมาะสม" ประเภทหนึ่งเท่านั้น อีกประเภทหนึ่งคือ "รายการแบบวงกลม" ซึ่งเซลล์ cons จะก่อตัวเป็นวงวน โดยทั่วไปแล้วจะแสดงโดยใช้#n=(...)เพื่อแสดงเซลล์ cons เป้าหมายที่จะมีการอ้างอิงหลายครั้ง และ#n#ใช้เพื่ออ้างอิงถึง cons นี้ ตัวอย่างเช่น(#1=(a b) . #1#)โดยปกติจะพิมพ์เป็น((a b) a b)(โดยไม่เปิดใช้งานการพิมพ์โครงสร้างแบบวงกลม) แต่ทำให้เห็นการนำเซลล์ cons กลับมาใช้ใหม่ได้อย่างชัดเจน#1=(a . #1#)โดยปกติจะไม่สามารถพิมพ์ได้เนื่องจากเป็นแบบวงกลม แม้ว่า(a...)บางครั้งจะแสดงผลก็ตาม CDR ของเซลล์ cons ที่กำหนดโดย ก็#1=คือตัวมันเอง

อ่านเพิ่มเติม

  • แมคคาร์ธี, จอห์น (12 กุมภาพันธ์ 1979). "การนำ Lisp ไปใช้" . ประวัติของ Lisp . มหาวิทยาลัยสแตนฟอร์ด. สืบค้นเมื่อ17 ตุลาคม 2008 .
  • Steele, Jr., Guy L.; Richard P. Gabriel (1993). วิวัฒนาการของ Lisp (PDF) . การประชุม ACM SIGPLAN ครั้งที่สองว่าด้วยประวัติศาสตร์ของภาษาโปรแกรม. นิวยอร์ก, นิวยอร์ก: ACM. หน้า231–270 . ISBN  0-89791-570-4เก็บถาวรจากต้นฉบับ(PDF)เมื่อวันที่ 12 ตุลาคม 2549 เรียกดูเมื่อวันที่ 17 ตุลาคม 2551
  • เวทช์, จิม (1998). "ประวัติและคำอธิบายของ CLOS". ใน ซาลัส, ปีเตอร์ เอช. (บรรณาธิการ). คู่มือภาษาการเขียนโปรแกรมเล่มที่ 4 ภาษาการเขียนโปรแกรมเชิงฟังก์ชันและตรรกะ (ฉบับพิมพ์ครั้งที่ 1  ). อินเดียนาโพลิส, อินเดียนา: สำนักพิมพ์แมคมิลแลน เทคนิคัล พับลิชชิ่ง หน้า107–158 . ISBN  1-57870-011-6.
  • Abelson, Harold ; Sussman, Gerald Jay ; Sussman, Julie (1996). โครงสร้างและการตีความโปรแกรมคอมพิวเตอร์ (  ฉบับที่ 2). สำนักพิมพ์ MIT. ISBN 0-262-01153-0.
  • ประสบการณ์ของผมกับภาษา Lisp และการพัฒนา GNU Emacs ( ถอดความจากสุนทรพจน์ของRichard Stallman เมื่อวันที่ 28 ตุลาคม 2002 ในการประชุม Lisp นานาชาติ)
  • เกรแฮม, พอล (2004). แฮกเกอร์และจิตรกร แนวคิดสำคัญจากยุคคอมพิวเตอร์สำนักพิมพ์โอไรลีย์ISBN 0-596-00662-4.
  • เบิร์กลีย์, เอ็ดมันด์ ซี. ; บอบโรว์, แดเนียล จี . , บรรณาธิการ (มีนาคม 1964). ภาษาโปรแกรม LISP: การทำงานและการประยุกต์ใช้ (PDF) . เคมบริดจ์, แมสซาชูเซตส์: สำนักพิมพ์ MIT.
    • บทความนี้อ้างอิงจากบท"LISP - A Simple Introduction" ของ Berkeley, Edmund C. (กันยายน 1964). "ภาษาโปรแกรม Lisp: บทนำและการประเมิน" . Computers and Automation : 16 -23.
  • ไวส์แมน, คลาร์ก (1967). คู่มือเบื้องต้น LISP 1.5 (PDF) . เบลมอนต์, แคลิฟอร์เนีย: บริษัท ดิคเคนสัน พับลิชชิง จำกัด
ประวัติศาสตร์
  • ประวัติของภาษา Lisp – ประวัติโดยJohn McCarthy เมื่อวันที่ 12 กุมภาพันธ์ 1979
  • ประวัติของภาษาลิสป์ – ประวัติที่รวบรวมโดยเฮอร์เบิร์ต สโตยัน จากเอกสารต่างๆ (ซึ่งแมคคาร์ธีรับรองว่าสมบูรณ์กว่าฉบับของเขาเอง ดูได้ที่: ลิงก์ประวัติของแมคคาร์ธี )
  • ประวัติของภาษา LISP ที่พิพิธภัณฑ์ประวัติศาสตร์คอมพิวเตอร์
  • เบลล์, อดัม กอร์ดอน (2 พฤษภาคม 2022). LISP ในอวกาศ กับ รอน การ์เร็ต . CoRecursive (พอดแคสต์, บทถอดเสียง, ภาพถ่าย).เกี่ยวกับการใช้งานซอฟต์แวร์ LISP ใน หุ่น ยนต์ของ NASA
  • Cassel, David (22 พฤษภาคม 2022). "โปรแกรมเมอร์ NASA รำลึกถึงการดีบัก Lisp ในห้วงอวกาศลึก" . The New Stack .
สมาคมและการประชุม
  • สมาคมผู้ใช้ Lisp
  • การประชุม Common Lisp ของยุโรป
  • การประชุมวิชาการ Lisp แห่งยุโรป
  • การประชุม Lisp นานาชาติ
หนังสือและบทแนะนำ
  • การร่ายเวทมนตร์ในภาษา Lisp : บทแนะนำเบื้องต้นในรูปแบบการ์ตูน
  • On Lispหนังสือฟรีโดย Paul Graham
  • Practical Common Lispเวอร์ชันฟรีแวร์ โดย Peter Seibel
  • ภาษาลิสป์สำหรับเว็บ
  • ดินแดนแห่งลิสป์
  • ปล่อยให้แลมบ์ดาผ่านไป
การสัมภาษณ์
  • บทสัมภาษณ์ประวัติศาสตร์ปากเปล่ากับจอห์น แมคคาร์ธีที่สถาบันชาร์ลส์ แบ็บเบจมหาวิทยาลัยมินนิโซตา เมืองมินนิแอโพลิส แมคคาร์ธีกล่าวถึงบทบาทของเขาในการพัฒนาระบบแบ่งเวลาใช้งาน (time-sharing) ที่สถาบันเทคโนโลยีแมสซาชูเซตส์ (MIT) นอกจากนี้เขายังอธิบายถึงงานของเขาในด้านปัญญาประดิษฐ์ (AI) ที่ได้รับทุนสนับสนุนจากสำนักงานโครงการวิจัยขั้นสูง (Advanced Research Projects Agency) ซึ่งรวมถึง AI เชิงตรรกะ (LISP) และหุ่นยนต์
  • บทสัมภาษณ์กับริชาร์ด พี. กาเบรียล (พอดแคสต์)
ทรัพยากร
  • CLiki: วิกิสำหรับภาษา Common Lisp
  • ไดเร็กทอรี Common Lisp (ผ่านทางWayback Machine ; เก็บถาวรจากต้นฉบับ )
  • ดัชนีคำถามที่พบบ่อยเกี่ยวกับ Lisp
  • lisppaste ถูกเก็บถาวรเมื่อวันที่ 9 มิถุนายน 2021 ที่Wayback Machine
  • ดาวเคราะห์ลิสป์
  • ข่าวลิสป์รายสัปดาห์
  • newLISP - ภาษาสคริปต์สมัยใหม่ที่ใช้งานได้หลากหลาย
  • ลิสป์ วีคลี่

สรุปเนื้อหา

ข้อมูลสำคัญจากบทความ

ข้อมูลสำคัญเกี่ยวกับ ลิสป์ (ภาษาโปรแกรม)

Lisp (ในอดีต เรียกว่า LISP ซึ่งเป็นคำย่อของ "list processing") เป็นตระกูลของ ภาษาโปรแกรม ที่มีประวัติยาวนานและมีลักษณะเฉพาะคือการเขียน แบบพรีฟิกที่ มีวงเล็บ ครบถ้วน [ 3 ]...

History

John McCarthy began developing Lisp in 1958 while he was at the Massachusetts Institute of Technology (MIT).

ไทม์ไลน์

ลำดับเหตุการณ์ของภาษาถิ่น Lisp วี ที อี 1958 1960 พ.ศ. 2508 1970 พ.ศ. 2518 1980 พ.ศ. 2528 1990 พ.ศ. 2538 2000 2548 2010 2015 2020 LISP 1, 1.

การเชื่อมต่อกับปัญญาประดิษฐ์

นับตั้งแต่เริ่มแรก Lisp มีความเชื่อมโยงอย่างใกล้ชิดกับ ชุมชนวิจัย ปัญญาประดิษฐ์ โดยเฉพาะอย่างยิ่งบน ระบบ PDP-10 [ 23 ] Lisp ถูกใช้เป็นการนำภาษา Micro Planner มาใช้ ซึ่งใช้ในระบบ AI ชื่อดังอย่าง SHRDLU ในช่วงทศวรรษ 1970 เมื่อการวิจัย AI...