LISP

维基百科,自由的百科全书
跳转至: 导航搜索
Lisp
Lisplogo alien 256.png
编程范型 多范型函数式过程式反射式元编程
发行时间 1958
設計者 约翰·麦卡锡
實作者 史帝芬·羅素, Timothy P. HartMike Levin
型態系統 动态类型强类型
衍生副語言 Common Lisp, Scheme, Emacs Lisp, AutoLISP, Logo, Clojure, ISLISP, Newlisp, Arc, SKILL, Racket
啟發語言 IPL
影響語言 ML, Perl, Python, Smalltalk, Ruby, Dylan, Haskell, Mathematica, REBOL, Qi, Lua, JavaScript, LPC, Forth, Nu语言, OPS5, CLU, Falcon, Io语言, Ioke, MDL, FPr

Lisp,最初被拼為LISP,一個歷史悠久的電腦程式語言家族,以波兰表示法編寫。最早由约翰·麦卡锡在1958年基于λ演算创造,是歷史第二悠久的高级语言,僅次於Fortran。也是第一個函数式编程语言

其名稱源自列表处理器英语List Processor)的縮寫。LISP有很多种方言,各个实现中的语言不完全一样。LISP语言的主要现代版本包括Common LispScheme。1980年代蓋伊·史提爾二世编写了Common Lisp试图进行标准化,这个标准被大多数解释器和编译器所接受。还有一种是編輯器Emacs所衍生出來的Emacs Lisp(而Emacs正是用Lisp作为扩展语言进行功能扩展的)非常流行,并建立了自己的标准。

歷史[编辑]

1955年至1956年間,資訊處理語言被創造出來,使用於人工智能處理(早期的基于符号处理的人工智能领域,以图灵测试为目标。此领域中有些研究者持有观点:“符号演算系统可以衍生出智能。”[1])。它首先使用了串列結構與遞迴

1958年,約翰·麥卡錫麻省理工學院發明了Lisp這個程式語言,其中採用了資訊處理語言的特徵。1960年,他在《ACM通讯》發表論文,名為《遞迴函數的符號表達式以及由機器運算的方式,第一部》(Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part I)。在這篇論文中,他展示了,只要透過一些簡單的運算子,以及用於函數的記號,就可以建立一個具圖靈完備性語言,可用於演算法中。

麥卡錫最初使用M表示式(M-expression)寫成程式碼,之後再轉譯成S表示式,舉例來說,M表示式的函數語法,car[cons[A,B]],等同於S表示式(car (cons A B))。然而由於S表示式具備同像性的特性(homoiconic,即程式與資料由同樣的結構儲存),實際應用中一般只使用S表示式。此外,他也由資訊處理語言中借用了許多觀念。

約翰·麥卡錫的學生史帝芬·羅素在閱讀完此論文後,認為Lisp程式語言當中的eval函式可以用機器碼來實做。他在IBM 704機器上,寫出了第一個LISP直譯器。1962年,提姆·哈特(Tim Hart)與麥克·萊文(Mike Levin)在麻省理工學院,以Lisp語言,實做出第一個完整的lisp編譯器。

基本介绍[编辑]

LISP是第一個函數型程式語言,区别于C/Java等命令型编程语言。

由于历史的原因,Lisp长期以来被认为主要用于AI领域,但Lisp并不是为AI而设计,而是一种通用的编程语言.

Lisp的表达式是一个原子(atom)或表(list),原子(atom)又包含符號(symbol)與數值(number);表是由零个或多个表达式组成的序列,表达式之间用空格分隔开,放入一对括号中,如:

abc
()
(abc xyz)
(a b (c) d)

最后一个表是由四个元素构成的,其中第三个元素本身也是一个表,這種list又稱為嵌套表(nested list)。

正如算数表达式1+1有值2一样,Lisp中的表达式也有值,如果表达式e得出值v,我们说e返回v。如果一个表达式是一个表,那么我们把表中的第一个元素叫做操作符,其余的元素叫做自变量。

Lisp的7个公理(基本操作符)[编辑]

基本操作符1 quote[编辑]

(quote x)返回x,我们简记为'x

(quote a)

上面的表達式的值是a。如果使用c/Java語言的表達方式,可以說成:上面這段代碼返回的值是a。

'a

這個表達式和上面的那個相同,值也是a。將quote寫成 ' 只是一種語法糖

基本操作符2 atom[编辑]

(atom x)当x是一个原子或者空表时返回原子t,否则返回NIL。在Common Lisp中我们习惯用原子t表示真,而用空表 ()和NIL表示假。

>atom 'a)
t
> (atom '(a b c))
NIL
> (atom '())
t

现在我们有了第一个需要求出自变量值的操作符,让我们来看看quote操作符的作用——通过引用(quote)一个表,我们避免它被求值(eval)。一个未被引用的表达式作为自变量,atom将其视为代码,例如:

> (atom (atom 'a))
t

这是因为(atom 'a)的结果(t)被求出,并代入(atom (atom 'a)),成为(atom t),而这个表达式的结果是t。

反之一个被引用的表仅仅被视为表

> (atom '(atom 'a))
NIL

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

基本操作符3 eq[编辑]

(eq x y)当x和y指向相同的对象的时候返回t,否则返回NIL,值得注意的是在Common Lisp中,原子对象在内存中只会有一份拷贝,所以(eq 'a 'a)返回t,例如:

>(eq 'a 'a)
t
>(eq 'a 'b)
NIL
> (eq '() '())
t
> (eq '(a b c) '(a b c))
NIL

基本操作符4 car[编辑]

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

> (car '(a b))
a

基本操作符5 cdr[编辑]

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

> (cdr '(a b c))
(b c)

基本操作符6 cons[编辑]

(cons x y)返回一个cons cell(x y),如果y不是一个list,将会以dotted pair形式展现这个cons cell,例如:

>(cons 'a 'b)
(a . b)

一个cons cell的第二项如果是另一个cons cell,就表示成表的形式,例如:

 (cons 'a (cons 'b 'c))

就表示成 (a b . c) 若一个cons cell第二项为空,就省略不写,例如:

 (cons 'a  (cons 'b ()))

表示为 (a b) 这样,多重的cons cell就构成了表:

> (cons 'a (cons 'b (cons 'c ())))
(a b c)

基本操作符7 cond[编辑]

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

> (cond ((eq 'a 'b) 'first)  ((atom 'a)  'second))
 second

函数[编辑]

七个原始操作符中,除了quote與cond,其他五個原始操作符总会对其自变量求值.我们称这样的操作符为函数.

语法和语义[编辑]

Scheme的Hello World程序[编辑]

(display "Hello, world!")
;; 在屏幕中打印出: Hello, world!
 
;; 函数定义
(define (hello)
  (display "Hello, world!"))
 
;; 函数调用
(hello)
;; 在屏幕中打印出: Hello, world!

Common Lisp的Hello World程序[编辑]

(format t "hello, world!")
;; 在屏幕中打印出: hello, world!
 
函数定义:
(defun hello-world ()
  (format t "hello, world!"))
调用函数:
(hello-world)
;; 在屏幕中打印出: hello, world!
;; 并以NIL作为函数的返回值

註釋[编辑]

参见[编辑]

Wikibooks-logo.svg
您可以在維基教科書中查找此百科条目的相關電子教程:

外部链接[编辑]