首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Lisp 之美更新

Lisp 之美更新

构建函数可以猜到,Lisp 函数声明为列表。清单 7 构建了一个返回列表第二个元素的函数,展示了函数声明的形式:
清单 7. 构建第二个函数
1
2
3
(defun my_second (lst)
  (first (rest lst))
)




defun 是用于定义自定义函数的函数。第一个参数是函数名,第二个参数是参数列表,第三个参数是希望执行的代码。可以看出,所有 Lisp 代码都表述为列表。借助这项灵活和强大的功能,就可以像操纵其他任何数据一样操纵应用程序。稍后将看到一些示例使代码和数据之间的区别变得模糊。
Lisp 也处理条件结构,如 if 语句。格式为 (if condition_statement then_statement else_statement)。清单 8 是一个简单的 my_max 函数,用于计算两个输入变量中的最大值:
清单 8. 计算两个整数中的最大值
1
2
3
4
5
6
7
8
9
10
11
(defun my_max (x y)
  (if (> x y) x y)
)

MY_MAX
(my_max 2 5)

5
(my_max 6 1)

6




下面回顾一下到目前为止看到的内容:
  • Lisp 使用列表和原子来表示数据和程序。
  • 对列表求值时将第一个元素看作列表函数,将其他元素看作函数参数。
  • Lisp 条件语句将 true/false 表达式和代码一起使用。
递归Lisp 提供用于迭代的编码结构,但递归是更受欢迎的列表遍历方式。使用 first 和 rest 组合实现递归效果很好。清单 9 中的 total 函数显示了其运行原理:
清单 9. 使用递归计算列表的总和
1
2
3
4
5
6
7
8
9
10
11
>(defun total (x)
  (if (null x)
    0
    (+ (first x) (total (rest x)))
  )
)

TOTAL
>(total '(1 5 1))

7




清单 9 中的 total 函数将列表当作单个的参数。第一个 if 语句在列表为空的情况下中断递归,返回零值。否则,该函数将第一个元素添加到列表其余部分的总和。现在应该明白如此构建 first 和 rest 的原因。first 能够去除列表的第一个元素,rest 简化了将尾部递归 (清单 9 中的递归类型)应用于列表其余部分的过程。
由于性能的原因,Java 语言中的递归是有限的。Lisp 提供一项称作尾部递归优化 的性能优化技术。Lisp 编译器或解释器能够将特定形式的递归翻译为迭代,从而允许以一种更为简单明快的方式来使用递归数据结构(如树结构)。
高阶函数如果模糊了数据和代码之间的区别,Lisp 会更有意思。在本系列的前两篇文章中,介绍了  和 。这两项功能都将函数作为参数进行传递。在 Lisp 中,由于函数和列表没有任何区别,高阶函数也就非常简单。
高阶函数的最常见用法或许是 lambda 表达式,这是闭包的 Lisp 版。lambda 函数是用于将高阶函数传入 Lisp 函数的函数定义。例如,清单 10 中的 lambda 表达式计算了两个整数的和:
清单 10. Lambda 表达式
1
2
3
4
5
6
7
8
>(setf total '(lambda (a b) (+ a b)))
(LAMBDA (A B) (+ A B))

>total
(LAMBDA (A B) (+ A B))

>(apply total '(101 102))
203




如果使用过高阶函数或闭包,那么可能更容易理解清单 10 中的代码。第一行代码定义了一个 lambda 表达式并将其和 total 符号绑定到一起。第二行代码仅显示了这个和 total 绑定到一起的 lambda 表达式。最终,最后一个表达式对包含 (101 102) 的列表应用这个 lambda 表达式。
高阶函数提供比面向对象概念更高层次的抽象。可以用它们来更简洁清晰地表达想法。编程的至高境界就是在不牺牲可读性或性能的前提下,用更少的代码提供更强大更灵活的功能。高阶函数能实现所有这些要求。
Lisp 还有两种类型的高阶函数。其中功能最强大的可能是。宏为后面的执行定义 Lisp 对象。可以将宏看作代码模板。请参考清单 11 中的示例:
清单 11. 宏
1
2
3
4
5
6
7
8
>(defmacro times_two (x) (* 2 x))
TIMES_TWO

>(setf a 4)
4

>(times_two a)
8




这个示例应该分为两个阶段进行阅读。第一次赋值定义了宏 times_two。在第二个阶段(称为宏扩展)中,在对 a 求值之前,将 a 扩展为 (* 2 a)。该模板中这项延迟求值方式使宏的功能非常强大。Lisp 语言本身的许多功能都是基于宏的。
结束语从年份上讲,Lisp 也许很陈旧,甚至语法也很陈旧。但如果稍作研究,就会发现该语言有着难以置信的强大功能,它的高阶抽象一如既往地有效,并且生产力很高。许多更为现代的语言从 Lisp 中得到借鉴,但是其中大多数语言的功能无法与 Lisp 媲美。如果 Lisp 拥有 Java 或 .NET 的一部分市场,并且大学中具备 lisp 知识的人也占有一定的比例,我们可能就会立即用它进行编码。
返回列表