fbpx
维基百科

LISP

Lisp(歷史上拼寫為LISP),是具有悠久歷史的計算機編程語言家族,有獨特的完全用圓括號的前綴符號表示法[3]。它起源於1958年[4],是現今第二悠久而仍廣泛使用的高階編程語言,只有FORTRAN編程語言比它更早一年[5]。Lisp編程語族已經演變出許多種方言,現代最著名的通用編程語種是SchemeCommon Lisp和新近的Clojure

Lisp
编程范型多范型函数式过程式同像性反射式元编程
設計者约翰·麦卡锡
實作者史帝芬·羅素, Timothy P. Hart和Michael I. Levin
发行时间1958年,​65年前​(1958
型態系統动态类型强类型
衍生副語言
Arc, AutoLISP, Clojure, Common Lisp, Emacs Lisp, ISLISP, newLISP, PicoLisp, Racket, Scheme, SKILL, T英语T (programming language)
啟發語言
IPL
影響語言
CLU, Dylan, Falcon, Forth, Haskell, Io, Ioke, JavaScript, Julia[1], Logo, Lua, LPC, MDL英语MDL (programming language), ML, Nu英语Nu (programming_language), OPS5英语OPS5, Perl, POP-2/11英语POP-11, Python, REBOL, Ruby, Smalltalk, Wolfram语言[2]

简介

Lisp最初是為計算機程序創建的實用數學表示法[6],當時借鑒過阿隆佐·邱奇lambda表示法[7]。它很快成為人工智能研究中最受歡迎的編程語言[8]。作為早期的高階編程語言之一,Lisp開創了計算機科學領域的許多概念,包括树结构自動記憶體管理动态类型条件表达式[9]高階函數[10]遞迴[11]自主編譯器英语Self-hosting (compilers)[12]讀取﹣求值﹣輸出循環(REPL)[13]

"LISP"名稱源自「列表處理器」(英語:LISt Processor)的縮寫[14]列表是Lisp的主要數據結構之一,Lisp編程代碼也同樣由列表組成。因此,Lisp程序可以把源代碼當作數據結構進行操作,而使用其中的宏系統,開發人員可將自己定義的新語法或領域專用的語言,嵌入在Lisp編程中。

代碼和數據的可互換性為Lisp提供了立即可辨識的語法。所有的Lisp程序代碼都寫為S-表達式或以括號表示的列表。函數調用或語義形式也同樣寫成列表,首先是函數或操作符的名稱,然後接著是一或多個參數:例如,取三個參數的函數f即為(f arg1 arg2 arg3)

歷史

在1958年,約翰·麥卡錫麻省理工學院發明了Lisp程式語言[4]。在1960年,他在《ACM通讯》發表了論文《符號表達式的遞迴函數及其機器計算,第一部份》[15]。在這篇論文中闡述了只要透過一些簡單的運算子,以及借鑒自阿隆佐·邱奇的用於匿名函數的表示法[7],就可以建立一個可用於演算法中的具圖靈完備性的語言。Lisp还采纳了在1955年至1956年間創建的資訊處理語言所提出的列表處理與遞歸概念。

約翰·麥卡錫在最初定义的Lisp之中,先将程序表达为M-表达式英语M-expression表达式)[16],再将它转换成S-表達式(符号英语Symbol (programming)表达式),舉例來說M-表达式英语M-expressioncar[cons[A;B]],等同於S-表達式(car (cons A B))。S-表達式可以将复杂结构表示为列表,在Lisp被实现了之后,编程者一般只使用S-表達式,而棄用M-表達式,这使得程式具備了同像性,即程式與資料由同樣的結構儲存。M-表達式曾短暫存續於Horace Enea的MLisp英语MLispVaughan Pratt英语Vaughan PrattCGOL英语CGOL之中[17]

史帝芬·羅素IBM 704機器上使用打孔卡寫出了第一個Lisp實作[18]史帝芬·羅素在閱讀完約翰·麥卡錫的論文後,認為其中的eval函数可以用機器碼來實作[19],从而创造了一個能工作的Lisp解释器[20]。解释器可以用来运行Lisp程序,或者更恰当的说“求值Lisp表达式”[21]

在1960年发表的LISP I中[22],研究生Daniel Edwards開發了垃圾回收程序,使得在通用計算機上運行Lisp變得可行。在1962年,Timothy Hart與Michael Levin在麻省理工學院以Lisp自身,實做出第一個完整的Lisp編譯器[23]。在1963年,Timothy Hart提议向LISP 1.5增加[24]

在1975年,傑拉德·薩斯曼蓋伊·史提爾二世开发了Scheme,它是使用词法作用域尾调用优化的第一个Lisp方言[25]。在1980年代至1990年代期间,蓋伊·史提爾二世Scott Fahlman英语Scott FahlmanRichard P. Gabriel英语Richard P. GabrielDavid A. Moon英语David A. MoonDaniel Weinreb英语Daniel Weinreb等人,在将当时新近的Lisp方言,其多数是Maclisp的后继者比如ZetaLisp和NIL,统一成单一语言上进行了巨大的努力。新语言Common Lisp,在某种程度上兼容于它所替代的方言。在1994年,ANSI出版了Common Lisp标准《ANSI X3.226-1994信息技术编程语言Common Lisp》。此外还有嵌入到編輯器Emacs中的Emacs Lisp,它非常流行并建立了自己的标准。

联系于人工智能

自从创始以来,Lisp就密切联系于人工智能研究社群,特别是在PDP-10系统之上[26]。在1970年傑拉德·薩斯曼特里·威诺格拉德使用Lisp实现了编程语言Micro-Planner英语Planner (programming language)[27],它被用在著名的AI系统SHRDLU之中。

谱系和方言

在它六十余年的历史中,Lisp产生了在S-表达式语言的核心主旨上的很多变体[28]。此外,每个给定方言又可能有多种实现,例如Common Lisp就有十余种以上的实现。在一种标准化了的方言之内,符合标准的实现支持相同的核心语言,但是有着不同的扩展和函数库。

在方言间的差异可能是非常显眼的,例如定义一个函数[29],Common Lisp使用Maclisp在1969年介入的关键字defun[30],而Scheme使用它在1975年介入的define[31]Richard P. Gabriel英语Richard P. GabrielKent Pitman英语Kent Pitman在1998年的一篇论文中,按采用统一的还是分立的函数与值命名空间,将Lisp家族语言划分为Lisp1和Lisp2(或写为Lisp-1和Lisp-2)[32]

历史上的重要方言

 
Lisp机器,现存于MIT博物馆英语MIT Museum
  • LISP I[22],是第一个实现。
  • LISP 1.5[33],是第一个广泛发行的版本,由McCarthy和其他人在MIT开发。如此命名是因为它包含了对最初的LISP I解释器的改进,但不是LISP 2英语LISP 2规划的那种重大重构。
  • Stanford LISP 1.6[34],是斯坦福AI实验室英语Stanford University centers and institutes开发的LISP 1.5后继者,广泛的发行于运行TOPS-10操作系统的PDP-10系统。罗宾·米尔纳LCF英语Logic for Computable Functions ML运行在Stanford LISP 1.6下[35]。它被Maclisp和InterLisp所淘汰。
  • MACLISP[36],由MIT的MAC计划开发,它是LISP 1.5的直接后代[37]。它运行在PDP-10和Multics系统上。MACLISP后来被称为Maclisp,也通常叫做MacLisp。在MACLISP中的“MAC”,既无关于Apple的Macintosh,又无关于McCarthy
  • Interlisp英语Interlisp[38],由BBN科技开发,用于运行TENEX英语TENEX (operating system)操作系统的PDP-10系统之上,后来InterLisp-D被Xerox Lisp机器接纳并昵称为“西海岸Lisp”。还有为基于6502Atari 8位机家族英语Atari 8-bit family计算机发行的叫做“InterLISP 65”的小型版本。在很长一段时间内,Maclisp和InterLisp相互之间是强有力的竞争者[37]
  • Franz Lisp,起源于加利福尼亚大学伯克利分校的计划,后来由Franz Inc开发。这个名字是Franz Liszt的幽默变形,它不牵涉到Franz Inc后来销售的Allegro Common Lisp英语Allegro Common Lisp
  • XLISP,由David Betz开发[39]AutoLISP基于了它。
  • Standard Lisp和Portable Standard Lisp英语Portable Standard Lisp,是曾被广泛使用和移植的犹他大学开发的版本,特别是用它写成了计算机代数系统REDUCE英语Reduce (computer algebra system)
  • Lisp Machine Lisp英语Lisp Machine Lisp,Symbolics称其变体版本为ZetaLisp,它用在Lisp机器之上,是Maclisp的直接后代。Lisp Machine Lisp对Common Lisp有巨大影响。
  • Le Lisp,是一个法国Lisp方言。最早的界面建造器英语Graphical user interface builder之一(叫做SOS界面[40])是用Le Lisp写成的。
  • Scheme(1975年版),最初是在Maclisp上运行的解释器[41]
  • Common Lisp(1984年版)[42],是通过合并对Maclisp的不同尝试(ZetaLisp、Spice Lisp英语Spice LispNIL英语NIL (programming language)S-1 Lisp英语S-1 Lisp)而创建的方言[43],也具有来自Scheme方言的实质影响。这个版本的Common Lisp在广泛的平台上都能获得到,从而被众人接受为业界标准[44],直至ANSI Common Lisp(ANSI X3.226-1994)出版。最广泛传播的Common Lisp子方言,是Steel Bank Common Lisp(SBCL)、CMU Common Lisp(CMU-CL)、Clozure OpenMCL、GNU CLISPAllegro Common Lisp英语Allegro Common Lisp;所有这些实现都坚持了后来的ANSI CL标准。
  • Dylan,在它的第一个版本中是Scheme和Common Lisp对象系统的混合。
  • EuLisp英语EuLisp,尝试开发一个新的高效和整洁的Lisp。
  • ISLISP,尝试开发一个新的高效和整洁的Lisp。标准化为ISO/IEC 13816:1997[45],后来修订为ISO/IEC 13816:2007[46]:《信息技术 – 编程语言,它们的环境和系统软件接口 – 编程语言 ISLISP》。
  • IEEE Scheme,IEEE标准1178–1990(停用日期:2019-11-07)[47]
  • ANSI Common Lisp(1994年版),是美国国家标准协会(ANSI)的Common Lisp标准 ,由X3J13英语X3J13委员会创建,其章程是[48]:开始于以《Common Lisp语言英语Common Lisp the Language》作为基础文档[42],致力于通过公开的达成共识过程,找到Common Lisp实现的程序可移植性兼容性这个共通问题的解决方案。尽管形式上是ANSI标准,ANSI Common Lisp的实现、销售、使用和影响一直都是世界范围的。
  • ACL2,是Common LISP的一个应用式(免于副作用)变体。ACL2既是可以建模计算机系统的编程语言,也是帮助证明这些模型性质的工具。
  • GOAL英语Game Oriented Assembly Lisp,是一个视频游戏编程语言,由Andy Gavin英语Andy GavinJak and Daxter英语Jak and Daxter团队在顽皮狗开发。它是使用Allegro Common Lisp写成并被用于整个Jak and Daxter英语Jak and Daxter系列游戏的开发。

2000年迄今

在1990年代衰退之後,Lisp在2000年之後因一些關注而逐漸復甦。當其他人認為Lisp已經過時陳舊,受到保羅·格雷厄姆埃里克·雷蒙等人關於Lisp的著作的啟發,很多新的Lisp编程者經常將其描述為令人大開眼界的經驗,並聲稱在本質上比較其它編程語言更有生產效率[49]。這種意識的提高可對比於“人工智能冬季”和Lisp在1990年代中期的短暫增長[50]

Common Lisp開源社群建立了至今仍活躍的支援基礎有:CLiki英语CLiki,它是收集Common Lisp相關資訊的維基;Planet Lisp,它是收集了各種Lisp相關博客的內容;Common-lisp.net,它是開源專案的託管站點;Quicklisp,它是含括了許多函式庫的裝載管理器。在Common-lisp.net上,推荐了6种开源和2种商业Common Lisp实现[51]

Scheme社群基于廣泛接納的R5RS語言標準[52],開發了一些活跃至今的實作如ChickenGambitGauche英语Gauche (Scheme implementation)LarcenySTklos英语STklos等。Scheme实现要求英语Scheme Requests for Implementation建立了很多準標準函式庫和Scheme擴展功能。随着Scheme實作用戶社群增長,始自2003年的語言標準化過程在2007年產生了R6RS標準[53],在2013年又通过了R7RS-small最终草案[54],它已经有了一些实现支持[55]。使用Scheme介紹計算機科學課程的學校似乎有所減少,麻省理工學院的計算機科學入門課程,已經不再使用Scheme[56][57]

Clojure是在2007年出現的新近Lisp方言,它编译至Java虚拟机并特别关注并发性。現今與Lisp有關的大多數新活動,包括開發新的跨平台函式庫和應用,都集中在SchemeCommon LispEmacs LispRacketClojure的實作上。

近年来又有了幾種新的Lisp方言:ArcHy、Axel[58]LFE英语LFE (programming language)。此外,在2007年出现的Nu英语Nu (programming language),是OS X上采用Lisp式语法的脚本语言;在2012年出现的Julia所采用的语法解析器,是用Scheme方言Femtolisp实现的。在2019年10月,保羅·格雷厄姆发布了一个新的Lisp方言Bel[59]

Lisp編程語族時間軸

主要方言

Common LispScheme是Lisp发展的两大主流的代表。这些语言体现了显著不同的设计选择。

Common LispMaclisp的后继者。对它有重要影响的是Lisp Machine Lisp英语Lisp Machine Lisp、Maclisp、NIL英语NIL (programming language)S-1 Lisp英语S-1 LispSpice Lisp英语Spice Lisp和Scheme[60]。它拥有用于编程Lisp机器的大型Lisp方言Lisp Machine Lisp的很多特征,但设计上能高效的实现在任何个人计算机或工作站上。Common Lisp是通用编程语言,因而拥有一个大型语言标准,包括很多内建数据类型、函数、宏和其他语言元素,以及一个对象系统,即Common Lisp对象系统。Common Lisp还从Scheme借鉴了特定特征,比如词法作用域词法闭包。Common Lisp实现目标定为不同的平台,比如:LLVM[61]Java虚拟机[62]、x86-64、PowerPC、Alpha、ARM、Motorola 68000和MIPS[63],和不同的操作系统,比如:Windows、macOS、Linux、Solaris、FreeBSD、NetBSD、OpenBSD、Dragonfly BSD和Heroku[64]

Scheme是一个静态作用域和适当尾递归的Lisp编程语言方言[65]。它的设计有着异常清晰和简单的语义,和很少的形成表达式的不同方式。它的设计大约比Common Lisp早上一个年代,Scheme是一个相当极简主义的设计。它拥有非常小的标准特征集合,但具有在Common Lisp中未规定的特定实现特征,比如尾递归优化和完全续体。在Scheme中能方便的表达广阔的编程范型,包括指令式、函数式和消息传递风格。Scheme通过一系列的标准,即第n次修订的算法语言Scheme报告,和一系列Scheme实现要求英语Scheme Requests for Implementation而持续的演化。

Clojure是Lisp的一个新近方言,其目标主要是Java虚拟机通用语言运行库(CLR)和编译成JavaScript,它被设计为一个务实的通用编程语言。Clojure受到了Haskell的相当大的影响,因而非常强烈的强调了不可变性[66]。Clojure提供了对Java框架和库的访问,具有可选的类型提示和类型推论,这样到Java的调用就可以避免反射并确使了快速的原始操作。Clojure设计上不后向兼容于其他Lisp方言[67]

进一步的,Lisp方言在很多应用中被用作脚本语言,其中最周知的是在Emacs编辑器中的Emacs Lisp,在AutoCAD中的AutoLISP和后来的Visual Lisp,Audacity中的Nyquist英语Nyquist (programming language),和LilyPondGNU Guile。有用的Scheme解释器潜在有很小的大小,使得它特别流行于嵌入式脚本。例子包括SIODTinyScheme,二者都曾经以共用名字“Script-fu”成功的嵌入到了GIMP图像处理软件中[68]。LIBREP是John Harper最初基于Emacs Lisp语言开发的Lisp解释器,它已经嵌入到了Sawfish窗口管理器[69]

标准化的方言

Lisp有官方标准化和业界标准的方言:IEEE Scheme[47]ANSI Common Lisp、ISO ISLISPR5RS SchemeR7RS-small Scheme

语法和语义

注意:本文的例子是用Common Lisp书写,但是其中的多数在Scheme中也是有效的,示例采用的Common Lisp实现是SBCL

符号表达式

Lisp是一个面向表达式编程语言英语Expression-oriented programming language。不同于多数其他语言,在表达式和语句之间不做区分。所有代码和数据都写为表达式。当求值一个表达式的时候,它产生一个值(在Common Lisp中可能有多个值),它可以接着被嵌入到其他表达式中。每个值都可以是任何数据类型的。

McCarthy的1958年论文介入两种类型的语法:符号英语Symbol (programming)表达式即S-表达式或sexps,它镜像了代码和数据的内部表示;和元表达式即M-表达式英语M-expression,它是与S-表达式对应的用类似数学符号表达的函数。M-表达式从未得到青睐,几乎所有今天的Lisp都使用S-表达式来操纵代码和数据二者。

大量而单一的使用圆括号,是Lisp与其他编程语言家族最直接明显的差别。为此学生们一直将Lisp戏称为:“迷失在愚蠢的括号中”(Lost In Stupid Parentheses),或“大量烦人的多余括号”(Lots of Irritating Superfluous Parentheses)[70]。但是S-表达式语法也承担了Lisp多数能力:语法极其正规,利于计算机操纵。然而Lisp的语法不局限于传统的括号表示法,它可以扩展为包括可替代表示法。例如,XMLisp是Common Lisp扩展,它采用元对象协议,集成了S-表达式和可扩展标记语言(XML)。

有赖于表达式给予了语言巨大的灵活性。由于Lisp函数都写为列表,它们可以完全就像数据那样处理。这允许了轻易的书写能操纵其他程序的程序,即进行元编程。很多Lisp方言使用宏系统来利用这个特征,它确使了语言扩展而几乎没有限制。

列表

书写Lisp列表,是以空白来分隔其元素,并包围以圆括号。例如,(1 2 foo)是其元素为三个原子12foo的一个列表。这些值是隐含的有类型的:它们分别是两个整数和叫做“符号”的Lisp专有数据类型,但不需要显式的声明。

空列表()也表示为特殊原子nil。这是Lisp中既是原子又是列表的唯一实体。

表示式被写为使用前缀表示法的列表。在列表中第一个元素是一个函数的名字、一个宏的名字、一个lambda表达式或特殊算符的名字(见后)。列表的余下部份是实际参数。例如,函数list将它的实际参数作为一个列表返回,所以表达式:

* (list 1 2 (quote foo)) (1 2 FOO) 

在前面例子中的foo之前的quote是特殊算符,它不求值就返回它的实际参数。任何未引述的表达式,在外围表达式被求值之前,都递归的被求值。例如:

* (list 1 2 (list 3 4)) (1 2 (3 4)) 

注意第三个实际参数是一个列表;列表是可以嵌套的。

算符

对算术算符的对待都是类似的。表达式:

* (+ 1 2 3 4) 10 

其在中缀表示法下的等价形式为:1 + 2 + 3 + 4

Lisp没有在Algol派生语言中实现的那样的算符概念。在Lisp中算术算符是可变参数函数(或多元函数),能够接受任何数目的实际参数。C-风格的++增加算符,有时在名字incf之下实现,给出的语法是:

* (setq x 0) 0 * (incf x) 1 

等价于(setq x (+ x 1)),它返回x的新值。

特殊算符(有时叫做特殊形式[71])提供了Lisp的控制结构。例如,特殊算符if接受三个实际参数。如果第一个实际参数为非nil,它求值为第二实际参数;否则它求值为第三个实际参数。因此表达式:

* (if nil (list 1 2 "foo") (list 3 4 "bar")) (3 4 "bar") 

当然,如果在nil的位置替换上非平凡的表达式会更有用处。

Lisp还提供逻辑算符andornotandor算符进行短路求值,并分别返回它们的第一个nil或非nil实际参数:

* (or (and "zero" nil "never") "James" 'task 'time) "James" 

Lambda表达式和函数定义

另一个特殊算符lambda,被用来绑定变量到值,接着对表达式求进行求值。这个算符还被用于建立函数:给lambda的实际参数是一个形式参数列表,和这个函数要求值的一个或多个表达式,它的返回值是其求值的最后一个表达式的值。表达式:

* (lambda (arg) (+ arg 1)) #<FUNCTION (LAMBDA (ARG)) {5344B3FB}> 

求值为一个函数,它接受一个实际参数,绑定它到arg并返回比这个实际参数大1的数。对待Lambda表达式于命名函数没有区别;它们以相同方式调用。如下表达式:

* ((lambda (arg) (+ arg 1)) 5) 6 

这里我们做了一次函数应用:我们通过传递给它值5而执行了这个匿名函数

命名函数是通过使用defun[30],将一个lambda表达式存储在一个符号之中而建立的:

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

(defun f (a) b...)在全局环境中定义一个名为f的新函数。它在概念上类似于表达式:

* (setf (fdefinition 'f) #'(lambda (a) (block f b...))) #<FUNCTION (LAMBDA (A)) {5344BA1B}> 

这里的setf是一个宏[72],用来设置第一个实际参数fdefinition 'f为一个新的函数对象。fdefinition是对命名为f的函数的全局函数定义。#'是特殊算符function的简写,它返回指定函数在当前词法环境下的一个函数对象[10]

作用域和闭包

按照变量的作用域[73],可将Lisp家族划分为两大支系,分别使用动态作用域[74],或使用静态(也叫做词法)作用域[75]SchemeCommon Lisp[76]Clojure缺省使用静态作用域,而AutoLISPPicoLisp[77]newLISP[78]使用动态作用域。Emacs Lisp自从Emacs版本24.1起使用动态和词法作用域二者[79]

原子

在最初的LISP中,有两种基础数据类型:原子和列表。列表是元素的一个有限有序序列,这里的每个元素要么是一个原子要么是一个列表,而原子要么是一个要么是一个符号。符号实质上是唯一性命名的项目,在源代码中写为字母数字串,并被要么用作一个变量名字要么符号处理英语Computer algebra中的一个数据项目。例如,列表(FOO (BAR 1) 2)包含三个元素:符号FOO、列表(BAR 1)和数2

在原子和列表之间的本质区别是原子是不可变的和唯一性的。出现在源代码中不同位置的两个原子,如果以完全相同方式写成则表示相同的对象,而每个列表都是一个分立的对象,它们可以独立于其他列表而改变 ,并可以通过比较算符而区分于其他列表。

随着后来的Lisp介入了更多的数据类型,和编程风格的演化,原子的概念失去了重要性。很多方言出于遗产兼容性而保留了谓词atom,定义它为对不是cons的任何对象都为真。

cons和列表

 
列表(42 69 613)的方框与指针示意图

Lisp列表被实现为单向链表[80]。这个链表的每个单元都叫做cons(在Scheme中叫做pair),它构成自两个指针,分别叫做car英语CAR and CDRcdr英语CAR and CDR

在众多可以用cons单元构建的数据结构中,最基本一个叫做“适当列表”(proper list)。适当列表要么是特殊的nil(空列表)符号,要么是一个cons,它的car指向一个数据项(它可以是另一个cons结构比如一个列表),而cdr指向另一个适当列表。

如果一个给定cons被接受为一个链表的头部,那么它的car指向这个列表的第一个元素,而它的cdr指向这个列表的余下部份。为此,在提及作为链表(而非树等)一部份的cons的时候,carcdr函数也分别叫做firstrest

因此,Lisp列表不是原子对象,它们类似C++或Java中的容器类的实例。一个列表就是链接的cons的一个聚集。引用一个给定列表的变量,简单的就是到列表中第一个cons的指针。遍历一个列表可以通过逐一cdr这个列表来进行,就是说连续的选取cdr来访问这个列表的每个cons;或者通过使用任何一个将一个函数映射在一个列表之上的高阶函数

由于cons和列表在Lisp系统中是普遍性的,经常有人误解它们是Lisp的唯一数据结构。事实上,除了最简单者之外的所有Lisp都有其他数据结构,比如向量(数组英语Array data type)、散列表、结构等等。

S-表达式表示列表

圆括号的S-表达式表示了链表结构。有多种方式将相同的列表表示为一个S-表达式。cons可以用“点对表示法”写为(a . b),这里的acarbcdr。更长的适当列表可以用点对表示法写为(a . (b . (c . (d . nil))))。这通常简写为列表表示法的(a b c d)。“不适当列表”(improper list)[81],可以用这二种表示法的组合来书写,比如列表(a b c . d)有三个cons,最后的cdrd,它就是完全特殊形式下的(a . (b . (c . d)))

列表处理过程

Lisp提供很多内建的过程,用来访问和控制列表。列表可以直接用list过程创建,它接受任何数目的实际参数,并返回这些实际参数的列表:

* (list 1 2 'a 3) (1 2 A 3) * (list 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列表是链表,附加两个列表有渐进时间复杂度  

* (append '(1 2) '(3 4)) (1 2 3 4) * (append '(1 2 3) '() '(a) '(5 6)) (1 2 3 A 5 6) 

共享结构

Lisp列表,作为单向链表,可以相互共享结构。就是说,两个列表可以有相同的尾部,或者最终的cons序列。例如,在执行下列Common Lisp代码之后:

* (setf foo (list 'a 'b 'c)) (A B C) * (setf bar (cons 'x (cdr foo))) (X B C) 

尾部(b c)在两个列表中都是相同的结构。它不是复件;对于两个列表指向bccons单元都在相同的内存位置。

共享结构而非复制可以得到相当客观的性能提升。但是这种技术可能以未预期的方式,交互于改变作为实际参数传递给它的列表的那些函数。改变一个列表,比如替代cgoose,将会影响另一个列表:

* (setf (third foo) 'goose) GOOSE * bar (X B GOOSE) 

不仅变更foo,还变更了bar,这可能是未预期的结果。这是缺陷的来源,为此改变它们的实际参数的那些函数被文档标示为破坏性的(destructive)。

函数式编程爱好者避免破坏性函数。在青睐函数式风格的Scheme方言中,破坏性函数的名字都标记了警告性感叹号,或者叫做“bang”,比如set-car!(读作set car bang),它替换一个conscar。在Common Lisp方言中,破坏性函数是司空见惯的,与set-car!等价的是rplaca,它的名字表示“replace car”。这个函数是不常见的,因为Common Lisp包括了一个特殊设施setf[72],用来轻易的定义和使用破坏性函数。在Common Lisp中常见的风格是在构建原型的时候写函数式代码(没有破坏性调用),接着将破坏性调用作为优化增加于可以安全的进行它们的地方。

自求值形式和引述

Lisp求值用户录入的表达式。符号和列表求值为某个其他(通常更简单的)表达式,例如:一个符号求值为它指名的变量的值;(+ 2 3)求值为5。但是,多数其他形式求值为其自身:如果录入5到Lisp中,它返回5

任何表达式都可以加上防止被求值的标记,这对于符号和列表是需要的。特殊算符quote承担了这个角色,它也简写为'(一个单引号)。例如,通常如果录入了符号foo,它返回对应变量的值(没有这个变量则为一个错误)。要引用这个文字英语Literal (computer programming)符号,录入要么(quote foo) ,要么更常见的'foo[37]

Common Lisp和Scheme二者还支持“反引述”(backquote)算符(在Scheme中叫做准引述英语quasiquote(quasiquote),这时录入`字符(重音符)。它几乎同于普通引述,除了它允许表达式被求值,并将它们的值插入到引述列表之中,这些表达式标记了,(逗号)表示去引述(unquote),或,@(逗号-at)表示拼接算符(unquote-splicing)。如果变量snue有值(bar baz),则`(foo ,snue)求值为(foo (bar baz)),而`(foo ,@snue)求值为(foo bar baz)。反引述经常用于定义宏展开[82][83]

自求值形式和引述形式是Lisp中文字英语Literal (computer programming)的等价者。在程序代码中可以修改(可变)文字的值。例如,如果一个函数返回一个引述形式,而调用这个函数的代码修改这个形式,这可以改变这个函数在后续调用时的行为:

* (defun should-be-constant () '(one two three)) SHOULD-BE-CONSTANT * (let ((stuff (should-be-constant))) (setf (third stuff) 'bizarre)) BIZARRE * (should-be-constant) (ONE TWO BIZARRE) 

像这样修改一个引述形式通常被认为是不良风格,并且被ANSI Common Lisp定义为是危险的。它会导致在编译文件中的未定义的行为,因为文件编译器可以合并类似的常量并将它们放置到写保护内存中,等等。

Lisp的引述形式化已经被Douglas Hofstadter(在《Gödel, Escher, Bach》中)和其他人注解为自引用哲学想法的例子。

控制结构

Lisp最初有很少的控制结构,但是在语言演化期间却增加了很多。Lisp最初的条件算符是cond[9],它或被视为后来的if-then-else结构的先驱。

Scheme方言的编程者经常使用尾递归表达循环。Scheme在学术计算机科学中的通行性,导致了一些学生相信尾递归是在Lisp中书写迭代的唯一的或最常用的方式,但是这是不正确的。所有常见的Lisp方言都有指令式风格的迭代构造,从Scheme的do循环到Common Lisp的复杂的loop表达式。此外,使之成为客观而非主观事物的关键要点,是Scheme对尾递归的处理提出了特殊要求,Scheme通常鼓励使用尾递归的原因,是语言定义明确的支持了这种实践。与之相反,ANSI Common Lisp不要求常称为尾递归消除的这种优化[84]。因此,不鼓励将尾递归风格作为使用更传统的迭代构造(比如dodolistloop)的替代品[85]。在Common Lisp中不只是风格偏好的问题,而是潜在的效率问题,这是因为在Common Lisp中明显的尾递归可能未被编译为简单的jump;并且也是程序正确性问题,这是因为在Common Lisp中尾递归可能增加栈的使用而有堆栈溢出风险。

一些Lisp控制构造是特殊算符,等价于其他语言的语法关键字。使用这些算符的表达式与函数调用有着相同的表面外观,但是不同之处在于参数不是必须求值的,或者在迭代表达式的情况下,可以被求值多于一次。

对比于多数其他主要编程语言,Lisp允许使用语言自身实现控制结构。一些控制结构被实现为Lisp宏,想知道它们是如何工作的编程者甚至可以通过宏展开来研究。

Common Lisp和Scheme二者都有非局部控制流程算符。在这些算符中的不同是在这两种方言之间最深的差异。Scheme使用call/cc过程支持可重入的续体,它允许一个程序保存(并在将来恢复)执行中的特定位置。Common Lisp不支持可重入的续体,但是支持处理逃脱续体的一些方式。

相同的算法在Lisp中经常可以用要么指令式要么函数式风格来表达。如上所述,Scheme趋于青睐函数式风格,使用尾递归和续体来表达控制流程。但是,指令式风格仍是很有可能的。很多Common Lisp编程者偏好的风格,可能让使用结构化编程语言比如C的编程者看着更加熟悉,而Scheme编程者偏好的风格更加密切类似于纯函数式编程语言比如Haskell

由于Lisp在列表处理上的早期遗产,它拥有与在序列上迭代有关的一组广泛的高阶函数。在其他语言中需要显式循环(比如C中的for循环)的很多情况下,在Lisp和很多函数式编程语言中,相同的任务可以通过高阶函数来完成。

一个好的例子是在Scheme中叫做map而在Common Lisp中叫做mapcar的函数。给定一个函数和一个或多个列表,mapcar按顺序将这个函数依次应用到这些列表的元素之上,并将结果收集入一个新的列表:

* (mapcar #'+ '(1 2 3 4 5) '(10 20 30 40 50)) (11 22 33 44 55) 

这个mapcar函数将+函数应用于每个对应的元素对之上。

程序代码的列表结构

在Lisp和其他语言之间的基本区别是,在Lisp中一个程序的文本表示,简单的是人类可读的描述,它同于底层Lisp系统使用的内部数据结构(链表、符号、数、字符等)。

Lisp利用这一点来实现了一个非常强力的系统。就像其他宏语言比如C,一个宏返回可以接着被编译的代码。但是不同于C的宏,Lisp的宏是函数因而可以利用Lisp的全部能力。

进一步的,因为Lisp代码作为列表有着相同的结构,宏可以使用语言中任何列表处理函数来建造。简要的说,Lisp可以在数据结构上做的任何事情,Lisp宏都可以在代码上做。相反的,在多数其他语言中,解析器的输出是纯粹的内部于语言实现的而不能被编程者操纵。

这个特征可以在语言中开发高效语言。例如,Common Lisp对象系统可以使用宏清晰的实现为一个语言扩展。这意味着如果一个应用需要不同的继承机制,它可以使用不同的对象系统。这直接的对立于多数其他语言;例如,Java不能支持多重继承并且没有增加它的合理方式。

在简单的Lisp实现中,这个列表结构被直接的解释来运行这个程序;一个函数是在文字上的一段列表结构,它被解释器在执行它的时候遍历。但是,多数后来的Lisp系统还包括一个编译器。编译器将列表结构转换成机器代码或字节码用于执行。这个代码可以像用常规语言比如C编译的代码一样快速。

宏在编译步骤之前展开,因而提供一些有价值的选项。如果一个程序需要一个预先计算了的表格,那么一个宏可以在编译时间建立这个表格,所以编译器只需要输出这个表格,而不需要在运行时间调用代码来建立这个表格。一些Lisp实现甚至拥有一种eval-when机制,允许代码在编译时间期间出现(在一个宏需要它的时候),而不出现在发行的模块中[86]

求值和读取–求值–打印循环

Lisp语言经常被以交互式命令行来使用,它还可以结合入集成开发环境(IDE)。用户在命令行录入表达式,或指示IDE将它们传送给Lisp系统。Lisp读取录入的表达式,求值它们,并打印结果。为此,Lisp命令行被叫做读取﹣求值﹣输出循环(REPL)。

REPL的基本操作描述如下。这是一个简化的描述,省略了很多真实Lisp的元素,比如引述和宏。

read函数接受文本的S-表达式作为输入,并将它们解析为内部数据结构。例如,如果你在提示符下录入文本(+ 1 2)read将它转换成有三个元素的一个链表:符号+、数1和数2。恰巧这个列表也是一段有效的Lisp代码,就是说它是可以被求值的。这是因为car这个列表指名了一个函数即加法运算。

注意foo将被读作一个单一符号。123将被读作数一百二十三。"123"将被读作字符串"123"

eval函数求值数据,返回零或多个其他Lisp数据作为结果。求值不必然意味着解释;一些Lisp系统编译所有的表达式为机器代码。但将求值描述为解释是很简单的:要求值其car指名一个函数的一个列表,eval首先求值在它的cdr中的每个实际参数,接着应用这个函数于这些实际参数。在这个案例中,这个函数是加法,而应用它于实际参数列表(1 2)产生答案3。这是这个求值的结果。

符号foo求值为符号foo的值。数据比如字符串"123"求值为相同的字符串。列表(quote (1 2 3))求值为列表(1 2 3)

print函数的工作是将输入表示给用户。对于简单结果比如3这是平凡的。求值为一段列表结构的一个表达式会要求print遍历这个列表并将结果输出为一个S-表达式。

要实现一个Lisp REPL,必需的只是实现这三个函数和一个无限循环函数。实现eval函数会很复杂是自然的,因为它必须也要实现所有特殊算符比如iflambda。它们完成后,一个基本的REPL就是一行代码:(loop (print (eval (read))))

Lisp REPL典型的也提供输入编辑、输入历史、错误处理和到调试器的接口。

Lisp通常使用及早求值。在Common Lisp中,实际参数以应用式次序(最左最内为先)求值,而在Scheme中实际参数的次序是未定义的,为编译器优化留下了余地[87]

语言创意

保罗·格雷厄姆辨识出Lisp区别于其他现存的语言如Fortran的九个重要特征[88]

Lisp是将程序代码的结构忠实而直接的表示为标准数据结构的第一个语言,这种品质后来被称为“同像性”。故而Lisp函数可以在Lisp程序中被操纵、更改、甚至创建,而不用低层操纵。 这通常被认为是语言表达能力方面的主要优势之一,使得语言适合于语法宏和元循环求值

条件表达式是麦卡锡用Fortran写一个象棋程序时发明的,他提议将其包含在ALGOL中但未被采纳[89]。Lisp中的条件表达式使用了一般性的cond结构,ALGOL 60采纳了约翰·巴科斯提议的if–then–else条件语句并使之流行起来[9]

Lisp深刻影响了艾伦·凯[90],他是在Xerox PARC开发Smalltalk的研究组的领导者;反过来Lisp又受到Smalltalk的影响,其后来的方言在1970年代接纳了面向对象编程特征,包括有继承的类、封装的实例、消息传递等。Flavors英语Flavors (programming language)对象系统介入了多重继承混入的概念。Common Lisp对象系统(CLOS)提供了多重继承、具有多分派的多方法、和头等泛化函数,从而产生了一种灵活而强力形式的动态分派。CLOS充当了很多后来的包括Scheme在内的Lisp的对象系统的模板,它经常通过Gregor Kiczales英语Gregor Kiczales等人发展出的元对象协议来实现,这是一种反射式元循环设计,其中的对象系统依据自身来定义。由于这些特征的融合,Lisp成为Smalltalk之后第二个具有元对象系统的语言。多年以后艾伦·凯宣称,只有Smalltalk和Lisp可以视为完全意义上的面向对象编程系统[91]

Lisp介入了自动垃圾回收的概念,即系统巡视来寻找无用的内存。现代复杂的垃圾回收算法比如分代垃圾回收的进步,受到了它在Lisp中使用的激励[92]

艾兹赫尔·戴克斯特拉在他的1972年图灵奖演讲中说道:

具有一些非常基本的原理作为基础,它[LISP]已经展示出卓越的稳定性。除此之外,LISP已经承载了相当可观的在某种意义上我们最复杂的计算机应用。LISP被玩笑的描述为“滥用计算机的最明智方式”。我认为这个描述是一种巨大的赞美,因为它传达了解放的全部意味:它辅助大量我们最有天赋的人类同胞去思考在以前不可能的想法。[93]

很大程度上由于它对于包括早期微处理器在内的早期计算机硬件的资源需求,Lisp未能像FortranALGOL后裔C语言那样在人工智能社区之外得以流行。由于它适合于复杂和动态的应用,Lisp在2010年代享有了一定程度的大众关注的复兴[94]

七个原始运算

保罗·格雷厄姆约翰·麦卡锡的最初论文中提炼出如下7个原始运算[95]

quote

(quote x)返回x,通常简记为'x

* (quote a) A * 'a A * (quote (a b c)) (A B C) 

quote寫成'只是一種語法糖[37]

atom

(atom x)x是一个atom或者空的list时返回原子t,否则返回NIL。在Common Lisp中通常习惯用原子t列表示真,而用空列表()NIL列表示假。例如:

* (atom 'a) T * (atom '(a b c)) NIL * (atom '()) T 

atom是需要求出实际参数值的算符,下面展示quote算符的作用,即通过引述一个列表,避免它被求值(eval)。一个未被引述的列表达式作为实际参数,atom会将其视为代码,例如:

* (atom (atom 'a)) T 

这是因为(atom 'a)已求值出结果t,把它代入(atom (atom 'a)),成为(atom t),从而这个列表达式的结果是t

反之一个被引述的列表,仅仅被视为列表,例如:

* (atom '(atom 'a)) NIL 

引用看上去有些奇怪,因为很难在其它语言中找到类似的概念,但正是这一特征构成了Lisp最为与众不同的特点:代码和数据使用相同的结构来列表示,只是用quote来区分它们。

eq

(eq x y)xy指向相同的对象的时候返回t,否则返回NIL,例如:

* (eq 'a 'a) T * (eq 'a 'b) NIL * (eq '() '()) T * (eq '(a b c) '(a b c)) NIL 

值得注意的是在Common Lisp中,原子对象在内存中只会有一份拷贝,所以(eq 'a 'a)返回t

car

(car x)要求x是一个列表,它返回x中的第一个元素,例如:

* (car '(a b)) A 

cdr

(cdr x)同样要求x是一个列表,它返回x中除第一个元素之外的所有元素组成的列表,例如:

* (cdr '(a b c)) (B C) 

cons

cons x y预期y的值是一个列表,并且返回包含x的值和随后y的值的那些元素的一个列表,例如:

* (cons 'a 'b) (A . B) * (cons 'a (cons 'b 'c)) (A B . C) * (cons 'a (cons 'b ())) (A B) * (cons 'a (cons 'b (cons 'c ()))) (A B C) 

cond

(cond (p1 e1) ...(pn en))的求值规则如下:对“条件列表达式p”依次求值,直到有一个返回t。如果能找到这样的p列表达式,相应的“结果列表达式e”的值,作为整个cond列表达式的返回值。例如:

* (cond ((eq 'a 'b) 'first) ((atom 'a) 'second)) SECOND 

对象系统

已经有各种对象系统和模型建造在Lisp之上、旁边或其中,包括:

  • Common Lisp对象系统(CLOS),是ANSI Common Lisp内在的一部份。CLOS衍生自New Flavors和CommonLOOPS。ANSI Common Lisp是第一个标准化的面向对象编程语言(1994, ANSI X3J13)。
  • ObjectLisp[96]Object Lisp英语Object Lisp,用于Lisp机器公司英语Lisp Machines和早期版本的Macintosh Common Lisp。
  • LOOPS(Lisp面向对象编程系统)和后来的CommonLOOPS英语CommonLOOPS
  • Flavors英语Flavors (programming language),建造于MIT,它的后代是New Flavors(由Symbolics.com开发)。
  • KR(知识表达),它是用来辅助书写Common Lisp的GUI库Garnet的基于约束英语Constraint satisfaction的对象系统。
  • 知识工程环境英语Knowledge Engineering Environment(KEE)使用叫做UNITS的对象系统并集成入了推理机[97]推理维护系统英语Reason maintenance(ATMS)。

範例

Hello World!

这个Hello World!例子展示Lisp的三种主要方言,在基本输出和函数定义上的用法:

Scheme Common Lisp Clojure
;; 显示过程在屏幕中打印字符串 ;; 并返回未规定值 (display "Hello, world!") ;; 定义过程hello-world (define (hello-world) (display "Hello, world!")) ;; 调用过程hello-world (hello-world) 
;; 格式化函数在第一个参数是t时,  ;; 在屏幕中打印字符串,并返回NIL (format t "hello, world!") ;; 定义函数hello-world (defun hello-world () (format t "hello, world!")) ;; 调用函数hello-world (hello-world) 
;; 打印函数在屏幕中打印字符串 ;; 并返回nil (print "hello, world!") ;; 定义函数hello-world (defn hello-world [] (print "hello, world!")) ;; 调用函数hello-world (hello-world) 

阶乘

Lisp语法自然的适合于递归。数学问题比如递归定义集合的枚举,在这种表示法中表达是很容易的。例如,要求值一个数的阶乘

(defun factorial (n) (if (zerop n) 1 (* n (factorial (1- n))))) 

下面的版本在底层Lisp系统进行尾递归优化时比前面版本取用更少的堆栈空间:

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

对比上述例子,下面的指令式版本使用了Common Lisploop宏:

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

反转列表

下列函数反转一个列表。它与Lisp内建的reverse函数做同样的事情:

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

参见

参考文献

  1. ^ Julia Documentation - Introduction. Julia builds upon the lineage of mathematical programming languages, but also borrows much from popular dynamic languages, including Lisp, Perl, Python, Lua, and Ruby. …… some advantages of Julia over comparable systems include: …… Lisp-like macros and other metaprogramming facilities. 
  2. ^ Wolfram Language Q&A. Wolfram Research. LISP and APL were two early influences, as was Stephen Wolfram's 1981 SMP symbolic computation language. 
  3. ^ Edwin D. Reilly. . Greenwood Publishing Group. 2003: 156–157 [2021-10-24]. ISBN 978-1-57356-521-9. (原始内容存档于2020-08-05). 
  4. ^ 4.0 4.1 John McCarthy. (PDF). Artificial Intelligence Laboratory, Stanford University. 12 February 1979 [2021-10-25]. (原始内容 (PDF)存档于2020-11-07). There were two motivations for developing a language for the IBM 704. First, IBM was generously establishing a New England Computation Center at M.I.T. …… Second, IBM was undertaking to develop a program for proving theorems in plane geometry (based on an idea of Marvin Minsky’s), ……. ……
    In connection with IBM’s plane geometry project, Nathaniel Rochester and Herbert Gelernter英语Herbert Gelernter (on the advice of McCarthy) decided to implement a list processing language within FORTRAN, ……. This work was undertaken by Herbert Gelernter and Carl Gerberich at IBM and led to FLPL, standing for FORTRAN List Processing Language. ……
    I spent the summer of 1958 at the IBM Information Research Department at the invitation of Nathaniel Rochester and chose differentiating algebraic expressions as a sample problem. It led to the following innovations beyond FLPL:
    a. Writing recursive function definitions using conditional expressions. ……
    b. The maplist function that forms a list of applications of a functional argument to the elements of a list. ……
    c. To use functions as arguments, one needs a notation for functions, and it seemed natural to use the λ-notation of Church (1941). ……
    d. The recursive definition of differentiation made no provision for erasure of abandoned list structure. ……
    The implementation of LISP began in Fall 1958. ……
    LISP is now the second oldest programming language in present widespread use (after FORTRAN and not counting APT, which isn’t used for programming per se).
     
  5. ^ . (原始内容存档于2001-07-27). Lisp is a survivor, having been in use for about a quarter of a century. Among the active programming languages only Fortran has had a longer life. 
  6. ^ Guy L. Steele Jr., Gerald J. Sussman. . MIT Libraries. May 1978 [2020-08-01]. hdl:1721.1/6094. (原始内容存档于2021-01-24). Contrary to popular belief, LISP was not originally derived from Church's λ-calculus [Church] [LISP History]. The earliest LISP did not have a well-defined notion of free variables or procedural objects. Early LISP programs were similar to recursion equations, defining functions on symbolic expressions ("S-expressions"). They differed from the equations of pure recursive function theory Kleene by introducing the conditional expression construction (often called the "McCarthy conditional"), to avoid "pattern-directed invocation". That is, in recursive function theory one would define the factorial function by the following two equations:
      factorial(0) = 1
      factorial(successor(x)) = successor(x) * factorial(x)
    In early LISP, however, one would have written:
      factorial[x] = [x=0 → 1; T → x*factoria1[x-1]]
    where "[a → b; T → c]" essentially means "if a then b else c". The recursive function theory version depends on selecting which of two equations to use by matching the argument to the left-hand sides (such a discipline is actually used in the PROLOG language [Warren]); the early LISP version represents this decision as a conditional expression.
    The theory of recursion equations deals with functions over the natural numbers. In LISP, however, one is interested in being able to manipulate algebraic expressions, programs, and other symbolic expressions as data structures. While such expressions can be encoded as numbers (using the technique of "arithmetization" developed by Kurt Gödel), such an encoding is not very convenient. Instead, a new kind of data called "S-expressions" (for "symbolic expressions") is introduced specifically to provide convenient encodings. S-expressions can be defined by a set of formal inductive axioms analogous to the Peano postulates used to define natural numbers.
     
  7. ^ 7.0 7.1 John McCarthy. History of Lisp (PDF). Artificial Intelligence Laboratory, Stanford University. 12 February 1979. To use functions as arguments, one needs a notation for functions, and it seemed natural to use the λ-notation of Church (1941). I didn’t understand the rest of his book, so I wasn’t tempted to try to implement his more general mechanism for defining functions. Church used higher order functionals instead of using conditional expressions. Conditional expressions are much more readily implemented on computers. ……
    One mathematical consideration that influenced LISP was to express programs as applicative expressions built up from variables and constants using functions. I considered it important to make these expressions obey the usual mathematical laws allowing replacement of expressions by expressions giving the same value. The motive was to allow proofs of properties of programs using ordinary mathematical methods. This is only possible to the extent that side-effects can be avoided. Unfortunately, side-effects are often a great convenience when computational efficiency is important, and “functions” with side-effects are present in LISP. However, the so-called pure LISP is free of side-effects, and (Cartwright 1976) and (Cartwright and McCarthy 1978) show how to represent pure LISP programs by sentences and schemata in first order logic and prove their properties. ……
    Free variables. In all innocence, James R. Slagle英语James Robert Slagle programmed the following LISP function definition and complained when it didn’t work right ……. …… In modern terminology, lexical scoping was wanted, and dynamic scoping was obtained.
    I must confess that I regarded this difficulty as just a bug and expressed confidence that Steve Russell would soon fix it. He did fix it but by inventing the so-called FUNARG device that took the lexical environment along with the functional argument. Similar difficulties later showed up in Algol 60, and Russell’s turned out to be one of the more comprehensive solutions to the problem. While it worked well in the interpreter, comprehensiveness and speed seem to be opposed in compiled code, and this led to a succession of compromises. …… the interested reader is referred to (Moses 1970) as a place to start.
     
    David Turner英语David Turner (computer scientist). (PDF). [2021-10-25]. (原始内容 (PDF)存档于2020-04-15). The data on which LISP works is the S-language. ……
    The M-language defines computations on S-expressions. ……
    This is computationally complete. McCarthy (1960, Sect. 6) showed an arbitrary flowchart can be coded as mutually recursive functions.
    The M-language of McCarthy (1960) is first order, as there is no provision to pass a function as argument or return a function as result.
    However, McCarthy shows that M-language expressions and functions can be easily encoded as S-expressions and then defines in the M-language functions, eval and apply, that correctly interpret these S-expressions.
    Thus LISP allows meta-programming, that is treating program as data and vice versa, by appropriate uses of eval and quote. The 1960 paper gives the impression, quite strongly, that McCarthy saw this as removing any limitation stemming from the M-Language itself being first order.
    It was originally intended that people would write programs in the M-language, in an Algol-like notation. In practice LISP programmers wrote their code directly in the S-language form, and the M-language became a kind of ghost that hovered in the background — theoretically important but nobody used it.
    In LISP 1.5 (McCarthy et al. 1962) atoms acquired property lists, which serve several purposes and numbers appeared, as another kind of atom, along with basic arithmetic functions. ……
    LISP was not based on the lambda calculus, despite using the word “LAMBDA” to denote functions. At the time he invented LISP, McCarthy was aware of (Church 1941) but had not studied it. The theoretical model behind LISP was Kleene’s theory of first order recursive functions. (McCarthy made these statements, or very similar ones, in a contribution from the floor at the 1982 ACM symposium on LISP and functional programming in Pittsburgh. No written version of this exists, as far as know.)
    The M-language was first order, as already noted, but you could pass a function as a parameter by quotation, i.e. as the S-expression which encodes it. Unfortunately, this gives the wrong binding rules for free variables (dynamic instead of lexicographic). ……
    McCarthy (1978) reports that this problem (wrong binding for free variables) showed up very early in a program of James Slagle. At first McCarthy assumed it was a bug and expected it to be fixed, but it actually springs from something fundamental — that meta-programming is not the same as higher order programming. Various devices were invented to get round this FUNARG problem, as it became known.
    Not until SCHEME (Sussman 1975) did versions of LISP with default static binding appear. Today all versions of LISP are lambda calculus based.
     
  8. ^ The Top Programming Languages in Artificial Intelligence. Artificial Intelligence. APRO. [2021-02-15]. (原始内容于2020-10-30). 
  9. ^ 9.0 9.1 9.2 John McCarthy. Recursive functions of symbolic expressions and their computation by machine, Part I. (PDF). Communications of the ACM (ACM New York, NY, USA). 1960, 3 (4): 184–195. doi:10.1145/367177.367199. A conditional expression has the form
    (p1 → e1, …, pn → en)
    where the p's are propositional expressions and the e's are expressions of any kind. It may be read, “If p1 then e1 otherwise if p2 then e2, …, otherwise if pn then en,” or “p1 yields e1, …, pn yields en.”
    I sent a proposal for conditional expressions to a CACM forum on what should be included in Algol 60. Because the item was short, the editor demoted it to a letter to the editor, for which CACM subsequently apologized. The notation given here was rejected for Algol 60, because it had been decided that no new mathematical notation should be allowed in Algol 60, and everything new had to be English. The if...then...else that Algol 60 adopted was suggested by John Backus.
     
    John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. LISP 1.5 Programmer's Manual (PDF) 2nd. MIT Press. 1985 [1962]. ISBN 0-262-13011-4. The conditional expression [p1 → e1; …; pn → en] is translated into (COND (p1* e1*) … (pn* en*)). 
  10. ^ 10.0 10.1 John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. LISP 1.5 Programmer's Manual (PDF) 2nd. MIT Press. 1985 [1962]. ISBN 0-262-13011-4. Mathematically, it is possible to have functions as arguments of other functions. For example, in arithmetic one could define a function operate [op;a;b], where op is a functional argument that specifies which arithmetic operation is to be performed on a and b. ……
    In LISP, functional arguments are extremely useful. A very important function with a functional argument is maplist. Its M-expression definition is
      maplist[x;fn]=[null[x]→NIL;
        T→cons[fn[x];maplist[cdr[x];fn]]]
    ……
    The functional argument is, of course, a function translated into an S-expression. It is bound to the variable fn and is then used whenever fn is mentioned as a function. The S-expression for maplist itself is as follows:
      (MAPLIST (LAMBDA (X FN) (COND ((NULL X) NIL)
        (T (CONS (FN X) (MAPLIST (CDR X) FN))) )))
    ……
    Using maplist, we define change by
      change[a]=maplist[a;λ[[j];cons[car[j];X]]]
    This is not a valid M-expression as defined syntactically in section 1.5 because a function appears where a form is expected. This can be corrected by modifying the rule defining an argument so as to include functional arguments:
      <argument> ::= <form> | <function>
    We also need a special rule to translate functional arguments into S-expression. If fn is a function used as an argument, then it is translated into (FUNCTION fn*).
    Example
      (CHANGE (LAMBDA (A) (MAPLIST A (FUNCTION
        (LAMBDA (J) (CONS (CAR J) (QUOTE X))) )))
    An examination of evalquote shows that QUOTE will work instead of FUNCTION, provided that there are no free variables present.
     
    Special Operator FUNCTION. Common Lisp HyperSpec.
    Syntax:
      function namefunction
    Arguments and Values:
      name - a function name or lambda expression.
      function - a function object.
    Description:
      The value of function is the functional value of name in the current lexical environment.
    ……
    Notes:
      The notation #' name may be used as an abbreviation for (function name).
     
    Function FUNCALL. Common Lisp HyperSpec.
    Syntax:
      funcall function &rest argsresult*
    Arguments and Values:
      function - a function designator.
      argsarguments to the function.
      results - the values returned by the function.
    Description:
      funcall applies function to args. If function is a symbol, it is coerced to a function as if by finding its functional value in the global environment.
     
  11. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-09-23]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). A function can be simply a name. In this case its meaning must be previously understood. A function may be defined by using the lambda notation and establishing a correspondence between the arguments and the variables used in a form. If the function is recursive, it must be given a name by using a label. ……
    When a symbol stands for a function, the situation is similar to that in which a symbol stands for an argument. When a function is recursive, it must be given a name. This is done by means of the form LABEL, which pairs the name with the function definition on the a-list. The name is then bound to the function definition, just as a variable is bound to its value.
    In actual practice, LABEL is seldom used. It is usually more convenient to attach the name to the definition in a uniform manner. This is done by putting on the property list of the name, the symbol EXPR followed by the function definition. The pseudo-function define used at the beginning of this section accomplishes this. When apply interprets a function represented by an atomic symbol, it searches the p-list of the atomic symbol before searching the current a-list. Thus a define will override a LABEL.
    The fact that most functions are constants defined by the programmer, and not variables that are modified by the program, is not due to any weakness of the system. On the contrary, it indicates a richness of the system which we do not know how to exploit very well.
     
  12. ^ Paul Graham. . [2013-03-14]. (原始内容存档于2019-06-07). 
  13. ^ Chisnall, David. . 2011-01-12 [2021-10-24]. (原始内容存档于2021-03-01). 
  14. ^ Jones, Robin; Maynard, Clive; Stewart, Ian. The Art of Lisp Programming. Springer Science & Business Media. December 6, 2012: 2. ISBN 9781447117193. 
  15. ^ John McCarthy. (PDF). Communications of the ACM (ACM New York, NY, USA). 1960, 3 (4): 184–195 [2021-09-23]. doi:10.1145/367177.367199. (原始内容 (PDF)存档于2021-02-19). In this article, we first describe a formalism for defining functions recursively. …… Next, we describe S-expressions and S-functions, give some examples, and then describe the universal S-function apply which plays the theoretical role of a universal Turing machine and the practical role of an interpreter. Then we describe the representation of S-expressions in the memory of the IBM 704 by list structures similar to those used by Newell, Shaw英语Cliff Shaw and Simon, and the representation of S-functions by program. Then we mention the main features of the LISP programming system for the IBM 704. Next comes another way of describing computations with symbolic expressions, and finally we give a recursive function interpretation of flow charts. ……
    We shall need a number of mathematical ideas and notations concerning functions in general. Most of the ideas are well known, but the notion of conditional expression is believed to be new, and the use of conditional expressions permits functions to be defined recursively in a new and convenient way. ……
    We shall first define a class of symbolic expressions in terms of ordered pairs and lists. Then we shall define five elementary functions and predicates, and build from them by composition, conditional expressions, and recursive definitions an extensive class of functions of which we shall give a number of examples. We shall then show how these functions themselves can be expressed as symbolic expressions, and we shall define a universal function apply that allows us to compute from the expression for a given function its value for given arguments. Finally, we shall define some functions with functions as arguments and give some useful examples. ……
    The LISP programming system is a system for using the IBM 704 computer to compute with symbolic information in the form of S-expressions. …… The basis of the system is a way of writing computer programs to evaluate S-functions. …… In addition to the facilities for describing S-functions, there are facilities for using S-functions in programs written as sequences of statements along the lines of FORTRAN or ALGOL. ……
    There are a number of ways of defining functions of symbolic expressions which are quite similar to the system we have adopted. Each of them involves three basic functions, conditional expressions, and recursive function definitions, but the class of expressions corresponding to S-expressions is different, and so are the precise definitions of the functions. We shall describe one of these variants called linear LISP. ……
    Since both the usual form of computer program and recursive function definitions are universal computationally, it is interesting to display the relation between them. The translation of recursive symbolic functions into computer programs was the subject of the rest of this report. In this section we show how to go the other way, at least in principle.
     
  16. ^ Michael J. Fischer英语Michael J. Fischer. (PDF). LISP AND SYMBOLIC COMPUTATION: An International Journal, 6, 259–288. 1993 [2021-11-10]. (原始内容 (PDF)存档于2022-03-02). Two general approaches were taken in order to have programming languages with fully specified semantics: (i) Better specification methods were developed that were adequate to fully describe existing large programming languages such as PL/1. (ii) New languages were developed with clean mathematical structure that were more amenable to formal description. McCarthy pioneered the latter approach in basing the LISP 1.5 programming language on a simpler functional language, sometimes called “pure LISP” or M-expressions, that was defined in a mathematical style, independent of a particular machine or implementation.
    Pure LISP allows the definition and evaluation of functions over S-expressions. The lambda notation for functional abstraction is borrowed from Church’s lambda calculus, but otherwise there is little similarity between the two systems. Pure LISP has no higher-order functions, and call-by-value evaluation order is implicitly assumed. Two special constructs, conditional expressions and the label operator, allow recursive functions to be defined. Limited as it is, pure LISP is nevertheless powerful enough to express all partial recursive functions and hence provides an adequate basis for a theory of computation.
    The LISP 1.5 programming language extends pure LISP in many ways that make it more useful in practice but at the same time tend to destroy its clean mathematical properties. Its semantics is defined by an interpreter written in a mixture of pure LISP and English. The distinction between programs and data is blurred. Higher-order functions, assignment, and a global symbol table are added.
     
  17. ^ CGOL: Algol-like language that compiles into Common Lisp. 
  18. ^ John McCarthy. History of Lisp (PDF). Artificial Intelligence Laboratory, Stanford University. 12 February 1979. The programs to be hand-compiled were written in an informal notation called M-expressions英语M-expression intended to resemble FORTRAN as much as possible. Besides FORTRAN-like assignment statements and go tos, the language allowed conditional expressions and the basic functions of LISP. Allowing recursive function definitions required no new notation from the function definitions allowed in FORTRAN I - only the removal of the restriction - as I recall, unstated in the FORTRAN manual - forbidding recursive definitions. The M-notation also used brackets instead of parentheses to enclose the arguments of functions in order to reserve parentheses for list-structure constants. It was intended to compile from some approximation to the M-notation, but the M-notation was never fully defined, because representing LISP functions by LISP lists became the dominant programming language when the interpreter later became available. A machine readable M-notation would have required redefinition, because the pencil-and-paper M-notation used characters unavailable on the IBM 026 key punch英语Keypunch.
    The READ and PRINT programs induced a de facto standard external notation for symbolic information, e.g. representing x + 3y + z by (PLUS X (TIMES 3 Y) Z) and (∀x)(P (x) ∨ Q(x, y) by (ALL (X) (OR (P X) (Q X Y))).
     
  19. ^ Stoyan, Herbert. . LFP '84: Proceedings of the 1984 ACM Symposium on LISP and functional programming. Association for Computing Machinery: 307. 1984-08-06. doi:10.1145/800055.802047. (原始内容存档于2005-04-05). As far as we know the first universal function was indeed applyeval was not present at all or not seen to be important. When McCarthy was working on this function S. Russel saw it and suggested translating it by hand - as he had done so often - and adding it to the program system. McCarthy recalls: "… this EVAL was written and published in the paper and Steve Russell said, look, why don't I program this EVAL and you remember the interpreter, and I said to him, ho, ho, you're confusing theory with practice, this EVAL is intended for reading not for computing. But he went ahead and did it. That is, he compiled the EVAL in my paper into 704 machine code fixing bugs and then advertised this as a LISP interpreter which it certainly was, so at that point LISP had essentially the form that it has today, the S-expression form ...". 
  20. ^ John McCarthy. History of Lisp (PDF). Artificial Intelligence Laboratory, Stanford University. 12 February 1979. Another way to show that LISP was neater than Turing machines was to write a universal LISP function and show that it is briefer and more comprehensible than the description of a universal Turing machine. This was the LISP function eval[e,a], which computes the value of a LISP expression e - the second argument a being a list of assignments of values to variables. (a is needed to make the recursion work). Writing eval required inventing a notation representing LISP functions as LISP data, and such a notation was devised for the purposes of the paper with no thought that it would be used to express LISP programs in practice. Logical completeness required that the notation used to express functions used as functional arguments be extended to provide for recursive functions, and the LABEL notation was invented by Nathaniel Rochester for that purpose. ……
    S.R. Russell noticed that eval could serve as an interpreter for LISP, promptly hand coded it, and we now had a programming language with an interpreter. ……
    Once the eval interpreter was programmed, it became available to the programmer, and it was especially easy to use because it interprets LISP programs expressed as LISP data. In particular, eval made possible FEXPRS and FSUBRS which are “functions” that are not given their actual arguments but are given the expressions that evaluate to the arguments and must call eval themselves when they want the expressions evaluated. The main application of this facility is to functions that don't always evaluate all of their arguments; they evaluate some of them first, and then decide which others to evaluate. This facility resembles Algol's call-by-name but is more flexible, because eval is explicitly available. A first order logic treatment of “extensional” FEXPRs and FSUBRs now seems possible.
     
  21. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. LISP 1.5 Programmer's Manual (PDF) 2nd. MIT Press. 1985 [1962]. ISBN 0-262-13011-4. 
    A form is an expression that can be evaluated. A form that is merely a constant has that constant as its value. If a form is a variable, then the value of the form is the S-expression that is bound to that variable at the time when we evaluate the form. ……
    A function can be simply a name. In this case its meaning must be previously understood. A function may be defined by using the lambda notation and establishing a correspondence between the arguments and the variables used in a form. If the function is recursive, it must be given a name by using a label. ……
    An interpreter or universal function is one that can compute the value of any given function applied to its arguments when given a description of that function. (Of course, if the function that is being interpreted has infinite recursion, the interpreter will recur infinitely also.)
    We are now in a position to define the universal LISP function evalqyote[fn;args]. When evalquote is given a function and a list of arguments for that function, it computes the value of the function applied to the arguments.
    LISP functions have S-expressions as arguments. In particular, the argument "fn" of the function evalquote must be an S-expression. Since we have been writing functions as M-expressions, it is necessary to translate them into S-expressions. ……
    evalquote is defined by using two main functions, called eval and apply. apply handles a function and its arguments, while eval handles forms. Each of these functions also has another argument that is used as an association list for storing the values of bound variables and function names. ……
    A variable is a symbol that is used to represent an argument of a function. ……
    The formalism for variables in LISP is the Church lambda notation. The part of the interpreter that binds variables is called apply. When apply encounters a function beginning with LAMBDA, the list of variables is paired with the list of arguments and added to the front of the a-list During the evaluation of the function, variables may be encountered. They are evaluated by looking them up on the a-list. If a variable has been bound several times, the last or most recent value is used. The part of the interpreter that does this is called eval. The following example will illustrate this discussion. Suppose the interpreter is given the following doublet:
      fn:   (LAMBDA (X Y) (CONS X Y))
      args: (A B)
    evalquote will give these arguments to apply. (Look at the universal function of Section I.)
      apply[(LAMBDA (X Y) (CONS X Y)); (A B);NIL]
    apply will bind the variables and give the function and a-list to eval.
      eval[(CONS X Y); ((X . A) (Y . B))]
    eval will evaluate the variables and give it to cons.
      cons[A;B] = (A . B)
    The actual interpreter skips one step required by the universal function, namely, apply[CONS;(A B);((X . A) (Y . B))]. ……
    It is sometimes assumed that a constant stands for itself as opposed to a variable which stands for something else. …… It seems more reasonable to say that one variable is more nearly constant than another if it is bound at a higher level and changes value less frequently.
    In LISP, a variable remains bound within the scope of the LAMBDA that binds it. When a variable always has a certain value regardless of the current a-list, it will be called a constant. This is accomplished by means of the property list (p-list) of the variable symbol. Every atomic symbol has a p-list. When the p-list contains the indicator APVAL, then the symbol is a constant and the next item on the list is the value. eval searches p-lists before a-lists when evaluating variables, thus making it possible to set constants. ……
    An interesting type of constant is one that stands for itself. NIL is an example of this. It can be evaluated repeatedly and will still be NIL. T, F. NIL, and other constants cannot be used as variables. ……
    The program form has the structure -
      (PROG, list of program variables, sequence of statements and atomic' symbols…)
    ……
    Program variables are treated much like bound variables, but they are not bound by LAMBDA. The value of each program variable is NIL until it has been set to something else. To set a program variable, use the form SET. To set variable PI to 3.14 write (SET (OUOTE PI) 3.14). SETQ is like SET except that it quotes its first argument. Thus (SETQ PI 3.14). SETQ is usually more convenient. SET and SETQ can change variables that are on the a-list from higher level functions. The value of SET or SETQ is the value of its second argument. ……
    Every atomic symbol has a property list. When an atomic symbol is read in for the first time, a property list is created for it.
    A property list is characterized by having the special constant 777778 (i.e., minus 1) as the first element of the list. The rest of the list contains various properties of the atomic symbol. Each property is preceded by an atomic symbol which is called its indicator. Some of the indicators are:
      PNAME - the BCD英语BCD (character encoding) print name of the atomic symbol for input-output use.
      EXPR - S-expression defining a function whose name is the atomic symbol on whose property list the EXPR appears.
      SUBR - Function defined by a machine language subroutine.
      APVAL - Permanent value for the atomic symbol considered as a variable.
    The atomic symbol NIL has two things on its property list - its PNAME, and an APVAL that gives it a value of NIL. Its property list looks like this:
    .---.---. .-----.---. .---.---. .-----.---. .---.---. |-1 | |->|APVAL| |->| | |->|PNAME| |->| | / | `---'---' `-----'---' `---'---' `-----'---' `---'---' ^ | | | .-V-.---. .-V-.---. | | | / | | | / | | `---'---' `---'---' | | | '-----------------------' .-V-----. | NIL???| `-------' 
    ……
    The indicator EXPR points to an S-expression defining a function. The function define puts EXPR's on property lists. After defining ff, its property list would look like this
    .---.---. .-----.---. .---.---. .-----.---. .---.---. |-1 | |->|EXPR | |->| | |->|PNAME| |->| | / | `---'---' `-----'---' `---'---' `-----'---' `---'---' .-----------------------' | .-V----.---. .---.---. .---.---. .-V-.---. |LAMBDA| |->| | |->| | / | | | / | `------'---' `---'---' `---'---' `---'---' | | | .---.---. .----.---. .-V-----. | X | / | |COND| |-> - - - | FF????| `---'---' `----'---' `-------' 
    ……
    An indicator on a property list that does not have a property following it is called a flag. ……
    Numbers are represented by a type of atomic symbol in LISP. This word consists of a word with -1 in the address, certain bits in the tag which specify that it is a number and what type it is, and a pointer to the number itself in the decrement of this word.
    Unlike atomic symbols, numbers are not stored uniquely.
    For example, the decimal number 15 is represented as follows:
    .----.-.---. .--------------. | -1 |1| |->| 000000000017 | `----'-'---' `--------------' 
    ……

    special[x]    SUBR    pseudo-function
    The list x contains the names of variables that are to be declared SPECIAL. ……
    common[x]    SUBR    pseudo-function
    The list x contains the names of variables that are to be declared COMMON. ……
    PROG feature is an FSUBR coded into the system. ……
    When a set or a setq is encountered, the name of the variable is located on the a-list. The value of the variable (or cdr of the pair) is actually replaced with the new value. ……
    The following points should be noted concerning declared variables.
      1. Program variables follow the same rules as λ variables do.
        a. If a variable is purely local, it need not be declared.
        b. Special variables can be used as free variables in compiled functions. They may be set at a lower level than that at which they are bound.
        c. Common program variables maintain complete communication between compiled programs and the interpreter.
      2. set as distinct from setq can only be used to set common variables.”

  22. ^ 22.0 22.1 John McCarthy; Robert Brayton; Daniel Edwards; Phyllis Fox英语Phyllis Fox; Louis Hodes英语Louis Hodes; David Luckham英语David Luckham; Klim Maling; David Park英语David Park (computer scientist); Steve Russell. (PDF). Boston, Massachusetts: Artificial Intelligence Group, M.I.T. Computation Center英语M.I.T. Computation Center and Research Laboratory. March 1960 [2021-09-23]. (原始内容 (PDF)存档于2022-04-02). 
  23. ^ Timothy P. Hart, Michael I. Levin. AI Memo 39-The new compiler (PDF). 
    Timothy P. Hart, Michael I. Levin. LISP 1.5 compiler. 
  24. ^ Hart, Timothy P. AIM-057, MACRO Definitions for LISP, Timothy P. Hart. October 1963. hdl:1721.1/6111. 
  25. ^ Gerald J. Sussman, Guy L. Steele Jr. . 1978 [2021-10-26]. (原始内容存档于2022-04-06). SCHEME is a dialect of LISP. It is an expression-oriented, applicative order, interpreter-based language which allows one to manipulate programs as data.
    It differs from most current dialects of LISP in that it closes all lambda-expressions in the environment of their definition or declaration, rather than in the execution environment. This has the consequence that variables are normally lexically scoped, as in ALGOL. However, in contrast with ALGOL, SCHEME treats procedures as a first-class data type. They can be the values of variables, the returned values of procedures, and components of data structures.
    Another difference from LISP is that SCHEME is implemented in such a way that tail-recursions execute without net growth of the interpreter stack. The effect of this is that a procedure call behaves like a GOTO and thus procedure calls can be used to implement iterations, as in PLASMA.
     
  26. ^ The 36-bit word size of the PDP-6/PDP-10 was influenced by the usefulness of having two Lisp 18-bit pointers in a single word. Peter J. Hurley. . Newsgroup: alt.folklore.computers. 18 October 1990 [2021-10-24]. Usenet: 84950@tut.cis.ohio-state.edu. (原始内容存档于2013-05-28). The PDP-6 project started in early 1963, as a 24-bit machine. It grew to 36 bits for LISP, a design goal. 
  27. ^ Gerald Jay Sussman, Terry Winograd. Micro-planner Reference Manual. AI Memo No, 203, MIT Project MAC. 1970. Micro-Planner is an implementation of a subset of Cal Hewitt's language, PLANNER by Gerald Jay Sussman, Terry Winograd, and Eugene Charniak on the AI group computer in LISP. 
  28. ^ Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. In this history of the evolution of Lisp, we have seen that Lisp seems to have a more elaborate and complex history than languages with wider usage. It would seem that almost every little research group has its own version of Lisp and there would appear to be as many Lisps as variations on language concepts. It is natural to ask what is so special or different about Lisp that explains it.
    There are six basic reasons: ……
    Its theoretical foundations. Lisp was founded on the footing of recursive function theory and the theory of computability. The work on Scheme aligned it with Church's lambda calculus and denotational semantics. Its purest form is useful for mathematical reasoning and proof. ……
    Its expressiveness. Lisp has proved itself concerned more with expressiveness than anything else. ……
    Its malleability. It is easy with Lisp to experiment with new language features, because it is possible to extend Lisp in such a way that the extensions are indistinguishable to users from the base language. Primarily this is accomplished through the use of macros, which have been part of Lisp since 1963 [Hart 1963]. ……
    Its interactive and incremental nature. It is easy to explore the solutions to programming problems in Lisp, because it is easy to implement part of a solution, test it, modify it, change design, and debug the changes. ……
    Its operating system facilities. Many Lisp implementations provide facilities reminiscent of operating systems: a command processor, an automatic storage management facility, file management, display (windows, graphics, mouse) facilities, multitasking, a compiler, an incremental (re)linker/loader, a symbolic debugger, performance monitoring, and sometimes multiprocessing. ……
    Its people. Of course, languages do not diversify themselves; people diversify languages. ……Lisp is the language of artificial intelligence, among other things. …… Another attraction is that Lisp is a language of experts, which for our purposes means that Lisp is not a language designed for inexpert programmers to code robust reliable software.
     
  29. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-10-25]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). 
    To define these functions, we use the pseudo-function define. …… A pseudo-function is a function that is executed for its effect on the system in core memory, as well as for its value. define causes these functions to be defined and available within the system. Its value is a list of the functions defined ……. ……
    define[x]    :    EXPR    pseudo-function
    The argument of define, x, is a list of pairs
      ((u1 v1) (u2 v2) … (un vn))
    where each u is a name and each v is a λ-expression for a function. For each pair, define puts an EXPR on the property list for u pointing to v. The function of define puts things on at the front of the property list. The value of define is the list of u's.
      define[x] = deflist[x,EXPR]
    deflist[x,ind]    :    EXPR    pseudo-function
    The function deflist is a more general defining function. Its first argument is a list of pairs as for define. Its second argument is the indicator that is to be used. After deflist has been executed with (ui vi) among its first argument, the property list of ui will begin:
     | .----.---. .---.---. .---.---. uᵢ `->| -1 | |->|IND| |->| | |--> - - - `----'---' `---'---' `---'---' | V vᵢ 

    If deflist or define is used twice on the same object with the same indicator, the old value will be replaced by the new one.”

  30. ^ 30.0 30.1 Kent M. Pitman英语Kent Pitman. . 1983, 2007 [2021-10-26]. (原始内容存档于2022-03-28).
    DEFUN    Special Form    (DEFUN namespec . definitionspec)
    DEFUN offers a way of associating a functional definition with a symbol. …… DEFUN can be used to define both normal functions and special forms (fexprs and macros). ……
      ;; Normal expr or lexpr function definitions
      (DEFUN name bvl . body)

    ……
    If name is a symbol and bvl is a list of symbols which is free of &keywords (to be described below), the definition is an expr or lexpr definition. In Maclisp, this would be essentially equivalent to writing
      (DEFPROP name (LAMBDA bvl . body) EXPR).
    …… Note also that the keyword EXPR is used for both expr and lexpr definitions. The only distinction between expr and lexpr definitions is whether the bvl is a symbol or a list, but they are specified in the same way and looked up from the same property. ……
    A fexpr英语fexpr is a function for which the formal parameters are not evaluated. The form of a fexpr definition is:
      (DEFUN name FEXPR (sym) . body).
    The lambda expression which describes a fexpr should expect to receive exactly one argument which will be the list of (unevaluated) arguments given in the call to the fexpr, so usually there is only one bound variable (sym) in the bound variable list. ……
    DEFUN can also be used to instantiate a MACRO definition. …… The syntax for a macro definition is
      (DEFUN name MACRO (sym) . body),
    where sym will become bound to the whole macro form to be expanded (including the name). Note that this argument convention is different than fexprs, which only receive the cdr of the call form. ……
    DEFUN was introduced into Maclisp in March, 1969. Although now it is recognized as the standard function defining form because it shields the user from the implementational details of how the function is defined ……. ……
    DEFPROP Function (DEFPROP sym val indicator)
    Gives sym a property called indicator with value val. The arguments are not evaluated. DEFPROP should not be used imbedded in other expressions. It is intended to occur at toplevel to assign properties that are set up once and never changed. In other places, use PUTPROP with three quoted arguments.
     
  31. ^ Gerald J. Sussman, Guy L. Steele Jr..   Scheme: An Interpreter for Extended Lambda Calculus. 维基文库. 1975 (英文). DEFINE - This is analogous to the MacLISP DEFUN primitive (but note that the LAMBDA must appear explicitly!). It is used for defining a function in the "global environment" permanently, as opposed to LABELS (see below), which is used for temporary definitions in a local environment. DEFINE takes a name and a lambda expression; it closes the lambda expression in the global environment and stores the closure in the LISP value cell of the name (which is a LISP atom). 
    Gerald J. Sussman, Guy L. Steele Jr. . 1978 [2021-10-26]. (原始内容存档于2022-04-06). Atoms which are not atomic symbols (identifiers) evaluate to themselves. Typical examples of such atoms are numbers, arrays, and strings (character arrays). Symbols are treated as identifiers or variables. They may be lexically bound by lambda-expressions. There is a global environment containing values initially have as their values primitive operations such as, for example, CAR, CONS, and PLUS. SCHEME differs from most LISP systems in that the atom CAR is not itself an operation (in the sense of being an invocable object, e.g. a valid first argument to APPLY), but only has one as a value when considered as an identifier. 
  32. ^ Richard P. Gabriel英语Richard P. Gabriel; Kent M. Pitman英语Kent M. Pitman. . Lisp and Symbolic Computation. June 1988, 1 (1): 81–101 [2021-11-01]. S2CID 26716515. doi:10.1007/bf01806178. (原始内容存档于2006-11-13). In 1981 the emerging Common Lisp community turned to Scheme for some of its motivation and inspiration [Steele 1984]. Adopting lexical scoping proved one of the most important decisions the Common Lisp group ever made.
    One aspect of Scheme that was not adopted, however, was a single namespace for functions and values, along with uniform evaluation rules for expressions in function and argument positions within the language. ……
    In this paper, we shall refer to two abstract dialects of Lisp called Lisp1 and Lisp2.
    Lisp1 has a single namespace that serves a dual role as the function namespace and value namespace; that is, its function namespace and value namespace are not distinct. In Lisp1, the functional position of a form and the argument positions of forms are evaluated according to the same rules. Scheme [Rees 1986] and the language being designed by the EuLisp group [Padget 1986] are Lisp1 dialects.
    Lisp2 has distinct function and value namespaces. In Lisp2, the rules for evaluation in the functional position of a form are distinct from those for evaluation in the argument positions of the form. Common Lisp is a Lisp2 dialect. ……
    Most Lisp dialects adopted a two-namespace approach to the naming problem. To some extent this is because most dialects followed Lisp 1.5 [McCarthy 1965] or dialects derived from Lisp 1.5.
    Lisp 1.5 broke symbols into values and functions; values were stored on an association list英语association list, and function on the property lists of symbols. Compiled and interpreted code worked in different ways. In the interpreter, the association list was where all bindings were kept. When an identifier was encountered (an 'atomic symbol' in Lisp 1.5 terminology), it was taken as a variable to be evaluated for its value. First the APVAL part of the symbol was interrogated — an APVAL was "A Permanent, system-defined VALue" stored in a specific place in the symbol. Second, the association list was searched. Finally, if no binding was found, an error was signaled.
    When a combination was encountered, the function position was evaluated differently from other positions. First, the symbol was interrogated to see whether there was a function definition associated with it; then the association list was searched.
    Here we can see two namespaces at work, though nonsymbol variables were treated somewhat uniformly (Lisp 1.5 did not have lexical variables in interpreted code): when there were no function definitions associated with a symbol, there was one namespace, which was explicitly represented by the association list.
    Compiled code worked a slightly different way, and from its internals we can see where the two namespaces came about in descendants of Lisp 1.5.
    The Lisp 1.5 compiler supported 'common' and 'special' variables. A common variable enabled compiled and interpreted code to communicate with each other. A common variable was bound on an explicit association list; to evaluate such a variable, a call to EVAL was emitted to determine the value. A special variable was the compiler's modeling of free variables and closely matched what is now called 'shallow binding.' Ordinary variables compiled into what we have termed lexical variables.
    Thus, we see all of the components of the two-namespace world in Lisp 1.5, along with some of the components of the one-namespace world.
    It seems that the designers of Lisp 1.5 thought of function names as being different from variable names — the Lisp 1.5 interpreter looked at the property list of the named atomic symbol first, and so it can be argued that a function was considered a property of a symbol. The designers used the terminology that a symbol "stands for" a function while a variable "refers" to a value.
    Lisp for the PDP-6 at MIT adopted the style of the Lisp 1.5 special variables for dynamic binding in both compiled and interpreted code, thereby eliminated common variables. Compilers were still written that were to try to interpret special variables as lexical variables in as many places as possible. The value of a symbol was stored in the value cell of the symbol, and the function remained on the property list as it did in Lisp 1.5.
    MacLisp [Pitman 1983] is a direct descendant of the PDP-6 Lisp and is a Lisp2 dialect. MacLisp uses a sophisticated form of link table, which is made possible by the separation of namespaces. In particular, function-defining functions have controlled access into the places where functions are stored so that the link tables can be correctly maintained. ……
    Common Lisp was the result of a compromise between a number of dialects of Lisp, most of them descendants of MacLisp, all of them Lisp2s. ……
    A free variable in Common Lisp is currently taken to be a dynamic rather than a lexical reference because there is no global lexical environment in Common Lisp. In this code
      (DEFUN PLUS (X Y) (+ X Y))
      (DEFUN SOMEWHAT-MORE-THAN (X) (PLUS X *SOMEWHAT*))
    The reference to *SOMEWHAT* is special (dynamic). On the surface, in Lisp1 the reference to PLUS is free also, and thus it is special (dynamic).
    When a variable is declared special, a free reference to it is to the most recent dynamically bound value for it; all bindings of it become special (dynamic) bindings. When a variable is declared constant, free references to it are to its permanent constant value, and compilers are free to fold that constant into the code they emit.
    We introduce the concept of global variables; when a variable is global, free references to it are to the value cell of the symbol named by the variable, and all bindings of it are still lexical.
    To avoid a compiler warning for free use of a variable like *SOMEWHAT*, the variable is declared SPECIAL. In order to have compilers for Lisp1 not to warn about the free use of PLUS, it would be unfortunate to have to declare it SPECIAL.
    As noted, in Common Lisp the default for free variable references is SPECIAL; that is, a free variable reference is taken to be a special variable reference. If the default in Lisp1 were that free variable references were global (lexical), then it would make sense for a compiler not to warn about such free variable references.
     
  33. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-10-25]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). The over-all design of the LISP Programming System is the work of John McCarthy and is based on his paper "Recursive Functions of Symbolic Expressions and Their Computation by Machine" which was published in Communications of the ACM, April 1960.
    This manual was written by Michael I. Levin.
    The interpreter was programmed by Stephen B. Russell and Daniel J . Edwards.
    The print and read programs were written by John McCarthy, Klim Maling, Daniel J. Edwards, and Paul W, Abrahams.
    The garbage collector and arithmetic features Were written by Daniel J. Edwards.
    The compiler and assembler were written by Timothy P. Hart and Michael I. Levin.
    An earlier compiler was written by Robert Brayton.
    The "LISP 1 Programmer's Manual," March 1, 1960, was written by Phyllis A. Fox. Additional programs and suggestions were contributed by the following members of the Artificial Intelligence Group of the Research Laboratory of Electronics: Marvin L. Minsky, Bertram Raphael, Louis Hodes, David M. R. Park, David C. Luckham, Daniel G. Bobrow, James R. Slagle, and Nathaniel Rochester.
     
  34. ^ Lynn H. Quam. (PDF). 1969 [2021-12-29]. (原始内容 (PDF)存档于2022-03-03). The STANFORD A.I. LISP 1.6 System was originally an adaptation of one developed by the Artificial Intelligence Project a t M.I.T. Since 1966, that system has been largely rewritten by John Allen and the author. 
    Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. At Stanford in the 1960s, an early version of MacLisp was adapted for their PDP-6; this Lisp was called Lisp 1.6 [Quam 1972]. The early adaptation was rewritten by John Allen and Lynn Quam; later compiler improvements were made by Whit Diffie. Lisp 1.6 disappeared during the mid-1970s, one of the last remnants of the Lisp 1.5 era. 
  35. ^ . 1977 [2021-10-10]. (原始内容存档于2021-10-10). 
  36. ^ . March 3, 1979 [2021-10-29]. (原始内容存档于2022-03-28). 
    Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. By 1964 a version of Lisp 1.5 was running in the Electrical Engineering Department at MIT on an IBM 7094 computer, running the Compatible Time Sharing System (CTSS). This Lisp and Basic PDP-1 Lisp were the main influences on the PDP-6 Lisp [PDP-6 Lisp 1967] implemented by DEC and some members of MIT's Tech Model Railroad Club in the spring of 1964. This Lisp was the first program written on the PDP-6. Also, this Lisp was the ancestor of MacLisp, the Lisp written to run under the Incompatible Timesharing System (ITS) [Eastlake 1968, 1972] at MIT on the PDP-6 and later on the PDP-10. ……
    In 1965, virtually all of the Lisps in existence were identical or differed only in trivial ways. After 1965 - or more precisely, after MacLisp and BBN-Lisp diverged from each other - there came a plethora of Lisp dialects. ……
    MacLisp was the primary Lisp dialect at the MIT AI Lab from the late 1960s until the early 1980s. Other important Lisp work at the Lab during this period included Lisp-Machine Lisp (later named Zetalisp) and Scheme. MacLisp is usually identified with the PDP-10 computer, but MacLisp also ran on another machine, the Honeywell 6180, under the Multics operating system [Organick 1972].
     
  37. ^ 37.0 37.1 37.2 37.3 John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-10-25]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). The Artificial Intelligence Project at Stanford University has produced a version of LISP 1.5 to be distributed by SHARE. In the middle of February 1965 the system is complete and is available from Stanford. The system should be available from SHARE by the end of March 1965. ……
    Evalquote is available to the programmer as a LISP function - thus, one may now write "(EVALQUOTE APPEND ((A)(B C D)))", rather than "(EVAL (QUOTE (APPEND (A)(B C D))) NIL)", should one desire to do so.
     
    Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. A key difference between MacLisp and Interlisp was the approach to syntax. MacLisp favored the pure list style, using EVAL as the top level. Interlisp, along with Lisp 1.5, used EVALQUOTE.
    To concatenate the lists (BOAT AIRPLANE SKATEBOARD) and (CAR TRUCK) in MacLisp, one would type this expression to EVAL:
      (APPEND (QUOTE (BOAT AIRPLANE SKATEBOARD)) (QUOTE (CAR TRUCK)))
    or, using the syntactic abbreviation 'x for (quote x),
      (APPEND '(BOAT AIRPLANE SKATEBOARD) '(CAR TRUCK))
    The result would of course be (BOAT AIRPLANE SKATEBOARD CAR TRUCK).
    In Lisp 1.5, one would type an expression (actually two expressions) like this to EVALQUOTE:
      APPEND((BOAT AIRPLANE SKATEBOARD) (CAR TRUCK))
    The first expression denotes a function, and the second is a list of arguments. The "quote" in the name EVALQUOTE signifies the "implicit quoting of the arguments" to the function applied. MacLisp forked off and used EVAL exclusively as a top level interface. BBN-Lisp (and thus Interlisp) accommodated both: if the first input line contained a complete form and at least one character of a second form, then BBN-Lisp finished reading the second form and used the EVALQUOTE interface for that interaction; otherwise it read exactly one form and used the EVAL interface for that interaction.
    The phrase "quoting arguments" actually is misleading and imprecise. It refers to the actions of a hypothetical preprocessor that transforms the input from a form like
      APPEND((BOAT AIRPLANE SKATEBOARD) (CAR TRUCK))
    to one like
      (APPEND (QUOTE (BOAT AIRPLANE SKATEBOARD)) (QUOTE (CAR TRUCK)))
    before evaluation is performed. A similar confusion carried over into the description of the so-called FEXPR or"special form." In some texts on Lisp one will find descriptions of special forms that speak of a special form "quoting its arguments," when in fact a special form has a special rule for determining its meaning and that rule involves not evaluating some forms [Pitman 1980].
    McCarthy [McCarthy 1981] noted that the original Lisp interpreter was regarded as a universal Turing machine: It could perform any computation given a set of instructions (a function) and the initial input on its tape (arguments). Thus it was intended that
      APPEND((BOAT AIRPLANE SKATEBOARD) (CAR TRUCK))
    be regarded not as a syntactically mutated version of
      (APPEND (QUOTE (BOAT AIRPLANE SKATEBOARD)) (QUOTE (CAR TRUCK)))
    but as a function and (separately) a literal list of arguments. In hindsight we see that the EVALQUOTE top level might better have been called the APPLY top level, making it pleasantly symmetrical to the EVAL top level; the BBN-Lisp documentation brought out this symmetry explicitly. Indeed, EVALQUOTE would have been identical to the function APPLY in Lisp 1.5 if not for these two differences: (a) in Lisp 1.5, APPLY took a third argument, an environment (regarded nowadays as something of a mistake that resulted in dynamic binding rather than the lexical scoping needed for a faithful reflection of the lambda calculus); and (b) "EVALQUOTE is capable of handling special forms as a sort of exception" [McCarthy 1962]. Nowadays such an exception is referred to as a kluge [Raymond 1991]. (Note, however, that MacLisp's APPLY function supported this same kluge.)
     
  38. ^ Teitelman, Warren. (PDF). 1974 [2021-10-29]. (原始内容 (PDF)存档于2022-03-03). 
    Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. In 1963, L. Peter Deutsch (at that time a high school student) implemented a Lisp similar to Lisp 1.5 on the PDP-1 at Bolt Beranek and Newman (BBN) [Deutsch 1964]. This Lisp was called Basic PDP-1 Lisp. ……
    At BBN, a successor to Basic PDP-1 Lisp was implemented on the PDP-1 and an upward-compatible version, patterned after Lisp 1.5 on the MIT CTSS system, was implemented on the Scientific Data Systems 940 (SDS 940) by Daniel Bobrow and D. L. Murphy. A further upward-compatible version was written for the PDP-10 by Alice Hartley and Murphy, and this Lisp was called BBN-Lisp [Teitelman 1971]. In 1973, not long after the time that SDS was acquired by Xerox and renamed Xerox Data Systems, the maintenance of BBN-Lisp was shared by BBN and Xerox Palo Alto Research Center and the name of the Lisp was changed to Interlisp [Teitelman 1974]. ……
    Interlisp (and BBN-Lisp before it) introduced many radical ideas into Lisp programming style and methodology. The most visible of these ideas are embodied in programming tools, such as the spelling corrector, the file package, DWIM, CLISP, the structure editor, and MASTERSCOPE.
    The origin of these ideas can be found in Warren Teitelman's Ph.D. dissertation on man-computer symbiosis [Teitelman 1966]. In particular, it contains the roots of structure editing (as opposed to "text" or "tape" editing [Rudloe 1962]), breakpointing, advice, and CLISP. ……
    CLISP (Conversational LISP) was a mixed ALGOL-like and English-like syntax embedded within normal Interlisp syntax. Here is a valid definition of FACTORIAL written in lnterlisp CLISP syntax:
      DEFINEQ((FACTORIAL
        (LAMBDA (N) (IF N=0 THEN 1 ELSE N*(FACTORIAL N-I)))))
     
  39. ^ . cs.cmu.edu. [2021-10-26]. (原始内容存档于2022-03-31). 
  40. ^ (PDF). [2021-10-24]. (原始内容 (PDF)存档于2017-10-01). 
  41. ^ Gerald J. Sussman, Guy L. Steele Jr. . 1975 [2021-10-27]. (原始内容存档于2022-04-17). Inspired by ACTORS [Greif and Hewitt][Smith and Hewitt], we have implemented an interpreter for a LISP-like language, SCHEME, based on the lambda calculus [Church], but extended for side effects, multiprocessing, and process synchronization. The purpose of this implementation is tutorial. We wish to:
    ⑴ alleviate the confusion caused by Micro-PLANNER英语Planner (programming language), CONNIVER, etc. by clarifying the embedding of non-recursive control structures in a recursive host language like LISP.
    ⑵ explain how to use these control structures, independent of such issues as pattern matching and data base manipulation.
    ⑶ have a simple concrete experimental domain for certain issues of programming semantics and style.
     
  42. ^ 42.0 42.1 Guy L. Steele, Jr., Scott Fahlman英语Scott Fahlman, Richard P. Gabriel英语Richard P. Gabriel, David A. Moon英语David A. Moon, Daniel Weinreb英语Daniel Weinreb. Common Lisp the Language 1st edition. 1984. ISBN 0-932376-41-X. 
  43. ^ Steele, Guy L., Jr. . Common Lisp the Language 2nd edition. 1990 [2021-10-24]. ISBN 0-13-152414-3. (原始内容存档于2021-03-08). 
  44. ^ Kantrowitz, Mark; Margolin, Barry. . FAQ: Lisp Frequently Asked Questions 2/7. 20 February 1996 [2021-10-24]. (原始内容存档于2021-03-08). 
  45. ^ . Iso.org. 2007-10-01 [2013-11-15]. (原始内容存档于2016-07-30). 
  46. ^ . Iso.org. 2013-10-30 [2013-11-15]. (原始内容存档于2016-07-30). 
  47. ^ 47.0 47.1 . IEEE 1178-1990 - IEEE Standard for the Scheme Programming Language. [27 August 2019]. (原始内容存档于2021-03-04). 
  48. ^ . [2021-10-24]. (原始内容存档于2021-03-05). 
  49. ^ . [2006-10-13]. (原始内容存档于2006-10-04). 
  50. ^ . Faqs.org. [2013-11-15]. (原始内容存档于2013-06-03). 
  51. ^ Common Lisp Implementations. 
  52. ^ . schemers.org. 1998 [2021-10-24]. (原始内容存档于2007-01-05). 
  53. ^ The Revised6 Report on the Algorithmic Language Scheme. 2007 [2021-11-04]. (原始内容存档于2013-06-25). 
  54. ^ R7RS-small language, final draft (PDF). [2022-09-06]. 
  55. ^ Implementations support all or part of R7RS-small. 
  56. ^ . cemerick.com. March 24, 2009 [November 10, 2013]. (原始内容存档于September 17, 2010). 
  57. ^ Broder, Evan. . mitadmissions.org. January 8, 2008 [November 10, 2013]. (原始内容存档于2018-08-21). 
  58. ^ Axel - Haskell + Lisp. 
  59. ^ a specification for Bel (页面存档备份,存于互联网档案馆), "a new dialect of Lisp."
  60. ^ Chapter 1.1.2, History, ANSI CL Standard
  61. ^ [1] (页面存档备份,存于互联网档案馆) Clasp is a Common Lisp implementation that interoperates with C++ and uses LLVM for just-in-time compilation (JIT) to native code.
  62. ^ [2] (页面存档备份,存于互联网档案馆) "Armed Bear Common Lisp (ABCL) is a full implementation of the Common Lisp language featuring both an interpreter and a compiler, running in the JVM"
  63. ^ [3] 互联网档案馆的,存档日期2018-06-22. Common Lisp Implementations: A Survey
  64. ^ [4] (页面存档备份,存于互联网档案馆) Comparison of actively developed Common Lisp implementations
  65. ^ Gerald J. Sussman, Guy L. Steele Jr. . 1998 [2021-10-28]. (原始内容存档于2022-04-06). Sussman had just been studying Algol. He suggested starting with a lexically scoped dialect of Lisp, because that seemed necessary to model the way names could refer to acquaintances in PLASMA. Lexical scoping would allow actors and functions to be created by almost identical mechanisms. Evaluating a form beginning with the word lambda would capture the current variable-lookup environment and create a closure; evaluating a form beginning with the word alpha would also capture the current environment but create an actor. Message passing could be expressed syntactically in the same way as function invocation. The difference between an actor and a function would be detected in the part of the interpreter traditionally known as apply. A function would return a value, but an actor would never return; instead, it would typically invoke a continuation, another actor that it knew about. Our interpreter also provided the necessary primitives for implementing the internal behavior of primitive actors, such as an addition operator that could accept two numbers and a continuation actor. ……
    …… This led us to three important ideas:
    • First, we realized that all the patterns of control structure that Hewitt had described in terms of actors could equally well be described by the λ-calculus. ……
    • Second, we realized that the λ-calculus — a small, simple formalism — could serve as the core of a powerful and expressive programming language. (Lisp had adopted the λ-notation for functions but had failed to support the appropriate behavior for free variables. The original theoretical core of Lisp was recursion equations, not the λ-calculus.) ……
    • Third, we realized that in our quest for the “ultimate AI language” we had come full circle. As the MIT school had struggled to find more and more powerful ways to express and manipulate control structure to support heuristic search, we had progressed from Lisp to CONVERT to Planner to Conniver to PLASMA to a simple variation of Lisp!
     
  66. ^ An In-Depth Look at Clojure Collections (页面存档备份,存于互联网档案馆), Retrieved 2012-06-24
  67. ^ . [27 August 2019]. (原始内容存档于2016-01-04). Clojure is a Lisp not constrained by backwards compatibility 
  68. ^ Script-fu In GIMP 2.4 (页面存档备份,存于互联网档案馆), Retrieved 2009-10-29
  69. ^ librep (页面存档备份,存于互联网档案馆) at Sawfish Wikia, retrieved 2009-10-29
  70. ^ . [2006-10-13]. (原始内容存档于2021-04-18). 
  71. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-10-25]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). Special Forms - Normally, eval evaluates the arguments of a function before applying the function itself. Thus if eval is given (CONS X Y), it will evaluate X and Y, and then cons them. But if eval is given (QUOTE X), X should not be evaluated. QUOTE is a special form that prevents its argument from being evaluated.
    A special form differs from a function in two ways. Its arguments are not evaluated before the special form sees them. COND, for example, has a very special way of evaluating its arguments by using evcon. The second way which special forms differ from functions is that they may have an indefinite number of arguments. Special forms have indicators on their property lists called FEXPR and FSUBR for LISP-defined forms and machine language coded forms, respectively.
     
  72. ^ 72.0 72.1 Guy L.Steele, Jr., Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. ACM: 231–270. 1993. The use of SETF throughout Common Lisp - a later dialect of Lisp and the most popular - can be traced through Symbolics Zetalisp and MacLisp to the influence of MIT Lisp-Machine Lisp and then back through Greenblatt's proposal to Peter Deutsch and thence to Alan Kay.
    The uniform treatment of access - reading and writing of state - has made Common Lisp more uniform that it might otherwise be. It is no longer necessary to remember both a reader function (such as CAR) and also a separate writer or update function (such as RPLACA), nor to remember the order of arguments. (For RPLACA, which comes first, the dotted pair or the new value for its car?) If the general form of a read operation is (f…), then the form of the write is (setf (f…) newvalue), and that is all the programmer needs to know about reading and writing data.
     
  73. ^ Guy L. Steele. Common Lisp the Language, 2nd Edition. 1990. ISBN 1-55558-041-6. 
    In describing various features of the Common Lisp language, the notions of scope and extent are frequently useful. These notions arise when some object or construct must be referred to from some distant part of a program. Scope refers to the spatial or textual region of the program within which references may occur. Extent refers to the interval of time during which references may occur. ……
    There are a few kinds of scope and extent that are particularly useful in describing Common Lisp:
    • Lexical scope. Here references to the established entity can occur only within certain program portions that are lexically (that is, textually) contained within the establishing construct. Typically the construct will have a part designated the body, and the scope of all entities established will be (or include) the body.
      Example: the names of parameters to a function normally are lexically scoped.
    • Indefinite scope. References may occur anywhere, in any program.
    • Dynamic extent. References may occur at any time in the interval between establishment of the entity and the explicit disestablishment of the entity. As a rule, the entity is disestablished when execution of the establishing construct completes or is otherwise terminated. Therefore entities with dynamic extent obey a stack-like discipline, paralleling the nested executions of their establishing constructs.
      Example: the with-open-file construct opens a connection to a file and creates a stream object to represent the connection. The stream object has indefinite extent, but the connection to the open file has dynamic extent: when control exits the with-open-file construct, either normally or abnormally, the stream is automatically closed.
      Example: the binding of a “special” variable has dynamic extent.
    • Indefinite extent. The entity continues to exist as long as the possibility of reference remains. (An implementation is free to destroy the entity if it can prove that reference to it is no longer possible. Garbage collection strategies implicitly employ such proofs.)
      Example: most Common Lisp data objects have indefinite extent.
      Example: the bindings of lexically scoped parameters of a function have indefinite extent. (By contrast, in Algol the bindings of lexically scoped parameters of a procedure have dynamic extent.) The function definition
      (defun compose (f g)
        #'(lambda (x)
            (funcall f (funcall g x))))
      when given two arguments, immediately returns a function as its value. The parameter bindings for f and g do not disappear because the returned function, when called, could still refer to those bindings. Therefore
      (funcall (compose #'sqrt #'abs) -9.0)
      produces the value 3.0. (An analogous procedure would not necessarily work correctly in typical Algol implementations or, for that matter, in most Lisp dialects.)
    In addition to the above terms, it is convenient to define dynamic scope to mean indefinite scope and dynamic extent. Thus we speak of “special” variables as having dynamic scope, or being dynamically scoped, because they have indefinite scope and dynamic extent: a special variable can be referred to anywhere as long as its binding is currently in effect.
    The term “dynamic scope” is a misnomer. Nevertheless it is both traditional and useful. ”
  74. ^ John McCarthy, Paul W. Abrahams, Daniel J. Edwards, Timothy P. Hart, Michael I. Levin. (PDF) 2nd. MIT Press. 1985 [1962] [2021-10-25]. ISBN 0-262-13011-4. (原始内容 (PDF)存档于2021-03-02). The variables in a lambda expression are dummy or bound variables because systematically changing them does not alter the meaning of the expression. Thus λ[[u;v];v2+u] means the same thing as λ[[x;y];y2+x].
    We shall sometimes use expressions in which a variable is not bound by a lambda. For example, in the function of two variables λ[[x;y];xn+yn] the variable n is not bound. This is called a free variable. It may be regarded as a parameter. Unless n has been given a value before trying to compute with this function, the value of the function must be undefined. ……
    When the compiler is called upon to compile a function, it looks for an EXPR or FEXPR on the property list of the function name. The compiler then translates this S-expression into an S-expression that represents a subroutine in the LISP Assembly Language (LAP). LAP then proceeds to assemble this program into binary program space. Thus an EXPR, or an FEXPR, has been changed to a SUBR or an FSUBR, respectively. ……
    Free variables in compiled functions must be declared before the function is compiled. ……
    A variable is bound in a particular function when it occurs in a list of bound variables following the word LAMBDA or PROG. Any variable that is not bound is free. ……
    When a variable is used free, it must have been bound by a higher level function. If a program is being run interpretively, and a free variable is used without having bee bound on a higher level, error diagnostic *A 8* will occur.
    If the program is being run complied, the diagnostic may not occur, and the variable may have value NIL.
    There are three types of variables in compiled functions: ordinary variables, SPECIAL variables, and COMMON variables. SPECIAL and COMMON variables must be declared before compiling. Any variable that is not declared will be considered an ordinary variable.
    When functions are translated into subroutines, the concept of a variable is translated into a location where an argument is stored. If the variable is an ordinary one, then a storage location for it is set up on the push-down list. Other functions cannot find this private cell, making it impossible to use it as a free variable.
    SPECIAL variables have the indicator SPECIAL on their property lists Following the indicator there is a pointer to a fixed cell. When this variable is bound, the old value is saved on the push-down list, and the current value is stored in the SPECLAL cell. When it is no longer bound, the old value must be restored. When a function uses this variable free, then the quantity in the SPECIAL cell is picked up.
    SPECIAL variables are declared by using the pseudo-function special[a], where a is a list of variable names. ……
    SPECIAL variables are inexpensive and will allow free communication among compiled functions. They do not increase run time significantly. SPECIAL variables cannot be communicated between the interpreter and compiled functions.
    COMMON variables have the flag COMMON on their property lists; however, this is only used to inform the compiler that they are COMMON, and is not needed at run time. COMMON variables are bound on an a-list by the compiled functions. When they are to be evaluated, eval is given this a-list. This happens at run time.
    The use of COMMON variables will slow down any compiled function using them. However, they do provide complete communication between interpreted and compiled functions.
    COMMON variables are declared by common[a], where a is a list of variable names. ……
    LISP is designed in such a way that all functions for which the possibility of recursion can exist are in fact recursive. This requires that all temporary stored results related to the computation that is in progress be set aside when a piece of coding is to be used recursively, and that they be later restored. This is done automatically and need not be programmed explicitly.
    All saving of temporary results in LISP is performed on a linear block of storage called the push-down list. Each set of stored data that is moved onto the push-down list is in a block labeled with its size and the name of the subroutine from which it came. Since it is in the nature of recursion that the first block to be saved is always the last block to be restored, it is possible to keep the push-down list compact.
     
    Joel Moses英语Joel Moses. The Function of FUNCTION in LISP, or Why the FUNARG Problem Should Be Called the Environment Problem (pdf). June 1970 [2009-10-27]. AI Memo 199. (原始内容于2010-05-23). There are several ways in which to maintain the values of free variables (and, thus the computational environment) in order to handle cases like the one above. All of the techniques used involve some increase in time. One approach makes it easy to access the value of a free variable is local. This approach is favored in recent implementations of LISP. We shall call it the "shallow access" approach.
    Another approach is to make it relatively easy to enter and leave a block in which a free variable is bound, but relatively expensive to access a free variable. This approach is used in the classical "alist" implementation of LISP. Several Algol systems have opted for a similar approach. We shall call this the "deep access" approach. Both of these approaches allow one to modify the value of the variable as well as access it. The access time is approximately the same as modification time in both approaches.
    Let us consider the "shallow access" approach first. By "shallow access" we mean that the value of a free variable can be obtained in a single fetch from memory. Since the current value may be stored in a difficult-to-determine location up in the stack, a special cell for its current value is used. In many recent LISP implementations this special values cell is stored as a property of the atom structure, and is unique to the free variable. In order to maintain the proper value in the special cell, extra work must be done every time a function or a block is entered in which the variable is an argument or is local. On entering such a function or block one usually saves the old value which is in the special cell on the stack alone with sufficient information to allow one to know from where the stack value came. On leaving such a function or block one must remember to store the value saved in the stack in the special cell.
    The "deep access" approach forces one to search upward in the stack for the most recent value of the free variable. Such a search may be quite deep and slow if the free variable was bond vary far up in the stack. However, this approach has the advantage of avoiding the need for an extra special value cell. In addition, we shall see later that this approach sometimes allows one to use free variables with greater ease and flexibility than the "shallow access" approach. ……
    Certain LISP systems use "deep access" in interpreted functions and "shallow access" in compiled functions. if free variables in compiled functions are declared to be COMMON, their values will be stored on the "alist". In this manner one can solve the environment problem. The cost is a very slow interpreter and "deep access" to free variables.
     
  75. ^ Gerald J. Sussman, Guy L. Steele Jr..   Scheme: An Interpreter for Extended Lambda Calculus. 维基文库. 1975 (英文). There are several important consequences of closing every lambda expression in the environment from which it is passed (i.e., in its "lexical" or "static" environment).
    First, the axioms of lambda calculus are automatically preserved. Thus, referential transparency is enforced. This in turn implies that there are no "fluid" variable bindings (as there are in standard stack implementations of LISP such as MacLISP).
    Second, the upward funarg problem英语funarg problem [Moses] requires that the environment structure be potentially tree-like.
    Finally, the environment at any point in a computation can never be deeper than the lexical depth of the expression being evaluated at that time; i.e., the environment contains bindings only for variables bound in lambdas lexically surrounding the expression being evaluated. This is true even if recursive functions are involved. ……Furthermore, it is not even necessary to scan the environment for the variable, since its value must be in a known position relative to the top of the environment structure; this position can be computed by a compiler at compile time on the basis of lexical scope.
     
  76. ^ Guy L. Steele. Common Lisp the Language, 2nd Edition. 1990. ISBN 1-55558-041-6. Symbols are used as names of variables in Common Lisp programs. When a symbol is evaluated as a form, the value of the variable it names is produced. For example, after doing (setq items 3), which assigns the value 3 to the variable named items, then items3. Variables can be assigned to, as by setq, or bound, as by let. Any program construct that binds a variable effectively saves the old value of the variable and causes it to have a new value, and on exit from the construct the old value is reinstated.
    There are actually two kinds of variables in Common Lisp, called lexical (or static) variables and special (or dynamic) variables. At any given time either or both kinds of variable with the same name may have a current value. Which of the two kinds of variable is referred to when a symbol is evaluated depends on the context of the evaluation. The general rule is that if the symbol occurs textually within a program construct that creates a binding for a variable of the same name, then the reference is to the variable specified by the binding; if no such program construct textually contains the reference, then it is taken to refer to the special variable of that name.
    The distinction between the two kinds of variable is one of scope and extent. A lexically bound variable can be referred to only by forms occurring at any place textually within the program construct that binds the variable. A dynamically bound (special) variable can be referred to at any time from the time the binding is made until the time evaluation of the construct that binds the variable terminates. Therefore lexical binding of variables imposes a spatial limitation on occurrences of references (but no temporal limitation, for the binding continues to exist as long as the possibility of reference remains). Conversely, dynamic binding of variables imposes a temporal limitation on occurrences of references (but no spatial limitation). For more information on scope and extent, see chapter 3.
    The value a special variable has when there are currently no bindings of that variable is called the global value of the (special) variable. A global value can be given to a variable only by assignment, because a value given by binding is by definition not global.
    It is possible for a special variable to have no value at all, in which case it is said to be unbound. By default, every global variable is unbound unless and until explicitly assigned a value, except for those global variables defined in this book or by the implementation already to have values when the Lisp system is first started. It is also possible to establish a binding of a special variable and then cause that binding to be valueless by using the function makunbound. In this situation the variable is also said to be “unbound,” although this is a misnomer; precisely speaking, it is bound but valueless. It is an error to refer to a variable that is unbound.
     
    Macro DEFPARAMETER, DEFVAR. Common Lisp HyperSpec. It is customary to name dynamic variables with an asterisk at the beginning and end of the name. e.g., *foo* is a good name for a dynamic variable, but not for a lexical variable; foo is a good name for a lexical variable, but not for a dynamic variable. This naming convention is observed for all defined names in Common Lisp; however, neither conforming programs nor conforming implementations are obliged to adhere to this convention. 
  77. ^ Alexander Burger. . [2021-10-29]. (原始内容存档于2017-08-06). Why do you use dynamic variable binding? Dynamic binding is very powerful, because there is only one single, dynamically changing environment active all the time. This makes it possible (e.g. for program snippets, interspersed with application data and/or passed over the network) to access the whole application context, freely, yet in a dynamically controlled manner. And (shallow) dynamic binding is the fastest method for a Lisp interpreter.
    Lexical binding is more limited by definition, because each environment is deliberately restricted to the visible (textual) static scope within its establishing form. Therefore, most Lisps with lexical binding introduce "special variables" to support dynamic binding as well, and constructs like labels to extend the scope of variables beyond a single function.
    In PicoLisp, function definitions are normal symbol values. They can be dynamically rebound like other variables. ……
    Are there no problems caused by dynamic binding? You mean the funarg problem, or problems that arise when a variable might be bound to itself? For that reason we have a convention in PicoLisp to use transient symbols (instead of internal symbols) or private internal symbols ……
    But with dynamic binding I cannot implement closures! This is not true. Closures are a matter of scope, not of binding.
    For a closure it is necessary to build and maintain a separate environment. In a system with lexical bindings, this has to be done at each function call, and for compiled code it is the most efficient strategy anyway, because it is done once by the compiler, and can then be accessed as stack frames at runtime.
    For an interpreter, however, this is quite an overhead. So it should not be done automatically at each and every function invocation, but only if needed.
     
  78. ^ Lutz Mueller. . [2021-10-29]. (原始内容存档于2022-04-06). Dynamic scoping inside isolated namespaces - newLISP is sometimes criticized for using dynamic scoping and fexprs. …… In newLISP, all variables are dynamically scoped by default. However, by defining a function in its own context, static/lexical scoping can be achieved. In newLISP, several functions and data can share a namespace. By enclosing functions in their own namespace, a lexical closure- like mechanism is achieved. Common Lisp and Scheme are lexically scoped by default and use lambda expressions as the closure mechanism. Common Lisp also offers special variables for dynamic scoping.
    The problems of free variables in dynamic scoping can be avoided. In the rare cases when free variables must be used, you can partition code into namespace modules for easier control over free variables. You can then exploit the advantages of dynamic scoping. With dynamic scoping inside lexically-closed namespaces, newLISP combines the best of both scoping worlds.
    newLISP has no funarg problem because it follows a simple rule: variables always show the binding of their current environment. When expressions with local variables are entered, newLISP saves the current variable state on a stack and restores it on exit of that expression. In newLISP, not only are function parameters and variables declared with let expressions local, loop variables in all looping expressions are local too.
     
  79. ^ . EmacsWiki. [2021-10-28]. (原始内容存档于2022-05-09). dynamic - All variable names and their values live in one global table. lexical - Each binding scope (function, let syntax, …) creates a new table of variable names and values, organised in a hierarchy called “the environment”. ……
    EmacsLisp as of 24.1 has both dynamic binding and lexical binding. Lexical binding must be enabled explicitly for a file or buffer. Individual variables can be 'defvar'ed to make them “special”, like in CommonLisp.
     
  80. ^ Sebesta, Robert W. "2.4 Functional Programming: LISP";"6.9 List Types";"15.4 The First Functional Programming Language: LISP". 10th. Boston, MA, USA: Addison-Wesley. 2012: 47–52;281–284;677–680 [2021-10-23]. ISBN 978-0-13-139531-2. (原始内容 (print)存档于2021-03-08) (英语). 
  81. ^ Conses as Lists. Common Lisp HyperSpec.
    A list is a chain of conses in which the car of each cons is an element of the list, and the cdr of each cons is either the next link in the chain or a terminating atom.
    A proper list is a list terminated by the empty list. The empty list is a proper list, but is not a cons.
    An improper list is a list that is not a proper list; that is, it is a circular list or a dotted list.
    A dotted list is a list that has a terminating atom that is not the empty list. A non-nil atom by itself is not considered to be a list of any kind---not even a dotted list.
    A circular list is a chain of conses that has no termination because some cons in the chain is the cdr of a later cons.
     
  82. ^ . Cs.washington.edu. 1999-02-22 [2013-11-15]. (原始内容存档于2013-08-23). 
  83. ^ Alan Bawden. . 1999 [2021-10-29]. (原始内容存档于2021-10-29). 
  84. ^ 3.2.2.3 Semantic Constraints (页面存档备份,存于互联网档案馆) in Common Lisp HyperSpec (页面存档备份,存于互联网档案馆
  85. ^ 4.3. Control Abstraction (Recursion vs. Iteration) in Tutorial on Good Lisp Programming Style (页面存档备份,存于互联网档案馆) by Kent Pitman英语Kent Pitman and Peter Norvig, August, 1993.
  86. ^ Time of Evaluation - Common Lisp Extensions (页面存档备份,存于互联网档案馆). Gnu.org. Retrieved on 2013-07-17.
  87. ^ Gerald J. Sussman, Guy L. Steele Jr. The Revised Report on SCHEME: A Dialect of LISP. 1978. Magic forms are recognized by then presence of a "magic (reserved) word" in the car position of the form. All non-atomic forms which are not magic forms are considered to be combinations. The system has a small initial set of magic words; there is also a mechanism for creating new ones {Note FUNCALL is a Pain}.
    A combination is considered to be a list of subforms. These subforms are all evaluated. The first value mub be a procedure; it is applied to the other values to get the value of the combination. There are four important points here:
    (1) the procedure Position is always evaluated just like any other position. (This is why the primitive operators are the values of global identifiers.)
    (2) the procedure is never "re-evaluated"; if the first subform fails to evaluate to a applicable procedure, it is an error. Thus, unlike most LISP systems, SCHEME always evaluates the first subform of a combination exactly once.
    (3) the arguments are all completely evaluated before the procedure is applied; that is, SCHEME, like most LISP systems, is an applicative-order language. Many SCHEME programs exploit this fact.
    (4) the argument forms (and procedure form) may in principle be evaluated in any order. This is unlike the usual LISP left-to-right order. (All SCHEME interpreters implemented so far have in fact performed left-to-right evaluation, but we do not wish programs to depend on this fact. Indeed, there are some reasons why a clever interpreter might want to evaluate them right-to-left, e.g. to get things on a stack in the correct order.)
     
  88. ^ Paul Graham. What Made Lisp Different. May 2002. 
  89. ^ John McCarthy. History of Lisp (PDF). Artificial Intelligence Laboratory, Stanford University. 12 February 1979. I invented conditional expressions in connection with a set of chess legal move routines I wrote in FORTRAN for the IBM 704 at M.I.T. during 1957-58. ……
    A paper defining conditional expressions and proposing their use in Algol was sent to the Communications of the ACM but was arbitrarily demoted to a letter to the editor, because it was very short.
     
  90. ^ Alan Kay. The Early History of Smalltalk. 1993. doi:10.1145/155360.155364. The biggest hit for me while at SAIL英语Stanford_University_centers_and_institutes#Stanford_Artificial_Intelligence_Laboratory in late '69 was to really understand LISP. Of course, every student knew about car, cdr, and cons, but Utah was impoverished in that no one there used LISP and hence, no one had penetrated the mysteries of eval and apply. I could hardly believe how beautiful and wonderful the idea of LISP was [McCarthy 1960]. I say it this way because LISP had not only been around enough to get some honest barnacles, but worse, there wee deep flaws in its logical foundations. By this, I mean that the pure language was supposed to be based on functions, but its most important components — such as lambda expressions quotes, and conds – were not functions at all, and instead were called special forms. Landin and others had been able to get quotes and conds in terms of lambda by tricks that were variously clever and useful, but the flaw remained in the jewel. In the practical language things were better. There were not just EXPRs (which evaluated their arguments), but FEXPR英语fexprs (which did not). My next questions was, why on earth call it a functional language? Why not just base everything on FEXPRs and force evaluation on the receiving side when needed? I could never get a good answer, but the question was very helpful when it came time to invent Smalltalk, because this started a line of thought that said “take the hardest and most profound thing you need to do, make it great, an then build every easier thing out of it”. That was the promise of LISP and the lure of lambda – needed was a better “hardest and most profound” thing. Objects should be it. ……
    This Smalltalk language (today labeled -71) was very influenced by FLEX英语Flex (programming language), PLANNER英语Planner (programming language), LOGO, META II英语META II, and my own derivatives from them. ……
    As I mentioned previously, it was annoying that the surface beauty of LISP was marred by some of its key parts having to be introduced as “special forms” rather than as its supposed universal building block of functions. ……
    An elegant approach was suggested in a CMU thesis of Dave Fisher [Fisher 70] on the syntheses of control structures. ALGOL60 required a separate link for dynamic subroutine linking and for access to static global state. Fisher showed how a generalization of these links could be used to simulate a wide variety of control environments. One of the ways to solve the “funarg problem” of LISP is to associate the proper global state link with expressions and functions that are to be evaluated later so that the free variables referenced are the ones that were actually implied by the static form of the language. The notion of “lazy evaluation” is anticipated here as well.
     
  91. ^ Alan Kay, Stefan Ram. Dr. Alan Kay on the Meaning of “Object-Oriented Programming”. 2003-07-23. My original experiments with this architecture were done using a model I adapted from van Wijngaarten's and Wirth's "Generalization of Algol" and Wirth's Euler. Both of these were rather LISP-like but with a more conventional readable syntax. I didn't understand the monster LISP idea of tangible metalanguage then, but got kind of close with ideas about extensible languages draw from various sources, including Irons' IMP.
    The second phase of this was to finally understand LISP and then using this understanding to make much nicer and smaller and more powerful and more late bound understructures. Dave Fisher's thesis was done in "McCarthy" style and his ideas about extensible control structures were very helpful. ……
    OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I'm not aware of them.
     
  92. ^ Lieberman, Henry; Hewitt, Carl, A Real-Time Garbage Collector Based on the Lifetimes of Objects, Communications of the ACM, June 1983, 26 (6): 419–429, CiteSeerX 10.1.1.4.8633 , S2CID 14161480, doi:10.1145/358141.358147, hdl:1721.1/6335 
  93. ^ Edsger W. Dijkstra, The Humble Programmer (EWD 340), 1972  (ACM Turing Award lecture).
  94. ^ A Look at Clojure and the Lisp Resurgence. 
  95. ^ Paul Graham. (PDF). 2002 [2021-10-28]. (原始内容 (PDF)存档于2021-10-28). 
  96. ^ Daniel G. Bobrow, Kenneth Kahn, Gregor Kiczales, Larry Masinter, Mark Stefik, Frank Zdybel. . 1986 [2021-10-29]. (原始内容存档于2022-04-06). 
  97. ^ "A History and Description of CLOS", by Jim Veitch. Pages 107–158 of Handbook of Programming Languages, Volume IV: Functional and Logic Programming Languages, ed. Peter H. Salus英语Peter H. Salus. 1998 (1st edition), Macmillan Technical Publishing; ISBN 1-57870-011-6

延伸阅读

  • McCarthy, John. History of Lisp. Stanford University. 1979-02-12 [2008-10-17]. 
  • Steele, Jr., Guy L.; Richard P. Gabriel. The evolution of Lisp. The second ACM SIGPLAN conference on History of programming languages. New York, NY: ACM: 231–270. 1993 [2008-10-17]. ISBN 0-89791-570-4. 
  • Richard Stallman. My Lisp Experiences and the Development of GNU Emacs. transcript of Richard Stallman's speech, 28 October 2002, at the International Lisp Conference. 
  • Edmund Berkeley英语Edmund Berkeley; Daniel G. Bobrow英语Daniel G. Bobrow. The Programming Language LISP: Its Operation and Applications (PDF). Cambridge, Massachusetts: MIT Press. March 1964. 
  • Weissman, Clark. LISP 1.5 Primer (PDF). Belmont, California: Dickenson Publishing Company Inc. 1967. 

外部链接

历史
  • History of LISP at the Computer History Museum (页面存档备份,存于互联网档案馆
图书和教程
资源

lisp, lisp, 歷史上拼寫為, 是具有悠久歷史的計算機編程語言家族, 有獨特的完全用圓括號的前綴符號表示法, 它起源於1958年, 是現今第二悠久而仍廣泛使用的高階編程語言, 只有fortran編程語言比它更早一年, lisp編程語族已經演變出許多種方言, 現代最著名的通用編程語種是scheme, common, lisp和新近的clojure, lisp编程范型多范型, 函数式, 过程式, 同像性, 反射式, 元编程設計者约翰, 麦卡锡實作者史帝芬, 羅素, timothy, hart和michael, . Lisp 歷史上拼寫為LISP 是具有悠久歷史的計算機編程語言家族 有獨特的完全用圓括號的前綴符號表示法 3 它起源於1958年 4 是現今第二悠久而仍廣泛使用的高階編程語言 只有FORTRAN編程語言比它更早一年 5 Lisp編程語族已經演變出許多種方言 現代最著名的通用編程語種是Scheme Common Lisp和新近的Clojure Lisp编程范型多范型 函数式 过程式 同像性 反射式 元编程設計者约翰 麦卡锡實作者史帝芬 羅素 Timothy P Hart和Michael I Levin发行时间1958年 65年前 1958 型態系統动态类型 强类型衍生副語言Arc AutoLISP Clojure Common Lisp Emacs Lisp ISLISP newLISP PicoLisp Racket Scheme SKILL T 英语 T programming language 啟發語言IPL影響語言CLU Dylan Falcon Forth Haskell Io Ioke JavaScript Julia 1 Logo Lua LPC MDL 英语 MDL programming language ML Nu 英语 Nu programming language OPS5 英语 OPS5 Perl POP 2 11 英语 POP 11 Python REBOL Ruby Smalltalk Wolfram语言 2 目录 1 简介 2 歷史 2 1 联系于人工智能 2 2 谱系和方言 2 2 1 历史上的重要方言 2 3 2000年迄今 2 4 Lisp編程語族時間軸 3 主要方言 3 1 标准化的方言 4 语法和语义 4 1 符号表达式 4 2 列表 4 3 算符 4 4 Lambda表达式和函数定义 4 5 作用域和闭包 4 6 原子 4 7 cons和列表 4 7 1 S 表达式表示列表 4 7 2 列表处理过程 4 7 3 共享结构 4 8 自求值形式和引述 4 9 控制结构 4 10 程序代码的列表结构 4 11 求值和读取 求值 打印循环 5 语言创意 6 七个原始运算 6 1 quote 6 2 atom 6 3 eq 6 4 car 6 5 cdr 6 6 cons 6 7 cond 7 对象系统 8 範例 8 1 Hello World 8 2 阶乘 8 3 反转列表 9 参见 10 参考文献 11 延伸阅读 12 外部链接简介 编辑Lisp最初是為計算機程序創建的實用數學表示法 6 當時借鑒過阿隆佐 邱奇的lambda表示法 7 它很快成為人工智能研究中最受歡迎的編程語言 8 作為早期的高階編程語言之一 Lisp開創了計算機科學領域的許多概念 包括树结构 自動記憶體管理 动态类型 条件表达式 9 高階函數 10 遞迴 11 自主編譯器 英语 Self hosting compilers 12 讀取 求值 輸出循環 REPL 13 LISP 名稱源自 列表處理器 英語 LISt Processor 的縮寫 14 列表是Lisp的主要數據結構之一 Lisp編程代碼也同樣由列表組成 因此 Lisp程序可以把源代碼當作數據結構進行操作 而使用其中的宏系統 開發人員可將自己定義的新語法或領域專用的語言 嵌入在Lisp編程中 代碼和數據的可互換性為Lisp提供了立即可辨識的語法 所有的Lisp程序代碼都寫為S 表達式或以括號表示的列表 函數調用或語義形式也同樣寫成列表 首先是函數或操作符的名稱 然後接著是一或多個參數 例如 取三個參數的函數f即為 span class p span span class nv f span span class nv arg1 span span class nv arg2 span span class nv arg3 span span class p span 歷史 编辑 John McCarthy Steve Russell 在1958年 約翰 麥卡錫在麻省理工學院發明了Lisp程式語言 4 在1960年 他在 ACM通讯 發表了論文 符號表達式的遞迴函數及其機器計算 第一部份 15 在這篇論文中闡述了只要透過一些簡單的運算子 以及借鑒自阿隆佐 邱奇的用於匿名函數的表示法 7 就可以建立一個可用於演算法中的具圖靈完備性的語言 Lisp还采纳了在1955年至1956年間創建的資訊處理語言所提出的列表處理與遞歸概念 約翰 麥卡錫在最初定义的Lisp之中 先将程序表达为M 表达式 英语 M expression 元表达式 16 再将它转换成S 表達式 符号 英语 Symbol programming 表达式 舉例來說M 表达式 英语 M expression 的car cons A B 等同於S 表達式的 span class p span span class nb car span span class p span span class nb cons span span class nv A span span class nv B span span class p span S 表達式可以将复杂结构表示为列表 在Lisp被实现了之后 编程者一般只使用S 表達式 而棄用M 表達式 这使得程式具備了同像性 即程式與資料由同樣的結構儲存 M 表達式曾短暫存續於Horace Enea的MLisp 英语 MLisp 和Vaughan Pratt 英语 Vaughan Pratt 的CGOL 英语 CGOL 之中 17 史帝芬 羅素在IBM 704機器上使用打孔卡寫出了第一個Lisp實作 18 史帝芬 羅素在閱讀完約翰 麥卡錫的論文後 認為其中的eval函数可以用機器碼來實作 19 从而创造了一個能工作的Lisp解释器 20 解释器可以用来运行Lisp程序 或者更恰当的说 求值Lisp表达式 21 在1960年发表的LISP I中 22 研究生Daniel Edwards開發了垃圾回收程序 使得在通用計算機上運行Lisp變得可行 在1962年 Timothy Hart與Michael Levin在麻省理工學院以Lisp自身 實做出第一個完整的Lisp編譯器 23 在1963年 Timothy Hart提议向LISP 1 5增加宏 24 在1975年 傑拉德 薩斯曼和蓋伊 史提爾二世开发了Scheme 它是使用词法作用域和尾调用优化的第一个Lisp方言 25 在1980年代至1990年代期间 蓋伊 史提爾二世 Scott Fahlman 英语 Scott Fahlman Richard P Gabriel 英语 Richard P Gabriel David A Moon 英语 David A Moon 和Daniel Weinreb 英语 Daniel Weinreb 等人 在将当时新近的Lisp方言 其多数是Maclisp的后继者比如ZetaLisp和NIL 统一成单一语言上进行了巨大的努力 新语言Common Lisp 在某种程度上兼容于它所替代的方言 在1994年 ANSI出版了Common Lisp标准 ANSI X3 226 1994信息技术编程语言Common Lisp 此外还有嵌入到編輯器Emacs中的Emacs Lisp 它非常流行并建立了自己的标准 联系于人工智能 编辑 自从创始以来 Lisp就密切联系于人工智能研究社群 特别是在PDP 10系统之上 26 在1970年傑拉德 薩斯曼和特里 威诺格拉德使用Lisp实现了编程语言Micro Planner 英语 Planner programming language 27 它被用在著名的AI系统SHRDLU之中 谱系和方言 编辑 在它六十余年的历史中 Lisp产生了在S 表达式语言的核心主旨上的很多变体 28 此外 每个给定方言又可能有多种实现 例如Common Lisp就有十余种以上的实现 在一种标准化了的方言之内 符合标准的实现支持相同的核心语言 但是有着不同的扩展和函数库 在方言间的差异可能是非常显眼的 例如定义一个函数 29 Common Lisp使用Maclisp在1969年介入的关键字defun 30 而Scheme使用它在1975年介入的define 31 Richard P Gabriel 英语 Richard P Gabriel 和Kent Pitman 英语 Kent Pitman 在1998年的一篇论文中 按采用统一的还是分立的函数与值命名空间 将Lisp家族语言划分为Lisp1和Lisp2 或写为Lisp 1和Lisp 2 32 历史上的重要方言 编辑 Lisp机器 现存于MIT博物馆 英语 MIT Museum LISP I 22 是第一个实现 LISP 1 5 33 是第一个广泛发行的版本 由McCarthy和其他人在MIT开发 如此命名是因为它包含了对最初的LISP I解释器的改进 但不是LISP 2 英语 LISP 2 规划的那种重大重构 Stanford LISP 1 6 34 是斯坦福AI实验室 英语 Stanford University centers and institutes 开发的LISP 1 5后继者 广泛的发行于运行TOPS 10操作系统的PDP 10系统 罗宾 米尔纳的LCF 英语 Logic for Computable Functions ML运行在Stanford LISP 1 6下 35 它被Maclisp和InterLisp所淘汰 MACLISP 36 由MIT的MAC计划开发 它是LISP 1 5的直接后代 37 它运行在PDP 10和Multics系统上 MACLISP后来被称为Maclisp 也通常叫做MacLisp 在MACLISP中的 MAC 既无关于Apple的Macintosh 又无关于McCarthy Interlisp 英语 Interlisp 38 由BBN科技开发 用于运行TENEX 英语 TENEX operating system 操作系统的PDP 10系统之上 后来InterLisp D被Xerox Lisp机器接纳并昵称为 西海岸Lisp 还有为基于6502的Atari 8位机家族 英语 Atari 8 bit family 计算机发行的叫做 InterLISP 65 的小型版本 在很长一段时间内 Maclisp和InterLisp相互之间是强有力的竞争者 37 Franz Lisp 起源于加利福尼亚大学伯克利分校的计划 后来由Franz Inc开发 这个名字是Franz Liszt的幽默变形 它不牵涉到Franz Inc后来销售的Allegro Common Lisp 英语 Allegro Common Lisp XLISP 由David Betz开发 39 AutoLISP基于了它 Standard Lisp和Portable Standard Lisp 英语 Portable Standard Lisp 是曾被广泛使用和移植的犹他大学开发的版本 特别是用它写成了计算机代数系统REDUCE 英语 Reduce computer algebra system Lisp Machine Lisp 英语 Lisp Machine Lisp Symbolics称其变体版本为ZetaLisp 它用在Lisp机器之上 是Maclisp的直接后代 Lisp Machine Lisp对Common Lisp有巨大影响 Le Lisp 是一个法国Lisp方言 最早的界面建造器 英语 Graphical user interface builder 之一 叫做SOS界面 40 是用Le Lisp写成的 Scheme 1975年版 最初是在Maclisp上运行的解释器 41 Common Lisp 1984年版 42 是通过合并对Maclisp的不同尝试 ZetaLisp Spice Lisp 英语 Spice Lisp NIL 英语 NIL programming language 和S 1 Lisp 英语 S 1 Lisp 而创建的方言 43 也具有来自Scheme方言的实质影响 这个版本的Common Lisp在广泛的平台上都能获得到 从而被众人接受为业界标准 44 直至ANSI Common Lisp ANSI X3 226 1994 出版 最广泛传播的Common Lisp子方言 是Steel Bank Common Lisp SBCL CMU Common Lisp CMU CL Clozure OpenMCL GNU CLISP和Allegro Common Lisp 英语 Allegro Common Lisp 所有这些实现都坚持了后来的ANSI CL标准 Dylan 在它的第一个版本中是Scheme和Common Lisp对象系统的混合 EuLisp 英语 EuLisp 尝试开发一个新的高效和整洁的Lisp ISLISP 尝试开发一个新的高效和整洁的Lisp 标准化为ISO IEC 13816 1997 45 后来修订为ISO IEC 13816 2007 46 信息技术 编程语言 它们的环境和系统软件接口 编程语言 ISLISP IEEE Scheme IEEE标准1178 1990 停用日期 2019 11 07 47 ANSI Common Lisp 1994年版 是美国国家标准协会 ANSI 的Common Lisp标准 由X3J13 英语 X3J13 委员会创建 其章程是 48 开始于以 Common Lisp语言 英语 Common Lisp the Language 作为基础文档 42 致力于通过公开的达成共识过程 找到Common Lisp实现的程序可移植性和兼容性这个共通问题的解决方案 尽管形式上是ANSI标准 ANSI Common Lisp的实现 销售 使用和影响一直都是世界范围的 ACL2 是Common LISP的一个应用式 免于副作用 变体 ACL2既是可以建模计算机系统的编程语言 也是帮助证明这些模型性质的工具 GOAL 英语 Game Oriented Assembly Lisp 是一个视频游戏编程语言 由Andy Gavin 英语 Andy Gavin 和Jak and Daxter 英语 Jak and Daxter 团队在顽皮狗开发 它是使用Allegro Common Lisp写成并被用于整个Jak and Daxter 英语 Jak and Daxter 系列游戏的开发 2000年迄今 编辑 在1990年代衰退之後 Lisp在2000年之後因一些關注而逐漸復甦 當其他人認為Lisp已經過時陳舊 受到保羅 格雷厄姆和埃里克 雷蒙等人關於Lisp的著作的啟發 很多新的Lisp编程者經常將其描述為令人大開眼界的經驗 並聲稱在本質上比較其它編程語言更有生產效率 49 這種意識的提高可對比於 人工智能冬季 和Lisp在1990年代中期的短暫增長 50 Common Lisp開源社群建立了至今仍活躍的支援基礎有 CLiki 英语 CLiki 它是收集Common Lisp相關資訊的維基 Planet Lisp 它是收集了各種Lisp相關博客的內容 Common lisp net 它是開源專案的託管站點 Quicklisp 它是含括了許多函式庫的裝載管理器 在Common lisp net上 推荐了6种开源和2种商业Common Lisp实现 51 Scheme社群基于廣泛接納的R5RS語言標準 52 開發了一些活跃至今的實作如Chicken Gambit Gauche 英语 Gauche Scheme implementation Larceny和STklos 英语 STklos 等 Scheme实现要求 英语 Scheme Requests for Implementation 建立了很多準標準函式庫和Scheme擴展功能 随着Scheme實作用戶社群增長 始自2003年的語言標準化過程在2007年產生了R6RS標準 53 在2013年又通过了R7RS small最终草案 54 它已经有了一些实现支持 55 使用Scheme介紹計算機科學課程的學校似乎有所減少 麻省理工學院的計算機科學入門課程 已經不再使用Scheme 56 57 Clojure是在2007年出現的新近Lisp方言 它编译至Java虚拟机并特别关注并发性 現今與Lisp有關的大多數新活動 包括開發新的跨平台函式庫和應用 都集中在Scheme Common Lisp Emacs Lisp Racket和Clojure的實作上 近年来又有了幾種新的Lisp方言 Arc Hy Axel 58 和LFE 英语 LFE programming language 此外 在2007年出现的Nu 英语 Nu programming language 是OS X上采用Lisp式语法的脚本语言 在2012年出现的Julia所采用的语法解析器 是用Scheme方言Femtolisp实现的 在2019年10月 保羅 格雷厄姆发布了一个新的Lisp方言Bel 59 Lisp編程語族時間軸 编辑主要方言 编辑Common Lisp和Scheme是Lisp发展的两大主流的代表 这些语言体现了显著不同的设计选择 Common Lisp是Maclisp的后继者 对它有重要影响的是Lisp Machine Lisp 英语 Lisp Machine Lisp Maclisp NIL 英语 NIL programming language S 1 Lisp 英语 S 1 Lisp Spice Lisp 英语 Spice Lisp 和Scheme 60 它拥有用于编程Lisp机器的大型Lisp方言Lisp Machine Lisp的很多特征 但设计上能高效的实现在任何个人计算机或工作站上 Common Lisp是通用编程语言 因而拥有一个大型语言标准 包括很多内建数据类型 函数 宏和其他语言元素 以及一个对象系统 即Common Lisp对象系统 Common Lisp还从Scheme借鉴了特定特征 比如词法作用域和词法闭包 Common Lisp实现目标定为不同的平台 比如 LLVM 61 Java虚拟机 62 x86 64 PowerPC Alpha ARM Motorola 68000和MIPS 63 和不同的操作系统 比如 Windows macOS Linux Solaris FreeBSD NetBSD OpenBSD Dragonfly BSD和Heroku 64 Scheme是一个静态作用域和适当尾递归的Lisp编程语言方言 65 它的设计有着异常清晰和简单的语义 和很少的形成表达式的不同方式 它的设计大约比Common Lisp早上一个年代 Scheme是一个相当极简主义的设计 它拥有非常小的标准特征集合 但具有在Common Lisp中未规定的特定实现特征 比如尾递归优化和完全续体 在Scheme中能方便的表达广阔的编程范型 包括指令式 函数式和消息传递风格 Scheme通过一系列的标准 即第n次修订的算法语言Scheme报告 和一系列Scheme实现要求 英语 Scheme Requests for Implementation 而持续的演化 Clojure是Lisp的一个新近方言 其目标主要是Java虚拟机 通用语言运行库 CLR 和编译成JavaScript 它被设计为一个务实的通用编程语言 Clojure受到了Haskell的相当大的影响 因而非常强烈的强调了不可变性 66 Clojure提供了对Java框架和库的访问 具有可选的类型提示和类型推论 这样到Java的调用就可以避免反射并确使了快速的原始操作 Clojure设计上不后向兼容于其他Lisp方言 67 进一步的 Lisp方言在很多应用中被用作脚本语言 其中最周知的是在Emacs编辑器中的Emacs Lisp 在AutoCAD中的AutoLISP和后来的Visual Lisp Audacity中的Nyquist 英语 Nyquist programming language 和LilyPond中GNU Guile 有用的Scheme解释器潜在有很小的大小 使得它特别流行于嵌入式脚本 例子包括SIOD和TinyScheme 二者都曾经以共用名字 Script fu 成功的嵌入到了GIMP图像处理软件中 68 LIBREP是John Harper最初基于Emacs Lisp语言开发的Lisp解释器 它已经嵌入到了Sawfish窗口管理器 69 标准化的方言 编辑 Lisp有官方标准化和业界标准的方言 IEEE Scheme 47 ANSI Common Lisp ISO ISLISP R5RS Scheme和R7RS small Scheme 语法和语义 编辑注意 本文的例子是用Common Lisp书写 但是其中的多数在Scheme中也是有效的 示例采用的Common Lisp实现是SBCL 符号表达式 编辑 Lisp是一个面向表达式编程语言 英语 Expression oriented programming language 不同于多数其他语言 在表达式和语句之间不做区分 所有代码和数据都写为表达式 当求值一个表达式的时候 它产生一个值 在Common Lisp中可能有多个值 它可以接着被嵌入到其他表达式中 每个值都可以是任何数据类型的 McCarthy的1958年论文介入两种类型的语法 符号 英语 Symbol programming 表达式即S 表达式或sexps 它镜像了代码和数据的内部表示 和元表达式即M 表达式 英语 M expression 它是与S 表达式对应的用类似数学符号表达的函数 M 表达式从未得到青睐 几乎所有今天的Lisp都使用S 表达式来操纵代码和数据二者 大量而单一的使用圆括号 是Lisp与其他编程语言家族最直接明显的差别 为此学生们一直将Lisp戏称为 迷失在愚蠢的括号中 Lost In Stupid Parentheses 或 大量烦人的多余括号 Lots of Irritating Superfluous Parentheses 70 但是S 表达式语法也承担了Lisp多数能力 语法极其正规 利于计算机操纵 然而Lisp的语法不局限于传统的括号表示法 它可以扩展为包括可替代表示法 例如 XMLisp是Common Lisp扩展 它采用元对象协议 集成了S 表达式和可扩展标记语言 XML 有赖于表达式给予了语言巨大的灵活性 由于Lisp函数都写为列表 它们可以完全就像数据那样处理 这允许了轻易的书写能操纵其他程序的程序 即进行元编程 很多Lisp方言使用宏系统来利用这个特征 它确使了语言扩展而几乎没有限制 列表 编辑 书写Lisp列表 是以空白来分隔其元素 并包围以圆括号 例如 span class p span span class mi 1 span span class mi 2 span span class nv foo span span class p span 是其元素为三个原子 span class mi 1 span span class mi 2 span 和 span class nv foo span 的一个列表 这些值是隐含的有类型的 它们分别是两个整数和叫做 符号 的Lisp专有数据类型 但不需要显式的声明 空列表 span class p span 也表示为特殊原子 span class no nil span 这是Lisp中既是原子又是列表的唯一实体 表示式被写为使用前缀表示法的列表 在列表中第一个元素是一个函数的名字 一个宏的名字 一个lambda表达式或特殊算符的名字 见后 列表的余下部份是实际参数 例如 函数 span class nb list span 将它的实际参数作为一个列表返回 所以表达式 list 1 2 quote foo 1 2 FOO 在前面例子中的 span class nv foo span 之前的quote是特殊算符 它不求值就返回它的实际参数 任何未引述的表达式 在外围表达式被求值之前 都递归的被求值 例如 list 1 2 list 3 4 1 2 3 4 注意第三个实际参数是一个列表 列表是可以嵌套的 算符 编辑 对算术算符的对待都是类似的 表达式 1 2 3 4 10 其在中缀表示法下的等价形式为 span class mi 1 span span class n span span class mi 2 span span class n span span class mi 3 span span class n span span class mi 4 span Lisp没有在Algol派生语言中实现的那样的算符概念 在Lisp中算术算符是可变参数函数 或多元函数 能够接受任何数目的实际参数 C 风格的 增加算符 有时在名字incf之下实现 给出的语法是 setq x 0 0 incf x 1 等价于 setq x x 1 它返回x的新值 特殊算符 有时叫做特殊形式 71 提供了Lisp的控制结构 例如 特殊算符 span class k if span 接受三个实际参数 如果第一个实际参数为非nil 它求值为第二实际参数 否则它求值为第三个实际参数 因此表达式 if nil list 1 2 foo list 3 4 bar 3 4 bar 当然 如果在 span class no nil span 的位置替换上非平凡的表达式会更有用处 Lisp还提供逻辑算符and or和not and和or算符进行短路求值 并分别返回它们的第一个nil或非nil实际参数 or and zero nil never James task time James Lambda表达式和函数定义 编辑 另一个特殊算符 span class k lambda span 被用来绑定变量到值 接着对表达式求进行求值 这个算符还被用于建立函数 给 span class k lambda span 的实际参数是一个形式参数列表 和这个函数要求值的一个或多个表达式 它的返回值是其求值的最后一个表达式的值 表达式 lambda arg arg 1 lt FUNCTION LAMBDA ARG 5344B3FB gt 求值为一个函数 它接受一个实际参数 绑定它到 span class nv arg span 并返回比这个实际参数大1的数 对待Lambda表达式于命名函数没有区别 它们以相同方式调用 如下表达式 lambda arg arg 1 5 6 这里我们做了一次函数应用 我们通过传递给它值5而执行了这个匿名函数 命名函数是通过使用defun宏 30 将一个lambda表达式存储在一个符号之中而建立的 defun foo a b c d a b c d FOO span class p span span class nb defun span span class nv f span span class p span span class nv a span span class p span span class nv b span span class p span 在全局环境中定义一个名为 span class nv f span 的新函数 它在概念上类似于表达式 setf fdefinition f lambda a block f b lt FUNCTION LAMBDA A 5344BA1B gt 这里的 span class nb setf span 是一个宏 72 用来设置第一个实际参数 span class nb fdefinition span span class ss f span 为一个新的函数对象 span class nb fdefinition span 是对命名为 span class nv f span 的函数的全局函数定义 span class nf span 是特殊算符 span class k function span 的简写 它返回指定函数在当前词法环境下的一个函数对象 10 作用域和闭包 编辑 按照变量的作用域 73 可将Lisp家族划分为两大支系 分别使用动态作用域 74 或使用静态 也叫做词法 作用域 75 Scheme Common Lisp 76 和Clojure缺省使用静态作用域 而AutoLISP PicoLisp 77 和newLISP 78 使用动态作用域 Emacs Lisp自从Emacs版本24 1起使用动态和词法作用域二者 79 原子 编辑 在最初的LISP中 有两种基础数据类型 原子和列表 列表是元素的一个有限有序序列 这里的每个元素要么是一个原子要么是一个列表 而原子要么是一个数要么是一个符号 符号实质上是唯一性命名的项目 在源代码中写为字母数字串 并被要么用作一个变量名字要么符号处理 英语 Computer algebra 中的一个数据项目 例如 列表 span class p span span class nv FOO span span class p span span class nv BAR span span class mi 1 span span class p span span class mi 2 span span class p span 包含三个元素 符号 span class nv FOO span 列表 span class p span span class nv BAR span span class mi 1 span span class p span 和数2 在原子和列表之间的本质区别是原子是不可变的和唯一性的 出现在源代码中不同位置的两个原子 如果以完全相同方式写成则表示相同的对象 而每个列表都是一个分立的对象 它们可以独立于其他列表而改变 并可以通过比较算符而区分于其他列表 随着后来的Lisp介入了更多的数据类型 和编程风格的演化 原子的概念失去了重要性 很多方言出于遗产兼容性而保留了谓词atom 定义它为对不是cons的任何对象都为真 cons和列表 编辑 主条目 列表構造函數 列表 42 69 613 的方框与指针示意图 Lisp列表被实现为单向链表 80 这个链表的每个单元都叫做 a href E5 88 97 E8 A1 A8 E6 A7 8B E9 80 A0 E5 87 BD E6 95 B8 html title 列表構造函數 cons a 在Scheme中叫做pair 它构成自两个指针 分别叫做 span class ilh all data orig title CAR与CDR data lang code en data lang name 英语 data foreign title CAR and CDR span class ilh page car span span class noprint ilh comment span class ilh lang 英语 span span class ilh colon span span class ilh link span lang en dir auto CAR and CDR span span span span 和 span class ilh all data orig title CAR与CDR data lang code en data lang name 英语 data foreign title CAR and CDR span class ilh page cdr span span class noprint ilh comment span class ilh lang 英语 span span class ilh colon span span class ilh link span lang en dir auto CAR and CDR span span span span 在众多可以用cons单元构建的数据结构中 最基本一个叫做 适当列表 proper list 适当列表要么是特殊的 span class no nil span 空列表 符号 要么是一个cons 它的 span class nb car span 指向一个数据项 它可以是另一个cons结构比如一个列表 而 span class nb cdr span 指向另一个适当列表 如果一个给定cons被接受为一个链表的头部 那么它的car指向这个列表的第一个元素 而它的cdr指向这个列表的余下部份 为此 在提及作为链表 而非树等 一部份的cons的时候 span class nb car span 和 span class nb cdr span 函数也分别叫做 span class nb first span 和 span class nb rest span 因此 Lisp列表不是原子对象 它们类似C 或Java中的容器类的实例 一个列表就是链接的cons的一个聚集 引用一个给定列表的变量 简单的就是到列表中第一个cons的指针 遍历一个列表可以通过逐一cdr这个列表来进行 就是说连续的选取cdr来访问这个列表的每个cons 或者通过使用任何一个将一个函数映射在一个列表之上的高阶函数 由于cons和列表在Lisp系统中是普遍性的 经常有人误解它们是Lisp的唯一数据结构 事实上 除了最简单者之外的所有Lisp都有其他数据结构 比如向量 数组 英语 Array data type 散列表 结构等等 S 表达式表示列表 编辑 圆括号的S 表达式表示了链表结构 有多种方式将相同的列表表示为一个S 表达式 cons可以用 点对表示法 写为 span class p span span class nv a span span class o span span class nv b span span class p span 这里的 span class nv a span 是car而 span class nv b span 是cdr 更长的适当列表可以用点对表示法写为 span class p span span class nv a span span class o span span class p span span class nv b span span class o span span class p span span class nv c span span class o span span class p span span class nv d span span class o span span class no nil span span class p span 这通常简写为列表表示法的 span class p span span class nv a span span class nv b span span class nv c span span class nv d span span class p span 不适当列表 improper list 81 可以用这二种表示法的组合来书写 比如列表 span class p span span class nv a span span class nv b span span class nv c span span class o span span class nv d span span class p span 有三个cons 最后的cdr是 span class nv d span 它就是完全特殊形式下的 span class p span span class nv a span span class o span span class p span span class nv b span span class o span span class p span span class nv c span span class o span span class nv d span span class p span 列表处理过程 编辑 Lisp提供很多内建的过程 用来访问和控制列表 列表可以直接用 span class nb list span 过程创建 它接受任何数目的实际参数 并返回这些实际参数的列表 list 1 2 a 3 1 2 A 3 list 1 2 3 4 1 2 3 4 由于列表是从cons对构造而来 可以使用 span class nb cons span 过程来在一个列表的前端增加一个元素 注意由于列表构造方法 span class nb cons span 在处理列表实际参数上是不对称的 cons 1 2 3 1 2 3 cons 1 2 3 4 1 2 3 4 span class nb append span 过程将两个 或更多 列表相互附加 由于Lisp列表是链表 附加两个列表有渐进时间复杂度 O n displaystyle O n append 1 2 3 4 1 2 3 4 append 1 2 3 a 5 6 1 2 3 A 5 6 共享结构 编辑 Lisp列表 作为单向链表 可以相互共享结构 就是说 两个列表可以有相同的尾部 或者最终的cons序列 例如 在执行下列Common Lisp代码之后 setf foo list a b c A B C setf bar cons x cdr foo X B C 尾部 span class p span span class nv b span span class nv c span span class p span 在两个列表中都是相同的结构 它不是复件 对于两个列表指向 span class nv b span 和 span class nv c span 的cons单元都在相同的内存位置 共享结构而非复制可以得到相当客观的性能提升 但是这种技术可能以未预期的方式 交互于改变作为实际参数传递给它的列表的那些函数 改变一个列表 比如替代 span class nv c span 为 span class nv goose span 将会影响另一个列表 setf third foo goose GOOSE bar X B GOOSE 不仅变更foo 还变更了bar 这可能是未预期的结果 这是缺陷的来源 为此改变它们的实际参数的那些函数被文档标示为破坏性的 destructive 函数式编程爱好者避免破坏性函数 在青睐函数式风格的Scheme方言中 破坏性函数的名字都标记了警告性感叹号 或者叫做 bang 比如 span class nv set car span 读作set car bang 它替换一个cons的car 在Common Lisp方言中 破坏性函数是司空见惯的 与 span class nv set car span 等价的是 span class nb rplaca span 它的名字表示 replace car 这个函数是不常见的 因为Common Lisp包括了一个特殊设施 span class nb setf span 72 用来轻易的定义和使用破坏性函数 在Common Lisp中常见的风格是在构建原型的时候写函数式代码 没有破坏性调用 接着将破坏性调用作为优化增加于可以安全的进行它们的地方 自求值形式和引述 编辑 Lisp求值用户录入的表达式 符号和列表求值为某个其他 通常更简单的 表达式 例如 一个符号求值为它指名的变量的值 span class p span span class nb span span class mi 2 span span class mi 3 span span class p span 求值为 span class mi 5 span 但是 多数其他形式求值为其自身 如果录入 span class mi 5 span 到Lisp中 它返回 span class mi 5 span 任何表达式都可以加上防止被求值的标记 这对于符号和列表是需要的 特殊算符 span class k quote span 承担了这个角色 它也简写为 span class o span 一个单引号 例如 通常如果录入了符号 span class nv foo span 它返回对应变量的值 没有这个变量则为一个错误 要引用这个文字 英语 Literal computer programming 符号 录入要么 span class p span span class k quote span span class nv foo span span class p span 要么更常见的 span class ss foo span 37 Common Lisp和Scheme二者还支持 反引述 backquote 算符 在Scheme中叫做准引述 英语 quasiquote quasiquote 这时录入 span class o span 字符 重音符 它几乎同于普通引述 除了它允许表达式被求值 并将它们的值插入到引述列表之中 这些表达式标记了 span class o span 逗号 表示去引述 unquote 或 span class o span 逗号 at 表示拼接算符 unquote splicing 如果变量 span class nv snue span 有值 span class p span span class nv bar span span class nv baz span span class p span 则 span class o span span class p span span class nv foo span span class o span span class nv snue span span class p span 求值为 span class p span span class nv foo span span class p span span class nv bar span span class nv baz span span class p span 而 span class o span span class p span span class nv foo span span class o span span class nv snue span span class p span 求值为 span class p span span class nv foo span span class nv bar span span class nv baz span span class p span 反引述经常用于定义宏展开 82 83 自求值形式和引述形式是Lisp中文字 英语 Literal computer programming 的等价者 在程序代码中可以修改 可变 文字的值 例如 如果一个函数返回一个引述形式 而调用这个函数的代码修改这个形式 这可以改变这个函数在后续调用时的行为 defun should be constant one two three SHOULD BE CONSTANT let stuff should be constant setf third stuff bizarre BIZARRE should be constant ONE TWO BIZARRE 像这样修改一个引述形式通常被认为是不良风格 并且被ANSI Common Lisp定义为是危险的 它会导致在编译文件中的未定义的行为 因为文件编译器可以合并类似的常量并将它们放置到写保护内存中 等等 Lisp的引述形式化已经被Douglas Hofstadter 在 Godel Escher Bach 中 和其他人注解为自引用的哲学想法的例子 控制结构 编辑 Lisp最初有很少的控制结构 但是在语言演化期间却增加了很多 Lisp最初的条件算符是 span class nb cond span 9 它或被视为后来的 span class nv if then else span 结构的先驱 Scheme方言的编程者经常使用尾递归表达循环 Scheme在学术计算机科学中的通行性 导致了一些学生相信尾递归是在Lisp中书写迭代的唯一的或最常用的方式 但是这是不正确的 所有常见的Lisp方言都有指令式风格的迭代构造 从Scheme的 span class nb do span 循环到Common Lisp的复杂的 span class nb loop span 表达式 此外 使之成为客观而非主观事物的关键要点 是Scheme对尾递归的处理提出了特殊要求 Scheme通常鼓励使用尾递归的原因 是语言定义明确的支持了这种实践 与之相反 ANSI Common Lisp不要求常称为尾递归消除的这种优化 84 因此 不鼓励将尾递归风格作为使用更传统的迭代构造 比如 span class nb do span span class nb dolist span 或 span class nb loop span 的替代品 85 在Common Lisp中不只是风格偏好的问题 而是潜在的效率问题 这是因为在Common Lisp中明显的尾递归可能未被编译为简单的 a href E5 88 86 E6 94 AF E8 A8 88 E7 AE 97 E6 A9 9F E7 A7 91 E5 AD B8 html title 分支 計算機科學 jump a 并且也是程序正确性问题 这是因为在Common Lisp中尾递归可能增加栈的使用而有堆栈溢出风险 一些Lisp控制构造是特殊算符 等价于其他语言的语法关键字 使用这些算符的表达式与函数调用有着相同的表面外观 但是不同之处在于参数不是必须求值的 或者在迭代表达式的情况下 可以被求值多于一次 对比于多数其他主要编程语言 Lisp允许使用语言自身实现控制结构 一些控制结构被实现为Lisp宏 想知道它们是如何工作的编程者甚至可以通过宏展开来研究 Common Lisp和Scheme二者都有非局部控制流程算符 在这些算符中的不同是在这两种方言之间最深的差异 Scheme使用 span class nv call cc span 过程支持可重入的续体 它允许一个程序保存 并在将来恢复 执行中的特定位置 Common Lisp不支持可重入的续体 但是支持处理逃脱续体的一些方式 相同的算法在Lisp中经常可以用要么指令式要么函数式风格来表达 如上所述 Scheme趋于青睐函数式风格 使用尾递归和续体来表达控制流程 但是 指令式风格仍是很有可能的 很多Common Lisp编程者偏好的风格 可能让使用结构化编程语言比如C的编程者看着更加熟悉 而Scheme编程者偏好的风格更加密切类似于纯函数式编程语言比如Haskell 由于Lisp在列表处理上的早期遗产 它拥有与在序列上迭代有关的一组广泛的高阶函数 在其他语言中需要显式循环 比如C中的 span class nv for span 循环 的很多情况下 在Lisp和很多函数式编程语言中 相同的任务可以通过高阶函数来完成 一个好的例子是在Scheme中叫做 span class nb map span 而在Common Lisp中叫做 span class nb mapcar span 的函数 给定一个函数和一个或多个列表 span class nb mapcar span 按顺序将这个函数依次应用到这些列表的元素之上 并将结果收集入一个新的列表 mapcar 1 2 3 4 5 10 20 30 40 50 11 22 33 44 55 这个 a href Map E9 AB 98 E9 98 B6 E5 87 BD E6 95 B0 html title Map 高阶函数 mapcar a 函数将 span class nb span 函数应用于每个对应的元素对之上 程序代码的列表结构 编辑 在Lisp和其他语言之间的基本区别是 在Lisp中一个程序的文本表示 简单的是人类可读的描述 它同于底层Lisp系统使用的内部数据结构 链表 符号 数 字符等 Lisp利用这一点来实现了一个非常强力的宏系统 就像其他宏语言比如C 一个宏返回可以接着被编译的代码 但是不同于C的宏 Lisp的宏是函数因而可以利用Lisp的全部能力 进一步的 因为Lisp代码作为列表有着相同的结构 宏可以使用语言中任何列表处理函数来建造 简要的说 Lisp可以在数据结构上做的任何事情 Lisp宏都可以在代码上做 相反的 在多数其他语言中 解析器的输出是纯粹的内部于语言实现的而不能被编程者操纵 这个特征可以在语言中开发高效语言 例如 Common Lisp对象系统可以使用宏清晰的实现为一个语言扩展 这意味着如果一个应用需要不同的继承机制 它可以使用不同的对象系统 这直接的对立于多数其他语言 例如 Java不能支持多重继承并且没有增加它的合理方式 在简单的Lisp实现中 这个列表结构被直接的解释来运行这个程序 一个函数是在文字上的一段列表结构 它被解释器在执行它的时候遍历 但是 多数后来的Lisp系统还包括一个编译器 编译器将列表结构转换成机器代码或字节码用于执行 这个代码可以像用常规语言比如C编译的代码一样快速 宏在编译步骤之前展开 因而提供一些有价值的选项 如果一个程序需要一个预先计算了的表格 那么一个宏可以在编译时间建立这个表格 所以编译器只需要输出这个表格 而不需要在运行时间调用代码来建立这个表格 一些Lisp实现甚至拥有一种eval when机制 允许代码在编译时间期间出现 在一个宏需要它的时候 而不出现在发行的模块中 86 求值和读取 求值 打印循环 编辑 Lisp语言经常被以交互式命令行来使用 它还可以结合入集成开发环境 IDE 用户在命令行录入表达式 或指示IDE将它们传送给Lisp系统 Lisp读取录入的表达式 求值它们 并打印结果 为此 Lisp命令行被叫做读取 求值 输出循环 REPL REPL的基本操作描述如下 这是一个简化的描述 省略了很多真实Lisp的元素 比如引述和宏 span class nb read span 函数接受文本的S 表达式作为输入 并将它们解析为内部数据结构 例如 如果你在提示符下录入文本 span class p span span class nb span span class mi 1 span span class mi 2 span span class p span span class nb read span 将它转换成有三个元素的一个链表 符号 span class nb span 数1和数2 恰巧这个列表也是一段有效的Lisp代码 就是说它是可以被求值的 这是因为car这个列表指名了一个函数即加法运算 注意 span class nv foo span 将被读作一个单一符号 span class mi 123 span 将被读作数一百二十三 span class s 123 span 将被读作字符串 123 span class nb eval span 函数求值数据 返回零或多个其他Lisp数据作为结果 求值不必然意味着解释 一些Lisp系统编译所有的表达式为机器代码 但将求值描述为解释是很简单的 要求值其car指名一个函数的一个列表 span class nb eval span 首先求值在它的cdr中的每个实际参数 接着应用这个函数于这些实际参数 在这个案例中 这个函数是加法 而应用它于实际参数列表 span class p span span class mi 1 span span class mi 2 span span class p span 产生答案 span class mi 3 span 这是这个求值的结果 符号 span class nv foo span 求值为符号foo的值 数据比如字符串 123 求值为相同的字符串 列表 span class p span span class k quote span span class p span span class mi 1 span span class mi 2 span span class mi 3 span span class p span 求值为列表 1 2 3 span class nb print span 函数的工作是将输入表示给用户 对于简单结果比如 span class mi 3 span 这是平凡的 求值为一段列表结构的一个表达式会要求 span class nb print span 遍历这个列表并将结果输出为一个S 表达式 要实现一个Lisp REPL 必需的只是实现这三个函数和一个无限循环函数 实现 span class nb eval span 函数会很复杂是自然的 因为它必须也要实现所有特殊算符比如 span class k if span 或 span class k lambda span 它们完成后 一个基本的REPL就是一行代码 span class p span span class nb loop span span class p span span class nb print span span class p span span class nb eval span span class p span span class nb read span span class p span Lisp REPL典型的也提供输入编辑 输入历史 错误处理和到调试器的接口 Lisp通常使用及早求值 在Common Lisp中 实际参数以应用式次序 最左最内为先 求值 而在Scheme中实际参数的次序是未定义的 为编译器优化留下了余地 87 语言创意 编辑保罗 格雷厄姆辨识出Lisp区别于其他现存的语言如Fortran的九个重要特征 88 条件不受限于跳转 头等函数 递归 将变量统一当作指针 将类型留给值 垃圾回收 程序完全构成自表达式 英语 Expression computer science 而没有语句 符号 英语 Symbol programming 数据类型 区别于字符串数据类型 代码的表示法构成自符号树 使用很多圆括号 完全的语言可以获得于装载时间 编译时间和执行时间 Lisp是将程序代码的结构忠实而直接的表示为标准数据结构的第一个语言 这种品质后来被称为 同像性 故而Lisp函数可以在Lisp程序中被操纵 更改 甚至创建 而不用低层操纵 这通常被认为是语言表达能力方面的主要优势之一 使得语言适合于语法宏和元循环求值 条件表达式是麦卡锡用Fortran写一个象棋程序时发明的 他提议将其包含在ALGOL中但未被采纳 89 Lisp中的条件表达式使用了一般性的cond结构 ALGOL 60采纳了约翰 巴科斯提议的if then else条件语句并使之流行起来 9 Lisp深刻影响了艾伦 凯 90 他是在Xerox PARC开发Smalltalk的研究组的领导者 反过来Lisp又受到Smalltalk的影响 其后来的方言在1970年代接纳了面向对象编程特征 包括有继承的类 封装的实例 消息传递等 Flavors 英语 Flavors programming language 对象系统介入了多重继承和混入的概念 Common Lisp对象系统 CLOS 提供了多重继承 具有多分派的多方法 和头等泛化函数 从而产生了一种灵活而强力形式的动态分派 CLOS充当了很多后来的包括Scheme在内的Lisp的对象系统的模板 它经常通过Gregor Kiczales 英语 Gregor Kiczales 等人发展出的元对象协议来实现 这是一种反射式元循环设计 其中的对象系统依据自身来定义 由于这些特征的融合 Lisp成为Smalltalk之后第二个具有元对象系统的语言 多年以后艾伦 凯宣称 只有Smalltalk和Lisp可以视为完全意义上的面向对象编程系统 91 Lisp介入了自动垃圾回收的概念 即系统巡视堆来寻找无用的内存 现代复杂的垃圾回收算法比如分代垃圾回收的进步 受到了它在Lisp中使用的激励 92 艾兹赫尔 戴克斯特拉在他的1972年图灵奖演讲中说道 具有一些非常基本的原理作为基础 它 LISP 已经展示出卓越的稳定性 除此之外 LISP已经承载了相当可观的在某种意义上我们最复杂的计算机应用 LISP被玩笑的描述为 滥用计算机的最明智方式 我认为这个描述是一种巨大的赞美 因为它传达了解放的全部意味 它辅助大量我们最有天赋的人类同胞去思考在以前不可能的想法 93 很大程度上由于它对于包括早期微处理器在内的早期计算机硬件的资源需求 Lisp未能像Fortran和ALGOL后裔C语言那样在人工智能社区之外得以流行 由于它适合于复杂和动态的应用 Lisp在2010年代享有了一定程度的大众关注的复兴 94 七个原始运算 编辑保罗 格雷厄姆从约翰 麦卡锡的最初论文中提炼出如下7个原始运算 95 quote 编辑 quote x 返回x 通常简记为 x quote a A a A quote a b c A B C 將quote寫成 只是一種語法糖 37 atom 编辑 atom x 当x是一个atom或者空的list时返回原子t 否则返回NIL 在Common Lisp中通常习惯用原子t列表示真 而用空列表 或NIL列表示假 例如 atom a T atom a b c NIL atom T atom是需要求出实际参数值的算符 下面展示quote算符的作用 即通过引述一个列表 避免它被求值 eval 一个未被引述的列表达式作为实际参数 atom会将其视为代码 例如 atom atom a T 这是因为 atom a 已求值出结果t 把它代入 atom atom a 成为 atom t 从而这个列表达式的结果是t 反之一个被引述的列表 仅仅被视为列表 例如 atom atom a NIL 引用看上去有些奇怪 因为很难在其它语言中找到类似的概念 但正是这一特征构成了Lisp最为与众不同的特点 代码和数据使用相同的结构来列表示 只是用quote来区分它们 eq 编辑 eq x y 当x和y指向相同的对象的时候返回t 否则返回NIL 例如 eq a a T eq a b NIL eq T eq a b c a b c NIL 值得注意的是在Common Lisp中 原子对象在内存中只会有一份拷贝 所以 eq a a 返回t car 编辑 car x 要求x是一个列表 它返回x中的第一个元素 例如 car a b A cdr 编辑 cdr x 同样要求x是一个列表 它返回x中除第一个元素之外的所有元素组成的列表 例如 cdr a b c B C cons 编辑 cons x y预期y的值是一个列表 并且返回包含x的值和随后y的值的那些元素的一个列表 例如 cons a b A B cons a cons b c A B C cons a cons b A B cons a cons b cons c A B C cond 编辑 cond p sub 1 sub e sub 1 sub p sub n sub e sub n sub 的求值规则如下 对 条件列表达式p 依次求值 直到有一个返回t 如果能找到这样的p列表达式 相应的 结果列表达式e 的值 作为整个cond列表达式的返回值 例如 cond eq a b first atom a second SECOND对象系统 编辑已经有各种对象系统和模型建造在Lisp之上 旁边或其中 包括 Common Lisp对象系统 CLOS 是ANSI Common Lisp内在的一部份 CLOS衍生自New Flavors和CommonLOOPS ANSI Common Lisp是第一个标准化的面向对象编程语言 1994 ANSI X3J13 ObjectLisp 96 或Object Lisp 英语 Object Lisp 用于Lisp机器公司 英语 Lisp Machines 和早期版本的Macintosh Common Lisp LOOPS Lisp面向对象编程系统 和后来的CommonLOOPS 英语 CommonLOOPS Flavors 英语 Flavors programming language 建造于MIT 它的后代是New Flavors 由Symbolics com开发 KR 知识表达 它是用来辅助书写Common Lisp的GUI库Garnet的基于约束 英语 Constraint satisfaction 的对象系统 知识工程环境 英语 Knowledge Engineering Environment KEE 使用叫做UNITS的对象系统并集成入了推理机 97 和推理维护系统 英语 Reason maintenance ATMS 範例 编辑Hello World 编辑 这个Hello World 例子展示Lisp的三种主要方言 在基本输出和函数定义上的用法 Scheme Common Lisp Clojure 显示过程在屏幕中打印字符串 并返回未规定值 display Hello world 定义过程hello world define hello world display Hello world 调用过程hello world hello world 格式化函数在第一个参数是t时 在屏幕中打印字符串 并返回NIL format t hello world 定义函数hello world defun hello world format t hello world 调用函数hello world hello world 打印函数在屏幕中打印字符串 并返回nil print hello world 定义函数hello world defn hello world print hello world 调用函数hello world hello world 阶乘 编辑 Lisp语法自然的适合于递归 数学问题比如递归定义集合的枚举 在这种表示法中表达是很容易的 例如 要求值一个数的阶乘 defun factorial n if zerop n 1 n factorial 1 n 下面的版本在底层Lisp系统进行尾递归优化时比前面版本取用更少的堆栈空间 defun factorial n amp optional acc 1 if zerop n acc factorial 1 n acc n 对比上述例子 下面的指令式版本使用了Common Lisp的 span class nb loop span 宏 defun factorial n loop for i from 1 to n for fac 1 then fac i finally return fac 反转列表 编辑 下列函数反转一个列表 它与Lisp内建的reverse函数做同样的事情 defun reverse list let return value dolist e list push e return value return value 参见 编辑 计算机程序设计主题 自修改代码参考文献 编辑 Julia Documentation Introduction Julia builds upon the lineage of mathematical programming languages but also borrows much from popular dynamic languages including Lisp Perl Python Lua and Ruby some advantages of Julia over comparable systems include Lisp like macros and other metaprogramming facilities Wolfram Language Q amp A Wolfram Research LISP and APL were two early influences as was Stephen Wolfram s 1981 SMP symbolic computation language Edwin D Reilly Milestones in computer science and information technology Greenwood Publishing Group 2003 156 157 2021 10 24 ISBN 978 1 57356 521 9 原始内容存档于2020 08 05 4 0 4 1 John McCarthy History of Lisp PDF Artificial Intelligence Laboratory Stanford University 12 February 1979 2021 10 25 原始内容 PDF 存档于2020 11 07 There were two motivations for developing a language for the IBM 704 First IBM was generously establishing a New England Computation Center at M I T Second IBM was undertaking to develop a program for proving theorems in plane geometry based on an idea of Marvin Minsky s In connection with IBM s plane geometry project Nathaniel Rochester and Herbert Gelernter 英语 Herbert Gelernter on the advice of McCarthy decided to implement a list processing language within FORTRAN This work was undertaken by Herbert Gelernter and Carl Gerberich at IBM and led to FLPL standing for FORTRAN List Processing Language I spent the summer of 1958 at the IBM Information Research Department at the invitation of Nathaniel Rochester and chose differentiating algebraic expressions as a sample problem It led to the following innovations beyond FLPL a Writing recursive function definitions using conditional expressions b The maplist function that forms a list of applications of a functional argument to the elements of a list c To use functions as arguments one needs a notation for functions and it seemed natural to use the l notation of Church 1941 d The recursive definition of differentiation made no provision for erasure of abandoned list structure The implementation of LISP began in Fall 1958 LISP is now the second oldest programming language in present widespread use after FORTRAN and not counting APT which isn t used for programming per se SICP Foreword 原始内容存档于2001 07 27 Lisp is a survivor having been in use for about a quarter of a century Among the active programming languages only Fortran has had a longer life Guy L Steele Jr Gerald J Sussman The Art of the Interpreter of the Modularity Complex Parts Zero One and Two MIT Libraries May 1978 2020 08 01 hdl 1721 1 6094 原始内容存档于2021 01 24 Contrary to popular belief LISP was not originally derived from Church s l calculus Church LISP History The earliest LISP did not have a well defined notion of free variables or procedural objects Early LISP programs were similar to recursion equations defining functions on symbolic expressions S expressions They differed from the equations of pure recursive function theory Kleene by introducing the conditional expression construction often called the McCarthy conditional to avoid pattern directed invocation That is in recursive function theory one would define the factorial function by the following two equations factorial 0 1 factorial successor x successor x factorial x In early LISP however one would have written factorial x x 0 1 T x factoria1 x 1 where a b T c essentially means if a then b else c The recursive function theory version depends on selecting which of two equations to use by matching the argument to the left hand sides such a discipline is actually used in the PROLOG language Warren the early LISP version represents this decision as a conditional expression The theory of recursion equations deals with functions over the natural numbers In LISP however one is interested in being able to manipulate algebraic expressions programs and other symbolic expressions as data structures While such expressions can be encoded as numbers using the technique of arithmetization developed by Kurt Godel such an encoding is not very convenient Instead a new kind of data called S expressions for symbolic expressions is introduced specifically to provide convenient encodings S expressions can be defined by a set of formal inductive axioms analogous to the Peano postulates used to define natural numbers 7 0 7 1 John McCarthy History of Lisp PDF Artificial Intelligence Laboratory Stanford University 12 February 1979 To use functions as arguments one needs a notation for functions and it seemed natural to use the l notation of Church 1941 I didn t understand the rest of his book so I wasn t tempted to try to implement his more general mechanism for defining functions Church used higher order functionals instead of using conditional expressions Conditional expressions are much more readily implemented on computers One mathematical consideration that influenced LISP was to express programs as applicative expressions built up from variables and constants using functions I considered it important to make these expressions obey the usual mathematical laws allowing replacement of expressions by expressions giving the same value The motive was to allow proofs of properties of programs using ordinary mathematical methods This is only possible to the extent that side effects can be avoided Unfortunately side effects are often a great convenience when computational efficiency is important and functions with side effects are present in LISP However the so called pure LISP is free of side effects and Cartwright 1976 and Cartwright and McCarthy 1978 show how to represent pure LISP programs by sentences and schemata in first order logic and prove their properties Free variables In all innocence James R Slagle 英语 James Robert Slagle programmed the following LISP function definition and complained when it didn t work right In modern terminology lexical scoping was wanted and dynamic scoping was obtained I must confess that I regarded this difficulty as just a bug and expressed confidence that Steve Russell would soon fix it He did fix it but by inventing the so called FUNARG device that took the lexical environment along with the functional argument Similar difficulties later showed up in Algol 60 and Russell s turned out to be one of the more comprehensive solutions to the problem While it worked well in the interpreter comprehensiveness and speed seem to be opposed in compiled code and this led to a succession of compromises the interested reader is referred to Moses 1970 as a place to start David Turner 英语 David Turner computer scientist Some History of Functional Programming Languages PDF 2021 10 25 原始内容 PDF 存档于2020 04 15 The data on which LISP works is the S language The M language defines computations on S expressions This is computationally complete McCarthy 1960 Sect 6 showed an arbitrary flowchart can be coded as mutually recursive functions The M language of McCarthy 1960 is first order as there is no provision to pass a function as argument or return a function as result However McCarthy shows that M language expressions and functions can be easily encoded as S expressions and then defines in the M language functions eval and apply that correctly interpret these S expressions Thus LISP allows meta programming that is treating program as data and vice versa by appropriate uses of eval and quote The 1960 paper gives the impression quite strongly that McCarthy saw this as removing any limitation stemming from the M Language itself being first order It was originally intended that people would write programs in the M language in an Algol like notation In practice LISP programmers wrote their code directly in the S language form and the M language became a kind of ghost that hovered in the background theoretically important but nobody used it In LISP 1 5 McCarthy et al 1962 atoms acquired property lists which serve several purposes and numbers appeared as another kind of atom along with basic arithmetic functions LISP was not based on the lambda calculus despite using the word LAMBDA to denote functions At the time he invented LISP McCarthy was aware of Church 1941 but had not studied it The theoretical model behind LISP was Kleene s theory of first order recursive functions McCarthy made these statements or very similar ones in a contribution from the floor at the 1982 ACM symposium on LISP and functional programming in Pittsburgh No written version of this exists as far as know The M language was first order as already noted but you could pass a function as a parameter by quotation i e as the S expression which encodes it Unfortunately this gives the wrong binding rules for free variables dynamic instead of lexicographic McCarthy 1978 reports that this problem wrong binding for free variables showed up very early in a program of James Slagle At first McCarthy assumed it was a bug and expected it to be fixed but it actually springs from something fundamental that meta programming is not the same as higher order programming Various devices were invented to get round this FUNARG problem as it became known Not until SCHEME Sussman 1975 did versions of LISP with default static binding appear Today all versions of LISP are lambda calculus based The Top Programming Languages in Artificial Intelligence Artificial Intelligence APRO 2021 02 15 原始内容存档于2020 10 30 9 0 9 1 9 2 John McCarthy Recursive functions of symbolic expressions and their computation by machine Part I PDF Communications of the ACM ACM New York NY USA 1960 3 4 184 195 doi 10 1145 367177 367199 A conditional expression has the form p sub 1 sub e sub 1 sub p sub n sub e sub n sub where the p s are propositional expressions and the e s are expressions of any kind It may be read If p sub 1 sub then e sub 1 sub otherwise if p sub 2 sub then e sub 2 sub otherwise if p sub n sub then e sub n sub or p sub 1 sub yields e sub 1 sub p sub n sub yields e sub n sub I sent a proposal for conditional expressions to a CACM forum on what should be included in Algol 60 Because the item was short the editor demoted it to a letter to the editor for which CACM subsequently apologized The notation given here was rejected for Algol 60 because it had been decided that no new mathematical notation should be allowed in Algol 60 and everything new had to be English The if then else that Algol 60 adopted was suggested by John Backus John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 ISBN 0 262 13011 4 The conditional expression p sub 1 sub e sub 1 sub p sub n sub e sub n sub is translated into COND p sub 1 sub sup sup e sub 1 sub sup sup p sub n sub sup sup e sub n sub sup sup 10 0 10 1 John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 ISBN 0 262 13011 4 Mathematically it is possible to have functions as arguments of other functions For example in arithmetic one could define a function operate op a b where op is a functional argument that specifies which arithmetic operation is to be performed on a and b In LISP functional arguments are extremely useful A very important function with a functional argument is u maplist u Its M expression definition is maplist x fn null x NIL T cons fn x maplist cdr x fn The functional argument is of course a function translated into an S expression It is bound to the variable u fn u and is then used whenever u fn u is mentioned as a function The S expression for u maplist u itself is as follows MAPLIST LAMBDA X FN COND NULL X NIL T CONS FN X MAPLIST CDR X FN Using u maplist u we define u change u by change a maplist a l j cons car j X This is not a valid M expression as defined syntactically in section 1 5 because a function appears where a form is expected This can be corrected by modifying the rule defining an argument so as to include functional arguments lt argument gt lt form gt lt function gt We also need a special rule to translate functional arguments into S expression If fn is a function used as an argument then it is translated into FUNCTION fn Example CHANGE LAMBDA A MAPLIST A FUNCTION LAMBDA J CONS CAR J QUOTE X An examination of evalquote shows that QUOTE will work instead of FUNCTION provided that there are no free variables present Special Operator FUNCTION Common Lisp HyperSpec Syntax function name functionArguments and Values name a function name or lambda expression function a function object Description The value of function is the functional value of name in the current lexical environment Notes The notation i name i may be used as an abbreviation for function i name i Function FUNCALL Common Lisp HyperSpec Syntax funcall function amp rest args result Arguments and Values function a function designator args arguments to the function results the values returned by the function Description funcall applies function to args If function is a symbol it is coerced to a function as if by finding its functional value in the global environment John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 09 23 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 A function can be simply a name In this case its meaning must be previously understood A function may be defined by using the lambda notation and establishing a correspondence between the arguments and the variables used in a form If the function is recursive it must be given a name by using a label When a symbol stands for a function the situation is similar to that in which a symbol stands for an argument When a function is recursive it must be given a name This is done by means of the form LABEL which pairs the name with the function definition on the a list The name is then bound to the function definition just as a variable is bound to its value In actual practice LABEL is seldom used It is usually more convenient to attach the name to the definition in a uniform manner This is done by putting on the property list of the name the symbol EXPR followed by the function definition The pseudo function u define u used at the beginning of this section accomplishes this When u apply u interprets a function represented by an atomic symbol it searches the p list of the atomic symbol before searching the current a list Thus a u define u will override a LABEL The fact that most functions are constants defined by the programmer and not variables that are modified by the program is not due to any weakness of the system On the contrary it indicates a richness of the system which we do not know how to exploit very well Paul Graham Revenge of the Nerds 2013 03 14 原始内容存档于2019 06 07 Chisnall David Influential Programming Languages Part 4 Lisp 2011 01 12 2021 10 24 原始内容存档于2021 03 01 Jones Robin Maynard Clive Stewart Ian The Art of Lisp Programming Springer Science amp Business Media December 6 2012 2 ISBN 9781447117193 John McCarthy Recursive functions of symbolic expressions and their computation by machine Part I PDF Communications of the ACM ACM New York NY USA 1960 3 4 184 195 2021 09 23 doi 10 1145 367177 367199 原始内容 PDF 存档于2021 02 19 In this article we first describe a formalism for defining functions recursively Next we describe S expressions and S functions give some examples and then describe the universal S function apply which plays the theoretical role of a universal Turing machine and the practical role of an interpreter Then we describe the representation of S expressions in the memory of the IBM 704 by list structures similar to those used by Newell Shaw 英语 Cliff Shaw and Simon and the representation of S functions by program Then we mention the main features of the LISP programming system for the IBM 704 Next comes another way of describing computations with symbolic expressions and finally we give a recursive function interpretation of flow charts We shall need a number of mathematical ideas and notations concerning functions in general Most of the ideas are well known but the notion of conditional expression is believed to be new and the use of conditional expressions permits functions to be defined recursively in a new and convenient way We shall first define a class of symbolic expressions in terms of ordered pairs and lists Then we shall define five elementary functions and predicates and build from them by composition conditional expressions and recursive definitions an extensive class of functions of which we shall give a number of examples We shall then show how these functions themselves can be expressed as symbolic expressions and we shall define a universal function apply that allows us to compute from the expression for a given function its value for given arguments Finally we shall define some functions with functions as arguments and give some useful examples The LISP programming system is a system for using the IBM 704 computer to compute with symbolic information in the form of S expressions The basis of the system is a way of writing computer programs to evaluate S functions In addition to the facilities for describing S functions there are facilities for using S functions in programs written as sequences of statements along the lines of FORTRAN or ALGOL There are a number of ways of defining functions of symbolic expressions which are quite similar to the system we have adopted Each of them involves three basic functions conditional expressions and recursive function definitions but the class of expressions corresponding to S expressions is different and so are the precise definitions of the functions We shall describe one of these variants called linear LISP Since both the usual form of computer program and recursive function definitions are universal computationally it is interesting to display the relation between them The translation of recursive symbolic functions into computer programs was the subject of the rest of this report In this section we show how to go the other way at least in principle Michael J Fischer 英语 Michael J Fischer Lambda Calculus Schemata PDF LISP AND SYMBOLIC COMPUTATION An International Journal 6 259 288 1993 2021 11 10 原始内容 PDF 存档于2022 03 02 Two general approaches were taken in order to have programming languages with fully specified semantics i Better specification methods were developed that were adequate to fully describe existing large programming languages such as PL 1 ii New languages were developed with clean mathematical structure that were more amenable to formal description McCarthy pioneered the latter approach in basing the LISP 1 5 programming language on a simpler functional language sometimes called pure LISP or M expressions that was defined in a mathematical style independent of a particular machine or implementation Pure LISP allows the definition and evaluation of functions over S expressions The lambda notation for functional abstraction is borrowed from Church s lambda calculus but otherwise there is little similarity between the two systems Pure LISP has no higher order functions and call by value evaluation order is implicitly assumed Two special constructs conditional expressions and the label operator allow recursive functions to be defined Limited as it is pure LISP is nevertheless powerful enough to express all partial recursive functions and hence provides an adequate basis for a theory of computation The LISP 1 5 programming language extends pure LISP in many ways that make it more useful in practice but at the same time tend to destroy its clean mathematical properties Its semantics is defined by an interpreter written in a mixture of pure LISP and English The distinction between programs and data is blurred Higher order functions assignment and a global symbol table are added CGOL Algol like language that compiles into Common Lisp John McCarthy History of Lisp PDF Artificial Intelligence Laboratory Stanford University 12 February 1979 The programs to be hand compiled were written in an informal notation called M expressions 英语 M expression intended to resemble FORTRAN as much as possible Besides FORTRAN like assignment statements and go tos the language allowed conditional expressions and the basic functions of LISP Allowing recursive function definitions required no new notation from the function definitions allowed in FORTRAN I only the removal of the restriction as I recall unstated in the FORTRAN manual forbidding recursive definitions The M notation also used brackets instead of parentheses to enclose the arguments of functions in order to reserve parentheses for list structure constants It was intended to compile from some approximation to the M notation but the M notation was never fully defined because representing LISP functions by LISP lists became the dominant programming language when the interpreter later became available A machine readable M notation would have required redefinition because the pencil and paper M notation used characters unavailable on the IBM 026 key punch 英语 Keypunch The READ and PRINT programs induced a de facto standard external notation for symbolic information e g representing x 3y z by PLUS X TIMES 3 Y Z and x P x Q x y by ALL X OR P X Q X Y Stoyan Herbert Early LISP history 1956 1959 LFP 84 Proceedings of the 1984 ACM Symposium on LISP and functional programming Association for Computing Machinery 307 1984 08 06 doi 10 1145 800055 802047 原始内容存档于2005 04 05 As far as we know the first universal function was indeed apply eval was not present at all or not seen to be important When McCarthy was working on this function S Russel saw it and suggested translating it by hand as he had done so often and adding it to the program system McCarthy recalls this EVAL was written and published in the paper and Steve Russell said look why don t I program this EVAL and you remember the interpreter and I said to him ho ho you re confusing theory with practice this EVAL is intended for reading not for computing But he went ahead and did it That is he compiled the EVAL in my paper into 704 machine code fixing bugs and then advertised this as a LISP interpreter which it certainly was so at that point LISP had essentially the form that it has today the S expression form John McCarthy History of Lisp PDF Artificial Intelligence Laboratory Stanford University 12 February 1979 Another way to show that LISP was neater than Turing machines was to write a universal LISP function and show that it is briefer and more comprehensible than the description of a universal Turing machine This was the LISP function eval e a which computes the value of a LISP expression e the second argument a being a list of assignments of values to variables a is needed to make the recursion work Writing eval required inventing a notation representing LISP functions as LISP data and such a notation was devised for the purposes of the paper with no thought that it would be used to express LISP programs in practice Logical completeness required that the notation used to express functions used as functional arguments be extended to provide for recursive functions and the LABEL notation was invented by Nathaniel Rochester for that purpose S R Russell noticed that eval could serve as an interpreter for LISP promptly hand coded it and we now had a programming language with an interpreter Once the eval interpreter was programmed it became available to the programmer and it was especially easy to use because it interprets LISP programs expressed as LISP data In particular eval made possible FEXPRS and FSUBRS which are functions that are not given their actual arguments but are given the expressions that evaluate to the arguments and must call eval themselves when they want the expressions evaluated The main application of this facility is to functions that don t always evaluate all of their arguments they evaluate some of them first and then decide which others to evaluate This facility resembles Algol s call by name but is more flexible because eval is explicitly available A first order logic treatment of extensional FEXPRs and FSUBRs now seems possible John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 ISBN 0 262 13011 4 A form is an expression that can be evaluated A form that is merely a constant has that constant as its value If a form is a variable then the value of the form is the S expression that is bound to that variable at the time when we evaluate the form A function can be simply a name In this case its meaning must be previously understood A function may be defined by using the lambda notation and establishing a correspondence between the arguments and the variables used in a form If the function is recursive it must be given a name by using a label An interpreter or universal function is one that can compute the value of any given function applied to its arguments when given a description of that function Of course if the function that is being interpreted has infinite recursion the interpreter will recur infinitely also We are now in a position to define the universal LISP function u evalqyote u fn args When u evalquote u is given a function and a list of arguments for that function it computes the value of the function applied to the arguments LISP functions have S expressions as arguments In particular the argument u fn u of the function u evalquote u must be an S expression Since we have been writing functions as M expressions it is necessary to translate them into S expressions u evalquote u is defined by using two main functions called u eval u and u apply u u apply u handles a function and its arguments while u eval u handles forms Each of these functions also has another argument that is used as an association list for storing the values of bound variables and function names A variable is a symbol that is used to represent an argument of a function The formalism for variables in LISP is the Church lambda notation The part of the interpreter that binds variables is called u apply u When u apply u encounters a function beginning with LAMBDA the list of variables is paired with the list of arguments and added to the front of the a list During the evaluation of the function variables may be encountered They are evaluated by looking them up on the a list If a variable has been bound several times the last or most recent value is used The part of the interpreter that does this is called u eval u The following example will illustrate this discussion Suppose the interpreter is given the following doublet fn tt tt LAMBDA X Y CONS X Y args tt tt A B u evalquote u will give these arguments to u apply u Look at the universal function of Section I apply LAMBDA X Y CONS X Y A B NIL u apply u will bind the variables and give the function and a list to u eval u eval CONS X Y X A Y B u eval u will evaluate the variables and give it to u cons u cons A B A B The actual interpreter skips one step required by the universal function namely apply CONS A B X A Y B It is sometimes assumed that a constant stands for itself as opposed to a variable which stands for something else It seems more reasonable to say that one variable is more nearly constant than another if it is bound at a higher level and changes value less frequently In LISP a variable remains bound within the scope of the LAMBDA that binds it When a variable always has a certain value regardless of the current a list it will be called a constant This is accomplished by means of the property list p list of the variable symbol Every atomic symbol has a p list When the p list contains the indicator APVAL then the symbol is a constant and the next item on the list is the value eval searches p lists before a lists when evaluating variables thus making it possible to set constants An interesting type of constant is one that stands for itself NIL is an example of this It can be evaluated repeatedly and will still be NIL T F NIL and other constants cannot be used as variables The program form has the structure PROG list of program variables sequence of statements and atomic symbols Program variables are treated much like bound variables but they are not bound by LAMBDA The value of each program variable is NIL until it has been set to something else To set a program variable use the form SET To set variable PI to 3 14 write SET OUOTE PI 3 14 SETQ is like SET except that it quotes its first argument Thus SETQ PI 3 14 SETQ is usually more convenient SET and SETQ can change variables that are on the a list from higher level functions The value of SET or SETQ is the value of its second argument Every atomic symbol has a property list When an atomic symbol is read in for the first time a property list is created for it A property list is characterized by having the special constant 77777 sub 8 sub i e minus 1 as the first element of the list The rest of the list contains various properties of the atomic symbol Each property is preceded by an atomic symbol which is called its indicator Some of the indicators are PNAME the BCD 英语 BCD character encoding print name of the atomic symbol for input output use EXPR S expression defining a function whose name is the atomic symbol on whose property list the EXPR appears SUBR Function defined by a machine language subroutine APVAL Permanent value for the atomic symbol considered as a variable The atomic symbol NIL has two things on its property list its PNAME and an APVAL that gives it a value of NIL Its property list looks like this 1 gt APVAL gt gt PNAME gt V V V NIL The indicator EXPR points to an S expression defining a function The function define puts EXPR s on property lists After defining u ff u its property list would look like this 1 gt EXPR gt gt PNAME gt V V LAMBDA gt gt V X COND gt FF An indicator on a property list that does not have a property following it is called a flag Numbers are represented by a type of atomic symbol in LISP This word consists of a word with 1 in the address certain bits in the tag which specify that it is a number and what type it is and a pointer to the number itself in the decrement of this word Unlike atomic symbols numbers are not stored uniquely For example the decimal number 15 is represented as follows 1 1 gt 000000000017 u special u x SUBR pseudo functionThe list x contains the names of variables that are to be declared SPECIAL u common u x SUBR pseudo functionThe list x contains the names of variables that are to be declared COMMON PROG feature is an FSUBR coded into the system When a u set u or a u setq u is encountered the name of the variable is located on the a list The value of the variable or u cdr u of the pair is actually replaced with the new value The following points should be noted concerning declared variables 1 Program variables follow the same rules as l variables do a If a variable is purely local it need not be declared b Special variables can be used as free variables in compiled functions They may be set at a lower level than that at which they are bound c Common program variables maintain complete communication between compiled programs and the interpreter 2 u set u as distinct from u setq u can only be used to set common variables 22 0 22 1 John McCarthy Robert Brayton Daniel Edwards Phyllis Fox 英语 Phyllis Fox Louis Hodes 英语 Louis Hodes David Luckham 英语 David Luckham Klim Maling David Park 英语 David Park computer scientist Steve Russell LISP I Programmers Manual PDF Boston Massachusetts Artificial Intelligence Group M I T Computation Center 英语 M I T Computation Center and Research Laboratory March 1960 2021 09 23 原始内容 PDF 存档于2022 04 02 Timothy P Hart Michael I Levin AI Memo 39 The new compiler PDF Timothy P Hart Michael I Levin LISP 1 5 compiler Hart Timothy P AIM 057 MACRO Definitions for LISP Timothy P Hart October 1963 hdl 1721 1 6111 Gerald J Sussman Guy L Steele Jr The Revised Report on SCHEME A Dialect of LISP 1978 2021 10 26 原始内容存档于2022 04 06 SCHEME is a dialect of LISP It is an expression oriented applicative order interpreter based language which allows one to manipulate programs as data It differs from most current dialects of LISP in that it closes all lambda expressions in the environment of their definition or declaration rather than in the execution environment This has the consequence that variables are normally lexically scoped as in ALGOL However in contrast with ALGOL SCHEME treats procedures as a first class data type They can be the values of variables the returned values of procedures and components of data structures Another difference from LISP is that SCHEME is implemented in such a way that tail recursions execute without net growth of the interpreter stack The effect of this is that a procedure call behaves like a GOTO and thus procedure calls can be used to implement iterations as in PLASMA The 36 bit word size of the PDP 6 PDP 10 was influenced by the usefulness of having two Lisp 18 bit pointers in a single word Peter J Hurley The History of TOPS or Life in the Fast ACs Newsgroup alt folklore computers 18 October 1990 2021 10 24 Usenet 84950 tut cis ohio state edu 原始内容存档于2013 05 28 The PDP 6 project started in early 1963 as a 24 bit machine It grew to 36 bits for LISP a design goal Gerald Jay Sussman Terry Winograd Micro planner Reference Manual AI Memo No 203 MIT Project MAC 1970 Micro Planner is an implementation of a subset of Cal Hewitt s language PLANNER by Gerald Jay Sussman Terry Winograd and Eugene Charniak on the AI group computer in LISP Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 In this history of the evolution of Lisp we have seen that Lisp seems to have a more elaborate and complex history than languages with wider usage It would seem that almost every little research group has its own version of Lisp and there would appear to be as many Lisps as variations on language concepts It is natural to ask what is so special or different about Lisp that explains it There are six basic reasons Its theoretical foundations Lisp was founded on the footing of recursive function theory and the theory of computability The work on Scheme aligned it with Church s lambda calculus and denotational semantics Its purest form is useful for mathematical reasoning and proof Its expressiveness Lisp has proved itself concerned more with expressiveness than anything else Its malleability It is easy with Lisp to experiment with new language features because it is possible to extend Lisp in such a way that the extensions are indistinguishable to users from the base language Primarily this is accomplished through the use of macros which have been part of Lisp since 1963 Hart 1963 Its interactive and incremental nature It is easy to explore the solutions to programming problems in Lisp because it is easy to implement part of a solution test it modify it change design and debug the changes Its operating system facilities Many Lisp implementations provide facilities reminiscent of operating systems a command processor an automatic storage management facility file management display windows graphics mouse facilities multitasking a compiler an incremental re linker loader a symbolic debugger performance monitoring and sometimes multiprocessing Its people Of course languages do not diversify themselves people diversify languages Lisp is the language of artificial intelligence among other things Another attraction is that Lisp is a language of experts which for our purposes means that Lisp is not a language designed for inexpert programmers to code robust reliable software John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 10 25 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 To define these functions we use the pseudo function u define u A pseudo function is a function that is executed for its effect on the system in core memory as well as for its value u define u causes these functions to be defined and available within the system Its value is a list of the functions defined u define u x EXPR pseudo functionThe argument of u define u x is a list of pairs u sub 1 sub v sub 1 sub u sub 2 sub v sub 2 sub u sub n sub v sub n sub where each u is a name and each v is a l expression for a function For each pair define puts an EXPR on the property list for u pointing to v The function of u define u puts things on at the front of the property list The value of define is the list of u s define x deflist x EXPR u deflist u x ind EXPR pseudo functionThe function u deflist u is a more general defining function Its first argument is a list of pairs as for u define u Its second argument is the indicator that is to be used After u deflist u has been executed with u sub i sub v sub i sub among its first argument the property list of u sub i sub will begin uᵢ gt 1 gt IND gt gt V vᵢ If u deflist u or u define u is used twice on the same object with the same indicator the old value will be replaced by the new one 30 0 30 1 Kent M Pitman 英语 Kent Pitman The Revised Maclisp Manual 1983 2007 2021 10 26 原始内容存档于2022 03 28 DEFUN Special Form DEFUN namespec definitionspec DEFUN offers a way of associating a functional definition with a symbol DEFUN can be used to define both normal functions and special forms fexprs and macros Normal expr or lexpr function definitions br tt tt DEFUN name bvl body If name is a symbol and bvl is a list of symbols which is free of amp keywords to be described below the definition is an expr or lexpr definition In Maclisp this would be essentially equivalent to writing DEFPROP name LAMBDA bvl body EXPR Note also that the keyword EXPR is used for both expr and lexpr definitions The only distinction between expr and lexpr definitions is whether the bvl is a symbol or a list but they are specified in the same way and looked up from the same property A fexpr 英语 fexpr is a function for which the formal parameters are not evaluated The form of a fexpr definition is DEFUN name FEXPR sym body The lambda expression which describes a fexpr should expect to receive exactly one argument which will be the list of unevaluated arguments given in the call to the fexpr so usually there is only one bound variable sym in the bound variable list DEFUN can also be used to instantiate a MACRO definition The syntax for a macro definition is DEFUN name MACRO sym body where sym will become bound to the whole macro form to be expanded including the name Note that this argument convention is different than fexprs which only receive the cdr of the call form DEFUN was introduced into Maclisp in March 1969 Although now it is recognized as the standard function defining form because it shields the user from the implementational details of how the function is defined DEFPROP Function DEFPROP sym val indicator Gives sym a property called indicator with value val The arguments are not evaluated DEFPROP should not be used imbedded in other expressions It is intended to occur at toplevel to assign properties that are set up once and never changed In other places use PUTPROP with three quoted arguments 请检查 date 中的日期值 帮助 Gerald J Sussman Guy L Steele Jr Scheme An Interpreter for Extended Lambda Calculus 维基文库 1975 英文 DEFINE This is analogous to the MacLISP DEFUN primitive but note that the LAMBDA must appear explicitly It is used for defining a function in the global environment permanently as opposed to LABELS see below which is used for temporary definitions in a local environment DEFINE takes a name and a lambda expression it closes the lambda expression in the global environment and stores the closure in the LISP value cell of the name which is a LISP atom Gerald J Sussman Guy L Steele Jr The Revised Report on SCHEME A Dialect of LISP 1978 2021 10 26 原始内容存档于2022 04 06 Atoms which are not atomic symbols identifiers evaluate to themselves Typical examples of such atoms are numbers arrays and strings character arrays Symbols are treated as identifiers or variables They may be lexically bound by lambda expressions There is a global environment containing values initially have as their values primitive operations such as for example CAR CONS and PLUS SCHEME differs from most LISP systems in that the atom CAR is not itself an operation in the sense of being an invocable object e g a valid first argument to APPLY but only has one as a value when considered as an identifier Richard P Gabriel 英语 Richard P Gabriel Kent M Pitman 英语 Kent M Pitman Technical Issues of Separation in Function Cells and Value Cells Lisp and Symbolic Computation June 1988 1 1 81 101 2021 11 01 S2CID 26716515 doi 10 1007 bf01806178 原始内容存档于2006 11 13 In 1981 the emerging Common Lisp community turned to Scheme for some of its motivation and inspiration Steele 1984 Adopting lexical scoping proved one of the most important decisions the Common Lisp group ever made One aspect of Scheme that was not adopted however was a single namespace for functions and values along with uniform evaluation rules for expressions in function and argument positions within the language In this paper we shall refer to two abstract dialects of Lisp called Lisp1 and Lisp2 Lisp1 has a single namespace that serves a dual role as the function namespace and value namespace that is its function namespace and value namespace are not distinct In Lisp1 the functional position of a form and the argument positions of forms are evaluated according to the same rules Scheme Rees 1986 and the language being designed by the EuLisp group Padget 1986 are Lisp1 dialects Lisp2 has distinct function and value namespaces In Lisp2 the rules for evaluation in the functional position of a form are distinct from those for evaluation in the argument positions of the form Common Lisp is a Lisp2 dialect Most Lisp dialects adopted a two namespace approach to the naming problem To some extent this is because most dialects followed Lisp 1 5 McCarthy 1965 or dialects derived from Lisp 1 5 Lisp 1 5 broke symbols into values and functions values were stored on an association list 英语 association list and function on the property lists of symbols Compiled and interpreted code worked in different ways In the interpreter the association list was where all bindings were kept When an identifier was encountered an atomic symbol in Lisp 1 5 terminology it was taken as a variable to be evaluated for its value First the APVAL part of the symbol was interrogated an APVAL was A Permanent system defined VALue stored in a specific place in the symbol Second the association list was searched Finally if no binding was found an error was signaled When a combination was encountered the function position was evaluated differently from other positions First the symbol was interrogated to see whether there was a function definition associated with it then the association list was searched Here we can see two namespaces at work though nonsymbol variables were treated somewhat uniformly Lisp 1 5 did not have lexical variables in interpreted code when there were no function definitions associated with a symbol there was one namespace which was explicitly represented by the association list Compiled code worked a slightly different way and from its internals we can see where the two namespaces came about in descendants of Lisp 1 5 The Lisp 1 5 compiler supported common and special variables A common variable enabled compiled and interpreted code to communicate with each other A common variable was bound on an explicit association list to evaluate such a variable a call to EVAL was emitted to determine the value A special variable was the compiler s modeling of free variables and closely matched what is now called shallow binding Ordinary variables compiled into what we have termed lexical variables Thus we see all of the components of the two namespace world in Lisp 1 5 along with some of the components of the one namespace world It seems that the designers of Lisp 1 5 thought of function names as being different from variable names the Lisp 1 5 interpreter looked at the property list of the named atomic symbol first and so it can be argued that a function was considered a property of a symbol The designers used the terminology that a symbol stands for a function while a variable refers to a value Lisp for the PDP 6 at MIT adopted the style of the Lisp 1 5 special variables for dynamic binding in both compiled and interpreted code thereby eliminated common variables Compilers were still written that were to try to interpret special variables as lexical variables in as many places as possible The value of a symbol was stored in the value cell of the symbol and the function remained on the property list as it did in Lisp 1 5 MacLisp Pitman 1983 is a direct descendant of the PDP 6 Lisp and is a Lisp2 dialect MacLisp uses a sophisticated form of link table which is made possible by the separation of namespaces In particular function defining functions have controlled access into the places where functions are stored so that the link tables can be correctly maintained Common Lisp was the result of a compromise between a number of dialects of Lisp most of them descendants of MacLisp all of them Lisp2s A free variable in Common Lisp is currently taken to be a dynamic rather than a lexical reference because there is no global lexical environment in Common Lisp In this code DEFUN PLUS X Y X Y DEFUN SOMEWHAT MORE THAN X PLUS X SOMEWHAT The reference to SOMEWHAT is special dynamic On the surface in Lisp1 the reference to PLUS is free also and thus it is special dynamic When a variable is declared special a free reference to it is to the most recent dynamically bound value for it all bindings of it become special dynamic bindings When a variable is declared constant free references to it are to its permanent constant value and compilers are free to fold that constant into the code they emit We introduce the concept of global variables when a variable is global free references to it are to the value cell of the symbol named by the variable and all bindings of it are still lexical To avoid a compiler warning for free use of a variable like SOMEWHAT the variable is declared SPECIAL In order to have compilers for Lisp1 not to warn about the free use of PLUS it would be unfortunate to have to declare it SPECIAL As noted in Common Lisp the default for free variable references is SPECIAL that is a free variable reference is taken to be a special variable reference If the default in Lisp1 were that free variable references were global lexical then it would make sense for a compiler not to warn about such free variable references John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 10 25 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 The over all design of the LISP Programming System is the work of John McCarthy and is based on his paper Recursive Functions of Symbolic Expressions and Their Computation by Machine which was published in Communications of the ACM April 1960 This manual was written by Michael I Levin The interpreter was programmed by Stephen B Russell and Daniel J Edwards The print and read programs were written by John McCarthy Klim Maling Daniel J Edwards and Paul W Abrahams The garbage collector and arithmetic features Were written by Daniel J Edwards The compiler and assembler were written by Timothy P Hart and Michael I Levin An earlier compiler was written by Robert Brayton The LISP 1 Programmer s Manual March 1 1960 was written by Phyllis A Fox Additional programs and suggestions were contributed by the following members of the Artificial Intelligence Group of the Research Laboratory of Electronics Marvin L Minsky Bertram Raphael Louis Hodes David M R Park David C Luckham Daniel G Bobrow James R Slagle and Nathaniel Rochester Lynn H Quam Stanford LISP 1 6 Manual PDF 1969 2021 12 29 原始内容 PDF 存档于2022 03 03 The STANFORD A I LISP 1 6 System was originally an adaptation of one developed by the Artificial Intelligence Project a t M I T Since 1966 that system has been largely rewritten by John Allen and the author Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 At Stanford in the 1960s an early version of MacLisp was adapted for their PDP 6 this Lisp was called Lisp 1 6 Quam 1972 The early adaptation was rewritten by John Allen and Lynn Quam later compiler improvements were made by Whit Diffie Lisp 1 6 disappeared during the mid 1970s one of the last remnants of the Lisp 1 5 era The original Edinburgh LCF 1977 2021 10 10 原始内容存档于2021 10 10 Maclisp Reference Manual March 3 1979 2021 10 29 原始内容存档于2022 03 28 Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 By 1964 a version of Lisp 1 5 was running in the Electrical Engineering Department at MIT on an IBM 7094 computer running the Compatible Time Sharing System CTSS This Lisp and Basic PDP 1 Lisp were the main influences on the PDP 6 Lisp PDP 6 Lisp 1967 implemented by DEC and some members of MIT s Tech Model Railroad Club in the spring of 1964 This Lisp was the first program written on the PDP 6 Also this Lisp was the ancestor of MacLisp the Lisp written to run under the Incompatible Timesharing System ITS Eastlake 1968 1972 at MIT on the PDP 6 and later on the PDP 10 In 1965 virtually all of the Lisps in existence were identical or differed only in trivial ways After 1965 or more precisely after MacLisp and BBN Lisp diverged from each other there came a plethora of Lisp dialects MacLisp was the primary Lisp dialect at the MIT AI Lab from the late 1960s until the early 1980s Other important Lisp work at the Lab during this period included Lisp Machine Lisp later named Zetalisp and Scheme MacLisp is usually identified with the PDP 10 computer but MacLisp also ran on another machine the Honeywell 6180 under the Multics operating system Organick 1972 37 0 37 1 37 2 37 3 John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 10 25 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 The Artificial Intelligence Project at Stanford University has produced a version of LISP 1 5 to be distributed by SHARE In the middle of February 1965 the system is complete and is available from Stanford The system should be available from SHARE by the end of March 1965 u Evalquote u is available to the programmer as a LISP function thus one may now write EVALQUOTE APPEND A B C D rather than EVAL QUOTE APPEND A B C D NIL should one desire to do so Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 A key difference between MacLisp and Interlisp was the approach to syntax MacLisp favored the pure list style using EVAL as the top level Interlisp along with Lisp 1 5 used EVALQUOTE To concatenate the lists BOAT AIRPLANE SKATEBOARD and CAR TRUCK in MacLisp one would type this expression to EVAL APPEND QUOTE BOAT AIRPLANE SKATEBOARD QUOTE CAR TRUCK or using the syntactic abbreviation x for quote x APPEND BOAT AIRPLANE SKATEBOARD CAR TRUCK The result would of course be BOAT AIRPLANE SKATEBOARD CAR TRUCK In Lisp 1 5 one would type an expression actually two expressions like this to EVALQUOTE APPEND BOAT AIRPLANE SKATEBOARD CAR TRUCK The first expression denotes a function and the second is a list of arguments The quote in the name EVALQUOTE signifies the implicit quoting of the arguments to the function applied MacLisp forked off and used EVAL exclusively as a top level interface BBN Lisp and thus Interlisp accommodated both if the first input line contained a complete form and at least one character of a second form then BBN Lisp finished reading the second form and used the EVALQUOTE interface for that interaction otherwise it read exactly one form and used the EVAL interface for that interaction The phrase quoting arguments actually is misleading and imprecise It refers to the actions of a hypothetical preprocessor that transforms the input from a form like APPEND BOAT AIRPLANE SKATEBOARD CAR TRUCK to one like APPEND QUOTE BOAT AIRPLANE SKATEBOARD QUOTE CAR TRUCK before evaluation is performed A similar confusion carried over into the description of the so called FEXPR or special form In some texts on Lisp one will find descriptions of special forms that speak of a special form quoting its arguments when in fact a special form has a special rule for determining its meaning and that rule involves not evaluating some forms Pitman 1980 McCarthy McCarthy 1981 noted that the original Lisp interpreter was regarded as a universal Turing machine It could perform any computation given a set of instructions a function and the initial input on its tape arguments Thus it was intended that APPEND BOAT AIRPLANE SKATEBOARD CAR TRUCK be regarded not as a syntactically mutated version of APPEND QUOTE BOAT AIRPLANE SKATEBOARD QUOTE CAR TRUCK but as a function and separately a literal list of arguments In hindsight we see that the EVALQUOTE top level might better have been called the APPLY top level making it pleasantly symmetrical to the EVAL top level the BBN Lisp documentation brought out this symmetry explicitly Indeed EVALQUOTE would have been identical to the function APPLY in Lisp 1 5 if not for these two differences a in Lisp 1 5 APPLY took a third argument an environment regarded nowadays as something of a mistake that resulted in dynamic binding rather than the lexical scoping needed for a faithful reflection of the lambda calculus and b EVALQUOTE is capable of handling special forms as a sort of exception McCarthy 1962 Nowadays such an exception is referred to as a kluge Raymond 1991 Note however that MacLisp s APPLY function supported this same kluge Teitelman Warren InterLisp Reference Manual PDF 1974 2021 10 29 原始内容 PDF 存档于2022 03 03 Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 In 1963 L Peter Deutsch at that time a high school student implemented a Lisp similar to Lisp 1 5 on the PDP 1 at Bolt Beranek and Newman BBN Deutsch 1964 This Lisp was called Basic PDP 1 Lisp At BBN a successor to Basic PDP 1 Lisp was implemented on the PDP 1 and an upward compatible version patterned after Lisp 1 5 on the MIT CTSS system was implemented on the Scientific Data Systems 940 SDS 940 by Daniel Bobrow and D L Murphy A further upward compatible version was written for the PDP 10 by Alice Hartley and Murphy and this Lisp was called BBN Lisp Teitelman 1971 In 1973 not long after the time that SDS was acquired by Xerox and renamed Xerox Data Systems the maintenance of BBN Lisp was shared by BBN and Xerox Palo Alto Research Center and the name of the Lisp was changed to Interlisp Teitelman 1974 Interlisp and BBN Lisp before it introduced many radical ideas into Lisp programming style and methodology The most visible of these ideas are embodied in programming tools such as the spelling corrector the file package DWIM CLISP the structure editor and MASTERSCOPE The origin of these ideas can be found in Warren Teitelman s Ph D dissertation on man computer symbiosis Teitelman 1966 In particular it contains the roots of structure editing as opposed to text or tape editing Rudloe 1962 breakpointing advice and CLISP CLISP Conversational LISP was a mixed ALGOL like and English like syntax embedded within normal Interlisp syntax Here is a valid definition of FACTORIAL written in lnterlisp CLISP syntax DEFINEQ FACTORIAL LAMBDA N IF N 0 THEN 1 ELSE N FACTORIAL N I Package lang lisp impl xlisp cs cmu edu 2021 10 26 原始内容存档于2022 03 31 Outils de generation d interfaces etat de l art et classification by H El Mrabet PDF 2021 10 24 原始内容 PDF 存档于2017 10 01 Gerald J Sussman Guy L Steele Jr SCHEME An Interpreter for Extended Lambda Calculus 1975 2021 10 27 原始内容存档于2022 04 17 Inspired by ACTORS Greif and Hewitt Smith and Hewitt we have implemented an interpreter for a LISP like language SCHEME based on the lambda calculus Church but extended for side effects multiprocessing and process synchronization The purpose of this implementation is tutorial We wish to alleviate the confusion caused by Micro PLANNER 英语 Planner programming language CONNIVER etc by clarifying the embedding of non recursive control structures in a recursive host language like LISP explain how to use these control structures independent of such issues as pattern matching and data base manipulation have a simple concrete experimental domain for certain issues of programming semantics and style 42 0 42 1 Guy L Steele Jr Scott Fahlman 英语 Scott Fahlman Richard P Gabriel 英语 Richard P Gabriel David A Moon 英语 David A Moon Daniel Weinreb 英语 Daniel Weinreb Common Lisp the Language 1st edition 1984 ISBN 0 932376 41 X 引文格式1维护 冗余文本 link Steele Guy L Jr Purpose Common Lisp the Language 2nd edition 1990 2021 10 24 ISBN 0 13 152414 3 原始内容存档于2021 03 08 引文格式1维护 冗余文本 link Kantrowitz Mark Margolin Barry History Where did Lisp come from FAQ Lisp Frequently Asked Questions 2 7 20 February 1996 2021 10 24 原始内容存档于2021 03 08 ISO IEC 13816 1997 Iso org 2007 10 01 2013 11 15 原始内容存档于2016 07 30 ISO IEC 13816 2007 Iso org 2013 10 30 2013 11 15 原始内容存档于2016 07 30 47 0 47 1 IEEE Scheme IEEE 1178 1990 IEEE Standard for the Scheme Programming Language 27 August 2019 原始内容存档于2021 03 04 X3J13 Charter 2021 10 24 原始内容存档于2021 03 05 The Road To Lisp Survey 2006 10 13 原始内容存档于2006 10 04 Trends for the Future Faqs org 2013 11 15 原始内容存档于2013 06 03 Common Lisp Implementations The Revised5 Report on the Algorithmic Language Scheme schemers org 1998 2021 10 24 原始内容存档于2007 01 05 The Revised6 Report on the Algorithmic Language Scheme 2007 2021 11 04 原始内容存档于2013 06 25 R7RS small language final draft PDF 2022 09 06 Implementations support all or part of R7RS small Why MIT now uses python instead of scheme for its undergraduate CS program cemerick com March 24 2009 November 10 2013 原始内容存档于September 17 2010 Broder Evan The End of an Era mitadmissions org January 8 2008 November 10 2013 原始内容存档于2018 08 21 Axel Haskell Lisp a specification for Bel 页面存档备份 存于互联网档案馆 a new dialect of Lisp Chapter 1 1 2 History ANSI CL Standard 1 页面存档备份 存于互联网档案馆 Clasp is a Common Lisp implementation that interoperates with C and uses LLVM for just in time compilation JIT to native code 2 页面存档备份 存于互联网档案馆 Armed Bear Common Lisp ABCL is a full implementation of the Common Lisp language featuring both an interpreter and a compiler running in the JVM 3 互联网档案馆的存檔 存档日期2018 06 22 Common Lisp Implementations A Survey 4 页面存档备份 存于互联网档案馆 Comparison of actively developed Common Lisp implementations Gerald J Sussman Guy L Steele Jr The First Report on Scheme Revisited 1998 2021 10 28 原始内容存档于2022 04 06 Sussman had just been studying Algol He suggested starting with a lexically scoped dialect of Lisp because that seemed necessary to model the way names could refer to acquaintances in PLASMA Lexical scoping would allow actors and functions to be created by almost identical mechanisms Evaluating a form beginning with the word lambda would capture the current variable lookup environment and create a closure evaluating a form beginning with the word alpha would also capture the current environment but create an actor Message passing could be expressed syntactically in the same way as function invocation The difference between an actor and a function would be detected in the part of the interpreter traditionally known as apply A function would return a value but an actor would never return instead it would typically invoke a continuation another actor that it knew about Our interpreter also provided the necessary primitives for implementing the internal behavior of primitive actors such as an addition operator that could accept two numbers and a continuation actor This led us to three important ideas First we realized that all the patterns of control structure that Hewitt had described in terms of actors could equally well be described by the l calculus Second we realized that the l calculus a small simple formalism could serve as the core of a powerful and expressive programming language Lisp had adopted the l notation for functions but had failed to support the appropriate behavior for free variables The original theoretical core of Lisp was recursion equations not the l calculus Third we realized that in our quest for the ultimate AI language we had come full circle As the MIT school had struggled to find more and more powerful ways to express and manipulate control structure to support heuristic search we had progressed from Lisp to CONVERT to Planner to Conniver to PLASMA to a simple variation of Lisp An In Depth Look at Clojure Collections 页面存档备份 存于互联网档案馆 Retrieved 2012 06 24 Clojure rational 27 August 2019 原始内容存档于2016 01 04 Clojure is a Lisp not constrained by backwards compatibility Script fu In GIMP 2 4 页面存档备份 存于互联网档案馆 Retrieved 2009 10 29 librep 页面存档备份 存于互联网档案馆 at Sawfish Wikia retrieved 2009 10 29 The Jargon File Lisp 2006 10 13 原始内容存档于2021 04 18 John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 10 25 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 Special Forms Normally u eval u evaluates the arguments of a function before applying the function itself Thus if u eval u is given CONS X Y it will evaluate X and Y and then u cons u them But if u eval u is given QUOTE X X should not be evaluated QUOTE is a special form that prevents its argument from being evaluated A special form differs from a function in two ways Its arguments are not evaluated before the special form sees them COND for example has a very special way of evaluating its arguments by using u evcon u The second way which special forms differ from functions is that they may have an indefinite number of arguments Special forms have indicators on their property lists called FEXPR and FSUBR for LISP defined forms and machine language coded forms respectively 72 0 72 1 Guy L Steele Jr Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages ACM 231 270 1993 The use of SETF throughout Common Lisp a later dialect of Lisp and the most popular can be traced through Symbolics Zetalisp and MacLisp to the influence of MIT Lisp Machine Lisp and then back through Greenblatt s proposal to Peter Deutsch and thence to Alan Kay The uniform treatment of access reading and writing of state has made Common Lisp more uniform that it might otherwise be It is no longer necessary to remember both a reader function such as CAR and also a separate writer or update function such as RPLACA nor to remember the order of arguments For RPLACA which comes first the dotted pair or the new value for its car If the general form of a read operation is i f i then the form of the write is setf i f i i newvalue i and that is all the programmer needs to know about reading and writing data Guy L Steele Common Lisp the Language 2nd Edition 1990 ISBN 1 55558 041 6 In describing various features of the Common Lisp language the notions of scope and extent are frequently useful These notions arise when some object or construct must be referred to from some distant part of a program Scope refers to the spatial or textual region of the program within which references may occur Extent refers to the interval of time during which references may occur There are a few kinds of scope and extent that are particularly useful in describing Common Lisp Lexical scope Here references to the established entity can occur only within certain program portions that are lexically that is textually contained within the establishing construct Typically the construct will have a part designated the body and the scope of all entities established will be or include the body Example the names of parameters to a function normally are lexically scoped Indefinite scope References may occur anywhere in any program Dynamic extent References may occur at any time in the interval between establishment of the entity and the explicit disestablishment of the entity As a rule the entity is disestablished when execution of the establishing construct completes or is otherwise terminated Therefore entities with dynamic extent obey a stack like discipline paralleling the nested executions of their establishing constructs Example the with open file construct opens a connection to a file and creates a stream object to represent the connection The stream object has indefinite extent but the connection to the open file has dynamic extent when control exits the with open file construct either normally or abnormally the stream is automatically closed Example the binding of a special variable has dynamic extent Indefinite extent The entity continues to exist as long as the possibility of reference remains An implementation is free to destroy the entity if it can prove that reference to it is no longer possible Garbage collection strategies implicitly employ such proofs Example most Common Lisp data objects have indefinite extent Example the bindings of lexically scoped parameters of a function have indefinite extent By contrast in Algol the bindings of lexically scoped parameters of a procedure have dynamic extent The function definition defun compose f g lambda x funcall f funcall g x when given two arguments immediately returns a function as its value The parameter bindings for f and g do not disappear because the returned function when called could still refer to those bindings Therefore funcall compose sqrt abs 9 0 produces the value 3 0 An analogous procedure would not necessarily work correctly in typical Algol implementations or for that matter in most Lisp dialects In addition to the above terms it is convenient to define dynamic scope to mean indefinite scope and dynamic extent Thus we speak of special variables as having dynamic scope or being dynamically scoped because they have indefinite scope and dynamic extent a special variable can be referred to anywhere as long as its binding is currently in effect The term dynamic scope is a misnomer Nevertheless it is both traditional and useful John McCarthy Paul W Abrahams Daniel J Edwards Timothy P Hart Michael I Levin LISP 1 5 Programmer s Manual PDF 2nd MIT Press 1985 1962 2021 10 25 ISBN 0 262 13011 4 原始内容 PDF 存档于2021 03 02 The variables in a lambda expression are dummy or bound variables because systematically changing them does not alter the meaning of the expression Thus l u v v sup 2 sup u means the same thing as l x y y sup 2 sup x We shall sometimes use expressions in which a variable is not bound by a lambda For example in the function of two variables l x y x sup n sup y sup n sup the variable n is not bound This is called a free variable It may be regarded as a parameter Unless n has been given a value before trying to compute with this function the value of the function must be undefined When the compiler is called upon to compile a function it looks for an EXPR or FEXPR on the property list of the function name The compiler then translates this S expression into an S expression that represents a subroutine in the LISP Assembly Language LAP LAP then proceeds to assemble this program into binary program space Thus an EXPR or an FEXPR has been changed to a SUBR or an FSUBR respectively Free variables in compiled functions must be declared before the function is compiled A variable is bound in a particular function when it occurs in a list of bound variables following the word LAMBDA or PROG Any variable that is not bound is free When a variable is used free it must have been bound by a higher level function If a program is being run interpretively and a free variable is used without having bee bound on a higher level error diagnostic A 8 will occur If the program is being run complied the diagnostic may not occur and the variable may have value NIL There are three types of variables in compiled functions ordinary variables SPECIAL variables and COMMON variables SPECIAL and COMMON variables must be declared before compiling Any variable that is not declared will be considered an ordinary variable When functions are translated into subroutines the concept of a variable is translated into a location where an argument is stored If the variable is an ordinary one then a storage location for it is set up on the push down list Other functions cannot find this private cell making it impossible to use it as a free variable SPECIAL variables have the indicator SPECIAL on their property lists Following the indicator there is a pointer to a fixed cell When this variable is bound the old value is saved on the push down list and the current value is stored in the SPECLAL cell When it is no longer bound the old value must be restored When a function uses this variable free then the quantity in the SPECIAL cell is picked up SPECIAL variables are declared by using the pseudo function u special u a where a is a list of variable names SPECIAL variables are inexpensive and will allow free communication among compiled functions They do not increase run time significantly SPECIAL variables cannot be communicated between the interpreter and compiled functions COMMON variables have the flag COMMON on their property lists however this is only used to inform the compiler that they are COMMON and is not needed at run time COMMON variables are bound on an a list by the compiled functions When they are to be evaluated u eval u is given this a list This happens at run time The use of COMMON variables will slow down any compiled function using them However they do provide complete communication between interpreted and compiled functions COMMON variables are declared by u common u a where a is a list of variable names LISP is designed in such a way that all functions for which the possibility of recursion can exist are in fact recursive This requires that all temporary stored results related to the computation that is in progress be set aside when a piece of coding is to be used recursively and that they be later restored This is done automatically and need not be programmed explicitly All saving of temporary results in LISP is performed on a linear block of storage called the push down list Each set of stored data that is moved onto the push down list is in a block labeled with its size and the name of the subroutine from which it came Since it is in the nature of recursion that the first block to be saved is always the last block to be restored it is possible to keep the push down list compact Joel Moses 英语 Joel Moses The Function of FUNCTION in LISP or Why the FUNARG Problem Should Be Called the Environment Problem pdf June 1970 2009 10 27 AI Memo 199 原始内容存档于2010 05 23 There are several ways in which to maintain the values of free variables and thus the computational environment in order to handle cases like the one above All of the techniques used involve some increase in time One approach makes it easy to access the value of a free variable is local This approach is favored in recent implementations of LISP We shall call it the shallow access approach Another approach is to make it relatively easy to enter and leave a block in which a free variable is bound but relatively expensive to access a free variable This approach is used in the classical alist implementation of LISP Several Algol systems have opted for a similar approach We shall call this the deep access approach Both of these approaches allow one to modify the value of the variable as well as access it The access time is approximately the same as modification time in both approaches Let us consider the shallow access approach first By shallow access we mean that the value of a free variable can be obtained in a single fetch from memory Since the current value may be stored in a difficult to determine location up in the stack a special cell for its current value is used In many recent LISP implementations this special values cell is stored as a property of the atom structure and is unique to the free variable In order to maintain the proper value in the special cell extra work must be done every time a function or a block is entered in which the variable is an argument or is local On entering such a function or block one usually saves the old value which is in the special cell on the stack alone with sufficient information to allow one to know from where the stack value came On leaving such a function or block one must remember to store the value saved in the stack in the special cell The deep access approach forces one to search upward in the stack for the most recent value of the free variable Such a search may be quite deep and slow if the free variable was bond vary far up in the stack However this approach has the advantage of avoiding the need for an extra special value cell In addition we shall see later that this approach sometimes allows one to use free variables with greater ease and flexibility than the shallow access approach Certain LISP systems use deep access in interpreted functions and shallow access in compiled functions if free variables in compiled functions are declared to be COMMON their values will be stored on the alist In this manner one can solve the environment problem The cost is a very slow interpreter and deep access to free variables Gerald J Sussman Guy L Steele Jr Scheme An Interpreter for Extended Lambda Calculus 维基文库 1975 英文 There are several important consequences of closing every lambda expression in the environment from which it is passed i e in its lexical or static environment First the axioms of lambda calculus are automatically preserved Thus referential transparency is enforced This in turn implies that there are no fluid variable bindings as there are in standard stack implementations of LISP such as MacLISP Second the upward funarg problem 英语 funarg problem Moses requires that the environment structure be potentially tree like Finally the environment at any point in a computation can never be deeper than the lexical depth of the expression being evaluated at that time i e the environment contains bindings only for variables bound in lambdas lexically surrounding the expression being evaluated This is true even if recursive functions are involved Furthermore it is not even necessary to scan the environment for the variable since its value must be in a known position relative to the top of the environment structure this position can be computed by a compiler at compile time on the basis of lexical scope Guy L Steele Common Lisp the Language 2nd Edition 1990 ISBN 1 55558 041 6 Symbols are used as names of variables in Common Lisp programs When a symbol is evaluated as a form the value of the variable it names is produced For example after doing setq items 3 which assigns the value 3 to the variable named items then items 3 Variables can be assigned to as by setq or bound as by let Any program construct that binds a variable effectively saves the old value of the variable and causes it to have a new value and on exit from the construct the old value is reinstated There are actually two kinds of variables in Common Lisp called lexical or static variables and special or dynamic variables At any given time either or both kinds of variable with the same name may have a current value Which of the two kinds of variable is referred to when a symbol is evaluated depends on the context of the evaluation The general rule is that if the symbol occurs textually within a program construct that creates a binding for a variable of the same name then the reference is to the variable specified by the binding if no such program construct textually contains the reference then it is taken to refer to the special variable of that name The distinction between the two kinds of variable is one of scope and extent A lexically bound variable can be referred to only by forms occurring at any place textually within the program construct that binds the variable A dynamically bound special variable can be referred to at any time from the time the binding is made until the time evaluation of the construct that binds the variable terminates Therefore lexical binding of variables imposes a spatial limitation on occurrences of references but no temporal limitation for the binding continues to exist as long as the possibility of reference remains Conversely dynamic binding of variables imposes a temporal limitation on occurrences of references but no spatial limitation For more information on scope and extent see chapter 3 The value a special variable has when there are currently no bindings of that variable is called the global value of the special variable A global value can be given to a variable only by assignment because a value given by binding is by definition not global It is possible for a special variable to have no value at all in which case it is said to be unbound By default every global variable is unbound unless and until explicitly assigned a value except for those global variables defined in this book or by the implementation already to have values when the Lisp system is first started It is also possible to establish a binding of a special variable and then cause that binding to be valueless by using the function makunbound In this situation the variable is also said to be unbound although this is a misnomer precisely speaking it is bound but valueless It is an error to refer to a variable that is unbound Macro DEFPARAMETER DEFVAR Common Lisp HyperSpec It is customary to name dynamic variables with an asterisk at the beginning and end of the name e g foo is a good name for a dynamic variable but not for a lexical variable foo is a good name for a lexical variable but not for a dynamic variable This naming convention is observed for all defined names in Common Lisp however neither conforming programs nor conforming implementations are obliged to adhere to this convention Alexander Burger PicoLisp Frequently Asked Questions 2021 10 29 原始内容存档于2017 08 06 Why do you use dynamic variable binding Dynamic binding is very powerful because there is only one single dynamically changing environment active all the time This makes it possible e g for program snippets interspersed with application data and or passed over the network to access the whole application context freely yet in a dynamically controlled manner And shallow dynamic binding is the fastest method for a Lisp interpreter Lexical binding is more limited by definition because each environment is deliberately restricted to the visible textual static scope within its establishing form Therefore most Lisps with lexical binding introduce special variables to support dynamic binding as well and constructs like labels to extend the scope of variables beyond a single function In PicoLisp function definitions are normal symbol values They can be dynamically rebound like other variables Are there no problems caused by dynamic binding You mean the funarg problem or problems that arise when a variable might be bound to itself For that reason we have a convention in PicoLisp to use transient symbols instead of internal symbols or private internal symbols But with dynamic binding I cannot implement closures This is not true Closures are a matter of scope not of binding For a closure it is necessary to build and maintain a separate environment In a system with lexical bindings this has to be done at each function call and for compiled code it is the most efficient strategy anyway because it is done once by the compiler and can then be accessed as stack frames at runtime For an interpreter however this is quite an overhead So it should not be done automatically at each and every function invocation but only if needed Lutz Mueller Comparison to Common Lisp and Scheme 2021 10 29 原始内容存档于2022 04 06 Dynamic scoping inside isolated namespaces newLISP is sometimes criticized for using dynamic scoping and fexprs In newLISP all variables are dynamically scoped by default However by defining a function in its own context static lexical scoping can be achieved In newLISP several functions and data can share a namespace By enclosing functions in their own namespace a lexical closure like mechanism is achieved Common Lisp and Scheme are lexically scoped by default and use lambda expressions as the closure mechanism Common Lisp also offers special variables for dynamic scoping The problems of free variables in dynamic scoping can be avoided In the rare cases when free variables must be used you can partition code into namespace modules for easier control over free variables You can then exploit the advantages of dynamic scoping With dynamic scoping inside lexically closed namespaces newLISP combines the best of both scoping worlds newLISP has no funarg problem because it follows a simple rule variables always show the binding of their current environment When expressions with local variables are entered newLISP saves the current variable state on a stack and restores it on exit of that expression In newLISP not only are function parameters and variables declared with let expressions local loop variables in all looping expressions are local too Dynamic Binding Vs Lexical Binding EmacsWiki 2021 10 28 原始内容存档于2022 05 09 dynamic All variable names and their values live in one global table lexical Each binding scope function let syntax creates a new table of variable names and values organised in a hierarchy called the environment EmacsLisp as of 24 1 has both dynamic binding and lexical binding Lexical binding must be enabled explicitly for a file or buffer Individual variables can be defvar ed to make them special like in CommonLisp Sebesta Robert W 2 4 Functional Programming LISP 6 9 List Types 15 4 The First Functional Programming Language LISP Concepts of Programming Languages 10th Boston MA USA Addison Wesley 2012 47 52 281 284 677 680 2021 10 23 ISBN 978 0 13 139531 2 原始内容 print 存档于2021 03 08 英语 Conses as Lists Common Lisp HyperSpec A list is a chain of conses in which the car of each cons is an element of the list and the cdr of each cons is either the next link in the chain or a terminating atom A proper list is a list terminated by the empty list The empty list is a proper list but is not a cons An improper list is a list that is not a proper list that is it is a circular list or a dotted list A dotted list is a list that has a terminating atom that is not the empty list A non nil atom by itself is not considered to be a list of any kind not even a dotted list A circular list is a chain of conses that has no termination because some cons in the chain is the cdr of a later cons CSE 341 Scheme Quote Quasiquote and Metaprogramming Cs washington edu 1999 02 22 2013 11 15 原始内容存档于2013 08 23 Alan Bawden Quasiquotation in Lisp 1999 2021 10 29 原始内容存档于2021 10 29 3 2 2 3 Semantic Constraints 页面存档备份 存于互联网档案馆 in Common Lisp HyperSpec 页面存档备份 存于互联网档案馆 4 3 Control Abstraction Recursion vs Iteration in Tutorial on Good Lisp Programming Style 页面存档备份 存于互联网档案馆 by Kent Pitman 英语 Kent Pitman and Peter Norvig August 1993 Time of Evaluation Common Lisp Extensions 页面存档备份 存于互联网档案馆 Gnu org Retrieved on 2013 07 17 Gerald J Sussman Guy L Steele Jr The Revised Report on SCHEME A Dialect of LISP 1978 Magic forms are recognized by then presence of a magic reserved word in the car position of the form All non atomic forms which are not magic forms are considered to be combinations The system has a small initial set of magic words there is also a mechanism for creating new ones Note FUNCALL is a Pain A combination is considered to be a list of subforms These subforms are all evaluated The first value mub be a procedure it is applied to the other values to get the value of the combination There are four important points here 1 the procedure Position is always evaluated just like any other position This is why the primitive operators are the values of global identifiers 2 the procedure is never re evaluated if the first subform fails to evaluate to a applicable procedure it is an error Thus unlike most LISP systems SCHEME always evaluates the first subform of a combination exactly once 3 the arguments are all completely evaluated before the procedure is applied that is SCHEME like most LISP systems is an applicative order language Many SCHEME programs exploit this fact 4 the argument forms and procedure form may in principle be evaluated in any order This is unlike the usual LISP left to right order All SCHEME interpreters implemented so far have in fact performed left to right evaluation but we do not wish programs to depend on this fact Indeed there are some reasons why a clever interpreter might want to evaluate them right to left e g to get things on a stack in the correct order Paul Graham What Made Lisp Different May 2002 John McCarthy History of Lisp PDF Artificial Intelligence Laboratory Stanford University 12 February 1979 I invented conditional expressions in connection with a set of chess legal move routines I wrote in FORTRAN for the IBM 704 at M I T during 1957 58 A paper defining conditional expressions and proposing their use in Algol was sent to the Communications of the ACM but was arbitrarily demoted to a letter to the editor because it was very short Alan Kay The Early History of Smalltalk 1993 doi 10 1145 155360 155364 The biggest hit for me while at SAIL 英语 Stanford University centers and institutes Stanford Artificial Intelligence Laboratory in late 69 was to really understand LISP Of course every student knew about car cdr and cons but Utah was impoverished in that no one there used LISP and hence no one had penetrated the mysteries of eval and apply I could hardly believe how beautiful and wonderful the idea of LISP was McCarthy 1960 I say it this way because LISP had not only been around enough to get some honest barnacles but worse there wee deep flaws in its logical foundations By this I mean that the pure language was supposed to be based on functions but its most important components such as lambda expressions quotes and conds were not functions at all and instead were called special forms Landin and others had been able to get quotes and conds in terms of lambda by tricks that were variously clever and useful but the flaw remained in the jewel In the practical language things were better There were not just EXPRs which evaluated their arguments but span class ilh all data orig title fexpr data lang code en data lang name 英语 data foreign title fexpr span class ilh page FEXPR span span class noprint ilh comment span class ilh lang 英语 span span class ilh colon span span class ilh link span lang en dir auto fexpr span span span span s which did not My next questions was why on earth call it a functional language Why not just base everything on FEXPRs and force evaluation on the receiving side when needed I could never get a good answer but the question was very helpful when it came time to invent Smalltalk because this started a line of thought that said take the hardest and most profound thing you need to do make it great an then build every easier thing out of it That was the promise of LISP and the lure of lambda needed was a better hardest and most profound thing Objects should be it This Smalltalk language today labeled 71 was very influenced by FLEX 英语 Flex programming language PLANNER 英语 Planner programming language LOGO META II 英语 META II and my own derivatives from them As I mentioned previously it was annoying that the surface beauty of LISP was marred by some of its key parts having to be introduced as special forms rather than as its supposed universal building block of functions An elegant approach was suggested in a CMU thesis of Dave Fisher Fisher 70 on the syntheses of control structures ALGOL60 required a separate link for dynamic subroutine linking and for access to static global state Fisher showed how a generalization of these links could be used to simulate a wide variety of control environments One of the ways to solve the funarg problem of LISP is to associate the proper global state link with expressions and functions that are to be evaluated later so that the free variables referenced are the ones that were actually implied by the static form of the language The notion of lazy evaluation is anticipated here as well Alan Kay Stefan Ram Dr Alan Kay on the Meaning of Object Oriented Programming 2003 07 23 My original experiments with this architecture were done using a model I adapted from van Wijngaarten s and Wirth s Generalization of Algol and Wirth s Euler Both of these were rather LISP like but with a more conventional readable syntax I didn t understand the monster LISP idea of tangible metalanguage then but got kind of close with ideas about extensible languages draw from various sources including Irons IMP The second phase of this was to finally understand LISP and then using this understanding to make much nicer and smaller and more powerful and more late bound understructures Dave Fisher s thesis was done in McCarthy style and his ideas about extensible control structures were very helpful OOP to me means only messaging local retention and protection and hiding of state process and extreme late binding of all things It can be done in Smalltalk and in LISP There are possibly other systems in which this is possible but I m not aware of them Lieberman Henry Hewitt Carl A Real Time Garbage Collector Based on the Lifetimes of Objects Communications of the ACM June 1983 26 6 419 429 CiteSeerX 10 1 1 4 8633 S2CID 14161480 doi 10 1145 358141 358147 hdl 1721 1 6335 Edsger W Dijkstra The Humble Programmer EWD 340 1972 ACM Turing Award lecture A Look at Clojure and the Lisp Resurgence Paul Graham The Roots of Lisp PDF 2002 2021 10 28 原始内容 PDF 存档于2021 10 28 Daniel G Bobrow Kenneth Kahn Gregor Kiczales Larry Masinter Mark Stefik Frank Zdybel CommonLoops Merging Lisp and Object Oriented Programming 1986 2021 10 29 原始内容存档于2022 04 06 A History and Description of CLOS by Jim Veitch Pages 107 158 of Handbook of Programming Languages Volume IV Functional and Logic Programming Languages ed Peter H Salus 英语 Peter H Salus 1998 1st edition Macmillan Technical Publishing ISBN 1 57870 011 6延伸阅读 编辑McCarthy John History of Lisp Stanford University 1979 02 12 2008 10 17 Steele Jr Guy L Richard P Gabriel The evolution of Lisp The second ACM SIGPLAN conference on History of programming languages New York NY ACM 231 270 1993 2008 10 17 ISBN 0 89791 570 4 Richard Stallman My Lisp Experiences and the Development of GNU Emacs transcript of Richard Stallman s speech 28 October 2002 at the International Lisp Conference Edmund Berkeley 英语 Edmund Berkeley Daniel G Bobrow 英语 Daniel G Bobrow The Programming Language LISP Its Operation and Applications PDF Cambridge Massachusetts MIT Press March 1964 Weissman Clark LISP 1 5 Primer PDF Belmont California Dickenson Publishing Company Inc 1967 外部链接 编辑从维基百科的姊妹计划了解更多有关 LISP 的内容 维基词典上的字词解释 维基共享资源上的多媒体资源 维基语录上的名言 维基文库上的原始文献 维基教科书上的教科书和手册 维基学院上的學習资源历史History of LISP at the Computer History Museum 页面存档备份 存于互联网档案馆 图书和教程Casting SPELs in Lisp 页面存档备份 存于互联网档案馆 a comic book style introductory tutorial On Lisp 页面存档备份 存于互联网档案馆 a free book by Paul Graham Practical Common Lisp 页面存档备份 存于互联网档案馆 freeware edition by Peter Seibel Land of Lisp 页面存档备份 存于互联网档案馆 Official Website 页面存档备份 存于互联网档案馆 for the book mal Make a Lisp 页面存档备份 存于互联网档案馆 Peter Norvig Paradigms of Artificial Intelligence Programming Case Studies in Common Lisp 1992 资源Awesome Common Lisp 页面存档备份 存于互联网档案馆 CLiki the Common Lisp wiki 页面存档备份 存于互联网档案馆 Lisp FAQ Index 页面存档备份 存于互联网档案馆 Planet Lisp 页面存档备份 存于互联网档案馆 取自 https zh wikipedia org w index php title LISP amp oldid 75216631, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。