一直在拖延,玩Lisp,终究绕不开这道坎啊。既然如此,抖擞下精神,开始了。
作者首先又是抱怨、比较了一番lisp的宏与其他语言的区别。从形式上来讲,其实所谓的标准宏就和c,java之类的类库一样,是事先已经被完成、验证过的东东封装在编译/虚拟环境 中供coder使用(省的重复造轮子)。当然,在lisp中,宏可不单单是如此简单,不过~管他呢(拜托,这只是初学者教程!)在这一章节主要给大伙介绍几个常用的宏。
条件宏
最常见的估计算是"if"了:
(if condition then-form [else-form])
(if (> 2 3) "Yup" "Nope") ==> "Nope"
(if (> 2 3) "Yup") ==> NIL
(if (> 3 2) "Yup" "Nope") ==> "Yup"
真是简单易懂啊,不过if只支持单行动语句,也就是说,“无论条件是否成立,都只能做一件事,而不能做一组事”。而在真实环境中,自然会大大影响其使用面。为此就引入了特别造作符:PROGN
(if (spam-p current-message)
(progn
(file-in-spam-folder current-message)
(update-spam-database current-message)))
恩,看起来还不错,不过,如果有更简洁的方案呢:
(when (spam-p current-message)
(file-in-spam-folder current-message)
(update-spam-database current-message))
when也是一个标准宏,即使不是,定义也不麻烦:
(defmacro when (condition &rest body)
`(if ,condition (progn ,@body)))
它的共生兄弟unless则是对条件作了逆判断:
(defmacro unless (condition &rest body)
`(if (not ,condition) (progn ,@body)))
似乎没什么神奇的啊,即没有神秘的魔法也没有晕人的逻辑。对头!或许"大道至简"可以用作解释吧。
如果说when解决了执行条目的问题,那么宏cond则是解决了条件条目的问题:
(cond
(test-1 form*)
.
.
(test-N form*))
(cond (a (do-x))
(b (do-y))
(t (do-z))) '理论上来说最后一条是default
在做条件运算时,通常都会搭配些基本的运算符:and,or,not(not其实算是函数)。
(not nil) ==> T
(not (= 1 1)) ==> NIL
(and (= 1 2) (= 3 3)) ==> NIL '遇到第一个nil即返回,没有则t
(or (= 1 2) (= 3 3)) ==> T '遇到第一个t即返回,没有则nil
循环宏
最简单的两个循环宏莫过于dolist和dotimes了:
(dolist (var list-form)
body-form*)
(dolist (x '(1 2 3)) (print x))
1
2
3
NIL
CL-USER> (dolist (x '(1 2 3)) (print x) (if (evenp x) (return)))
1
2
NIL '通过return截断了循环
-----------------------------
(dotimes (var count-form)
body-form*)
(dotimes (i 4) (print i))
0
1
2
3
NIL
一个循环列表,一个根据数值递进循环,都算定制型的循环宏。而他们都有一个"父宏"(可以这么叫么)--do,这玩意由于超级灵活(万金油啊),那么也造成了易用度的降低:
(do (variable-definition*)
(end-test-form result-form*)
statement*)
variable-definition-->(var init-form step-form)
简单看来,需要在veriable-definition中定义循环初值,跳步幅度(没有则默认一步),当达到end-test-form时,执行result-form,他的返回值将作为整个循环的返回值。而statement则是循环体。这里给出了一个例子来证明do的灵活性:
(do ((n 0 (1+ n))
(cur 0 next)
(next 1 (+ cur next)))
((= 10 n) cur))
其实就是传说中的“斐波纳契数列”。在这个例子中循环体似乎并不重要,重要的是构造本身。正如前面所说,灵活的同时易用性正在丧失,例子中的括弧实在令人印象深刻啊。咱们来看个对比:
(do ((i 0 (1+ i)))
((>= i 4))
(print i))
(dotimes (i 4) (print i))
果然是“红花需要绿叶衬”~
在某些情况下,循环条件都是非必需的:
(do () '虽然没有条件,位置还得留着
((> (get-universal-time) *some-future-date*))
(format t "Waiting~%")
(sleep 60))
接下来要介绍的算是在lisp界颇具争议的"强力"循环宏:loop.
dolist,dotimes虽然简单,覆盖面却不广,而do又过于灵活(=复杂?),那么看似更趋向于中间的loop便有了出现的理由,纵然有不少人反对他(支持的也不少)。
看起来很简洁:
(loop
body-form*)
用起来也不赖:
(loop
(when (> (get-universal-time) *some-future-date*)
(return))
(format t "Waiting~%")
(sleep 60))
与do比较下:
(do ((nums nil) (i 1 (1+ i)))
((> i 10) (nreverse nums))
(push i nums)) ==> (1 2 3 4 5 6 7 8 9 10
(loop for i from 1 to 10 collecting i) ==> (1 2 3 4 5 6 7 8 9 10)
也来实现个“斐波纳契数列”:
(loop for i below 10
and a = 0 then b
and b = 1 then (+ b a)
finally (return a))
虽然其中用到了类似for,below什么的loop专用符号,但的确看着清爽多了,也更符合自然语言。这是loop簇拥们的理由,也是反对者腹诽的地方"一点都不lisp".个人观点就是,你觉着哪个爽就用哪个呗,正是"条条大路通罗马"~当然,这里的loop使用还只是冰山一角,后面的章节还会详述。
lisp编译器自带的标准宏自然不光这么几个,仅仅是摘出几个常用的,以简单一窥其中奥妙。那么,在接下来的章节中,即将深入介绍--自定义宏。你准备好了么?
(未完待续)
分享到:
相关推荐
common-lisp-the-language-second-edition.PDF
Practical Common Lisp-1st-2005,官方排版,我为大部分章节加了二级书签
cad-lisp-3-表操作.LSP.lsp
Common Lisp the Language, 2nd Edition经典,喜欢commonlisp的朋友们的少有资源
Provides practical advice for the construction of Common Lisp programs. Shows examples of how Common Lisp is best used. Illustrates and compares features of the most popular Common Lisp systems on ...
AutoLisp源文件--标注高程.LSP
practical common lisp.pdf 实用Common.Lisp编程 英文版
ANSI Common Lisp 中文翻译版.pdf
这本《Practical Common Lisp》之所以号称Practical,正是因为这本书大量介绍Common Lisp在现实世界中的各种应用方式,算是第一本「入世传教」的Common Lisp著作。《Practical Common Lisp》是目前最畅销的Common ...
Autocad的课件——AutoLISP-Visual-LISP教程.ppt
Practical Common Lisp 学习lisp的入门书籍
practical common lisp英文版mobi for kindle https://github.com/akosma/PracticalCommonLisp_ePub
lisp解密程序-适用于早期的Lisp程序
内含ANSI Common Lisp+On Lisp+实用Common Lisp编程,带书签
Apress原始PDF印刷版本,页面比较精细,适合打印了看。pdf大小约17M,用7z压缩后约为7M。
计算多个数字之和、计算多条线段长度之和、插入墙高标注、查询多段线顶点坐标并绘制、自动生成页码、绘制示坡线、插入排水箭头 https://blog.csdn.net/qq_24141055/article/details/121446354
这本《Practical Common Lisp》之所以号称Practical,正是因为这本书大量介绍Common Lisp在现实世界中的各种应用方式,算是第一本「入世传教」的Common Lisp著作。《Practical Common Lisp》是目前最畅销的Common ...
NULL 博文链接:https://jamsa.iteye.com/blog/1188836
Common-Lisp-Actors, 通用Lisp的actor系统 这是一个简单且易于使用的Actor系统,在。设置需要波尔多螺纹。http://common-lisp.net/project/bordeaux-threads/ 2. 加载 actors.lisp 并开始使用它。 如果你有 Quick
If you’re interested in Lisp as it relates to Python or Perl, and want to learn through doing rather than watching, Practical Common Lisp is an excellent entry point. — Chris McAvoy, Chicago Python ...