您的位置:首页 > 其它

lisp感悟(欢迎大家前来指导,谢谢)

2011-03-17 03:17 239 查看
Lsip感悟
Lisp是一种可编程语言,他采取自底向上的设计方式,如今在许多方面都有广泛的运用。
一 list结构
1 内部结构:
Lisp是List Processor的缩写,而list也正好反映了Lisp语言的结构,他的整个程式都是由一个个的list堆积而成。而一对括号, 以及括号里面的内容, 组成为一个串列, 学名就叫list.,而括号的内容, 称为元素, 学名为atom. list本身功能非常强大他可以由任意数据构成甚至list里也可嵌套list构成其结构如以下均可称为list:
( 1 2 3 ) (1 'red 'green ) ( + 3 ( * 5 8 ) )
(‘(BLUE SKY)
’(GREEN GRASS)
‘(BROWN EARTH))(这里需注意某些atom前添加了‘后面将作解释)
2 针对list的操作:
list这种独特的结构让lisp拥有了许多独特的操作。如:
length用于计算list的长度如:
>(length ’(1 2 3))
3
> (length '(1 '( a b) 2 'abc)
4
first second third分别用于得到con cell结构的第一项第二项第三项rest得到第一项以外的项如:
>(first '(a b c))
a
>(rest '(a b c))
(b c)
car(功能用法均和first一样)cdr(功能用法同rest)此外cadr表示the car of cdr功能可自己推出。caddr等均如上。例:
>(caar '( '( blue cube ) '( red man)))
blue
cons接受两个输入返回的list的car为第一个输入cdr为第二个输入;list将任意数量其中的元素list合成为一个新的list返回;append将两个list作为输入,返回一个list包含整个list的所有元素(第一个输入必须为list)。例:
> (cons 4 5)
(4 . 5)
> (cons (cons 4 5) 6)
((4 . 5) . 6)
> (list 4 5 6)
(4 5 6)
>(append '(here today) 'man)
((here today) . man)
reverse将整个list颠倒例:
>(reverse '( a b c))
(c b a)
此外还有member,intersection,union,set-difference,subsetp,nth,assoc等操作,不过在此就不一一赘述了。而通过以上的例子我们可以发现lisp中我们通常只需要知道单词的意思就能够理解它的功能。值得一提的是以上操作均不真正改变变量的值。
二 Eval function
1 功能简介:
Eval function是lisp的核心。而每个list实际上都是由Eval function翻译过来的,正因此它独特的这种功能决定了lisp前缀表达式等等一系列特点。
在 Eval function 中只有数字是自动计算的,因此当我们要在list中使用字符或子list来构成时,我们必须添加单引号,单引号自动会告诉电脑后面跟的内容不进行值计算。
当任何一个list运行时电脑会首先检查他的第一个元素,每个 list 的头 (就是第一个atom)将会告诉告诉电脑要作什么事。所以第一个元素必须是一些运算操作或lisp本身的一些special form。接着他将会对头以后的元素进行求值。这是lisp制式化的步骤。
三 定义与赋值
1 定义函数及使用
单纯的定义一个函数十分简单,只需找如下模样定义即可:
(defun 函数名 (参数)
( 函数体 )
例:
>(defun square (n) (* n n) )
square
而当我们定义好函数后要使用也只需找一下模样运行即可:
(函数名 参数)
>(square 5)
25
当然在定义函数时我们有时还会使用lambda。
2 为变量定义赋值
在lisp中当我们想为一个变量赋值时十分简单只需要使用简单的setf(也可使用setq)宏功能就能实现我们的目的,而不用考虑c++那些还要匹配类型的规矩,我们可以给我们的变量赋任意的值。如:
(setf a '( a b c) ) (setf a 1)
当然提到了定义变量,这里不得不讲的还有let和let*。我们可以用let在函数中创造一个局部变量并在其中赋值。例:
(defun average (x y)
(let ((sum (+ x y)))
(list x y ’average ’is (/ sum 2.0))))
(defun switch-billing (x)
(let ((star (first x))
(co-star (third x)))
(list co-star ’accompanied ’by star)))
let*与let的功能相同但它们的不同点在于let是一次就把所有的局部变量同时创建,而let*则是一次只创建一个所以在上例中let创建的co-star局部变量是无法利用star这个局部变量获得值的,因为co-star和star是同时创建的,而如果使用let*那么程序实际是先创建出star这个局部变量再创造出co-star这个局部变量。所以如使用let*那么co-star的值也可通过star获得。例:
(defun switch-billing (x)
(let* ((star (first x))
(co-star (third star)))
(list co-star ’accompanied ’by star)))
切记不要因此就贪图简洁所有时候均使用let*因为有时只能够使用let。
3 赋值
此外在lisp中由于其独特的结构,所以还存在专门的操作对其进行一些技巧性的赋值。如incf ,decf,push,pop等等,但这里就不做赘述了。
四 lisp中的控制结构
无论是c语言c++、java说到控制结构都离不开循环选择,而这在lisp中也是一样的,以下就将介绍lisp中最基本的控制结构。
1 判断:
If是lisp中最简单的判断语句例:
(defun my-abs (x)
(if (< x 0) (- x) x))
Cond则是lisp中最经典的判断语句,他的简单的结构如下:
(COND (test-1 consequent-1)
(test-2 consequent-2)
(test-3 consequent-3)
....
(test-n consequent-n))
例:
(defun where-is (x)
(cond ((equal x ’paris) ’france)
((equal x ’london) ’england)
((equal x ’beijing) ’china)
(t ’unknown)))
这里的t表示正确如if(1),但写在cond的最后可理解成else。
我们记得在c++中我们在判断时&&和||及!表示或与非来加强选择,而在lisp中我们则用and,or、not这些宏功能来实现。
另外我们还可以使用when和unless来实现我们的功能。
2 循环:
循环其实就是迭代,而提到迭代必然也会很自然的想到递归,但考虑到递归的思想如果学过别的编程语言应该就会建立好这种思维,而在lisp中递归也并没有本质的区别,所以在此不仔细说明,但递归绝对是不可忽视的一种编程思想。
在lisp中循环有很多宏功能来实现,而每种宏功能都有其独特的特点。实现循环最直白的就是loop了,其次还有dotimes,dolist,do,do*这种种均可实现循环的功能。
在以上这些循环中最简单的就是dotimes和dolist了,这两种是相对的,一个是针对数字操作而一个则是针对list操作。它们的基本模型如下:
(DOTIMES (index-var n [result-form])
body) 例:
> (dotimes (i 4)
(format t "~&I is ~S." i))
I is 0.
I is 1.
I is 2.
I is 3.
NIL
(DOLIST (index-var list [result-form])
body)例:
> (dolist (x ’(red blue green) ’flowers)
(format t "~&Roses are ~S." x))
Roses are RED.
Roses are BLUE.
Roses are GREEN.
FLOWERS
当二者如果没有接受到return的命令时则会一直往下执行直至程序结束。
(注result-form为返回值什么都不写则返回nil所以上面两个例子最后会多出flowers和nil。)
而do和do*两种循环的区别我们可参照list和list*来理解以下为do的模板:
(DO ((var1 init1 [update1])
(var2 init2 [update2])
...)
(test action-1 ... action-n)
body)
在程序执行时,首先会对do中变量list中的变量初始化,接着执行test满足要求了则退出循环否则执行body中的内容直至程序最终退出。在这里我们可以参照c中的for循环来理解。以下为实例:
(defun launch (n)
(do ((cnt n (- cnt 1)))
((zerop cnt) (format t "Blast off!"))
(format t "~S..." cnt)))
> (launch 10)
10...9...8...7...6...5...4...3...2...1...Blast off!
NIL
五 输入与输出
任何语言都是离不开输入和输出的。早期的lisp主要采取print或其变形prin1,princ来完成输出。而如今最常用的输入和输出我们则主要采取的是read和format来实现。format的模板通常如下:
(format t 内容)
它的返回值通常是nil,但是其边缘效应使它能够打印出我们想要的内容。而在format中还存在一些特殊的format 控制操作进一步帮助我们实现想要的操作。如
~%(让字符串输出时换行)例:
> (format t "Time flies~%like an arrow.")
Time flies
like an arrow.
NIL
~s (功能类似于c语言中printf(“%d%s”。。。))例:
> (format t "From ~S to ~S in ~S minutes!"
’boston ’(new york) 55)
From BOSTON to (NEW YORK) in 55 minutes!
NIL
~a,功能和~s一样只不过使用~a时输出的东西不包含引号而~s则包含。
lisp中用read来完成输入此操作,如:
(defun my-square ()
(format t "Please type in a number: ")
(let ((x (read)))
(format t "The number ~S squared is ~S.~%"
x (* x x))))
此外lisp中也有针对文件的流操作with-open-file宏功能实现了这种操作。其模板如下:
(WITH-OPEN-FILE (var pathname)
body)
六 宏功能
Lisp中的宏功能和c++等语言比起来可以说是非常强大的,我感觉整个lisp就是构筑在无数的宏功能上的。而在上面的介绍中我们已接收了许多宏功能,如defun,do,cond,defstruct等等。对于其强大的各种宏功能我们就不一一介绍了。
那么我们应该怎样才能定义宏功能呢?定义一个宏非常简单只需使用defmacro即可类似于defun。有了这些我们就能按自己的意愿实现自己的种种需求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: