Lisp与其他语言之区别 函数式编程,前缀表达式,繁多的括号,奇怪的操作符等等,这些都足以让Lisp和其他编程语言看起来有很大的区别,但是这些区别并非本质上的差异。让Lisp和其他编程语言有本质区别的是它对宏的支持。
C语言中的,被称为宏的预编译系统自有其好处,但是和Lisp中的宏比起来,好比的Notepad和Vim或者Emacs之间的差异。
数据与代码 在Lisp中,数据和代码间的差异非常小,上一篇文章简单讨论了引用的基本概念,其中对数据与代码的差异已经有所涉及。
宏(Macro) 简而言之,宏即替换,在Lisp中,可以通过程序生成代码(s-expr),而这些代码又可以被执行(当然,需要是合法的s-expr)。这一点赋予了宏无限的可能性,比如定义一个新的语法:
(defmacro only (condition &rest body) `(if ,condition (progn ,@body))) Lisp中函数macroexpand-1可以用来查看调用时宏是如何展开的:
> (macroexpand-1 '(only (> x 10) (format t "big than 10"))) (IF (> X 10) (PROGN (FORMAT T "big than 10"))) 上例中,(> x 10)被作为condition,而(format t "big than 10")作为body传递给了宏。
> (macroexpand-1 '(only (> x 10) (format t "big than 10") (format t "~%"))) (IF (> X 10) (PROGN (FORMAT T "big than 10") (FORMAT T "~%"))) 使用progn是为了让剩余的多条语句(如果有的话),逐条执行,并返回最后一条语句的值(正如在函数中那样)。...
###Common Lisp
之前一直说JavaScript是一门被误解很深的语言,现在学习了一段时间Lisp后发现,Lisp才是!Lisp一直为人所诟病的是它虽然很强大,但是有点学院派,难当大用。但是读了七,八章《Practical Common Lisp》和几章《ANSI Common Lisp》之后发现,怎么就学院派了,其他编程语言能处理的,Lisp一样可以处理,其他语言处理不了的(或者很繁琐的,比如java中的循环,map之类),Lisp却能处理。
Lisp本质上是一个抽象语法树(AST)而已,但是又提供了一些操作这个AST的方法(比如强大的宏),这样很容易用Lisp开发出来一个新的DSL。用函数式编程的好处之一就是在编写完一个应用程序之后,通常还可以获得一个新的语言(于业务领域很匹配的语言)。
Common Lisp本身是Lisp的一个方言,是有一个标准来定义,其目的是为了标准化众多的Lisp分支而定。
sbcl环境 上一篇文章已经介绍了如何在Mac下配置Common Lisp的开发环境:
引用(quote) 由于在Lisp中,数据和代码都是通过S-expr来表示,所以需要用一种标记法来告诉解释器:这个表达式表示数据/代码。这就是引用的作用:
> (+ 1 2 3 4 5) 15 > '(+ 1 2 3 4 5) (+ 1 2 3 4 5) 解释器会将s-expr的第一项作为函数(car),而将后续的元素(cdr)作为参数传递给第一项来调用,并求值。可以通过引用(quote)来阻止解释器这样解释。
反引号(`) 与引用对应的,有一个反引号形式的引用(在键盘上1的左边)。一般的用法上,它与quote的含义一样,都是防止解释器解释被引用的列表。
>`(a b c) (a b c) >`(a b (+ 1 2)) (a b (+ 1 2)) 但是,反引号引用的列表提供了重新启动求值的能力,这……,我的意思是,如上式中,如果想要将(+1 2)这个子列表求值,怎么做到呢?反引号引用提供了这个能力,用逗号(,)作为子列表的前缀即可:
>`(a b ,(+ 1 2)) (a b 3) 这个当然在此刻看起来毫无用处,或者感觉略有画蛇添足之嫌,但是在宏中,这个操作符却有很广泛的用途,这里有一个有意思的例子:
(defun foo (x) (only (> x 10) (format t "big than 10"))) 我们可以通过if来实现此处的only,当only之后的条件满足的话,就执行后续的所有语句:...