内容


使用 Cusp Eclipse 插件开发 Lisp 应用程序

Lisp 不再只适用于人工智能 —— 试试它,您可能会用不同的方式思考 Java 和 C 编程

Comments

Cusp,Lisp 的 Eclipse 开发环境

Cusp 是 Common Lisp 编程语言的开发环境。使用 Lisp 可以开发所有类型的应用程序,包括 Web 应用程序。Lisp 是目前仍在使用的第二种最古老的编程语言(在 Fortran 之后)并被称为第一种函数语言。Lisp 的创建开始于二十世纪五十年代后期,并且于 1958 年由 MIT 人工智能 (AI) 项目首次实现。它的强大之处在于处理列表:AI 和符号数学。实际上,Lisp 是 “list processor” 的简写,正是出于对列表处理器的需求创建了这种编程语言,您将在稍后的段落中看到相关说明(有关 Lisp 的历史信息,请参阅 参考资料)。

您将会发现 Lisp 与其他普通的编程语言根本不同。例如,在大多数普通编程语言中,执行乘法就像您在纸上作运算一样:int times = 5 * 5;。

使用 Lisp,将通过代码 (* 5 5 3) 得到 75。要获得此列表中的最大值,使用 (MAX 9 8 7 6 20) 将返回 20。

注意,这里所说的 “第一种函数语言” 十分贴切,因为一切都基于函数。每个函数都可以有若干数目不定的参数。使用递归和诸如 carcdr 之类的 Lisp 函数处理这些列表是使用 Lisp 处理列表的强大之处。

由于 Lisp 历史较久,因此您可以找到许多适用于 Lisp 的开发环境,但是,也存在旧编程语言固有的问题,工具支持大部分都是基于文本的,并且对于新手来说不够直观。因此,尝试使用 Cusp 的一个原因是它提供了供新手了解和开发 Lisp 的直观 GUI,而不使用基于文本的 “尝试记住所有这些命令” 类型的界面。它还比 Eclipse GUI 框架固有的 superb 项目管理功能更具优势。

继续之前,您需要从 Eclipse.org 下载最新的 Eclipse 标准包。然后了解如何安装和设置 Cusp。

安装 Cusp

现在应当有一个经过压缩的 Eclipse 标准包归档。请将其解压缩并运行 eclipse.exe。

要获得最新版本的 Cusp,请单击 Help > Software Updates > Find and Install。单击 Search for new features to install 选项。现在单击 New Remote Site 按钮。键入名称 Cusp update site 和 URL http://www.sergeykolos.com/cusp/update,然后单击 OK(参见图 1)。

图 1. 为 Cusp 输入远程站点信息
为 Cusp 输入远程站点信息
为 Cusp 输入远程站点信息

单击已添加的新远程站点旁边的复选框并单击 Finish(参见图 2)。

图 2. 选择 Cusp Eclipse Update Site
选择 Cusp Eclipse Update Site
选择 Cusp Eclipse Update Site

系统将显示另一个窗口,在该窗口中需要展开 Cusp Eclipse Update Site 并选择 Cusp,如下所示:

图 3. 选择要安装的功能
选择要安装的功能
选择要安装的功能

单击 Next。然后阅读许可证协议并单击 I accept the terms in the license agreement 接受许可证协议,然后单击 Next。确保选中所有库,如下所示,然后再次单击 Next

图 4. 选择可选功能
选择可选功能
选择可选功能

最后一个页面将显示要安装功能的安装汇总。单击 Finish。插件及其组件将下载并安装。下载后,您将收到一则警告,表明将要安装一个未签名的功能。单击 Install all。在安装结束时,系统将询问您是否要重新启动 Eclipse;请单击 Yes

您已经安装了 Eclipse Cusp 插件。接下来,将创建一个 Lisp 项目。

创建 Lisp 项目

在开始进行 Lisp 开发之前,必须先创建一个新的 Lisp 项目。您可以通过转到 File > New > Project 来完成此操作。展开 Lisp 文件夹,单击 Lisp Project,然后单击 Next。为新项目选择一个名称 my_new_lisp_project,如下所示,然后单击 Finish

图 5. 命名新 Lisp 项目
命名新 Lisp 项目
命名新 Lisp 项目

单击 Finish 后,将创建新项目并打开 Lisp 透视图,如下所示:

图 6. Lisp 透视图
Lisp 透视图
Lisp 透视图

查看 Lisp 透视图。Lisp Navigator 窗口显示打开的项目及其相关文件。Outline 窗口显示当前打开文件的概要。位于右上侧显示 main.lisp 的窗口是 Lisp 开发窗口。位于右下侧的窗口 REPL 是 Lisp 的命令行 Lisp 解析程序,您可以在这里运行 Lisp 命令。

如果关闭并重新打开 Eclipse,则需要装入项目的 .asd 文件,如下所示:

图 7. 装入 ASD 文件
装入 ASD 文件

注意,需要在 my_new_lisp_project 文件夹下的 my_new_lisp_project.asd 文件上右键单击,然后选择 Load asd。这实际上就是在 REPL 窗口中编译 Lisp 项目,允许您输入可以使用新代码的 Lisp 命令。

接下来,将尝试使用 Cusp 进行一些 Lisp 开发。

使用 Cusp 进行 Lisp 开发

首先,还是定义并测试一个简单的自定义函数。打开 main.lisp 文件,并使用 defun(定义函数)命令,然后添加以下内容:

...
(defun first_howdy_function ()
  "howdy ho")

保存该文件。要从包中导出函数,请在 defpackage.lisp 中键入以下代码:

...
   ;; Exported symbols go here
  first_howdy_function
   ))

可以从包的外部使用该函数。要测试新函数,请在 REPL 中位置靠下的窗口中键入以下代码:(my_new_lisp_project:first_howdy_function)

注意,在您所处的范围内,这样做与输入 (my_new_lisp_project::first_howdy_function) 等效。如果未在 defpackage.lisp 中导出函数,则这是您必须键入的代码。

单击 Send,然后查看输出。输入上面任意一条命令所得到的输出都是:

COMMON-LISP-USER>
(my_new_lisp_project:first_howdy_function)

"howdy ho"

您已经得到它了:第一个 Lisp Howdy 函数。

尝试为 echo 函数提供一个输入:

...
(defun first_echo_function (echoval)
  echoval)

同上一个函数一样,将其导出到 defpackage.lisp 中。在 REPL 窗口中位置靠下的部分中键入以下代码 (my_new_lisp_project:first_echo_function '("howd" "y h" "o")) 来测试这个 first_echo_function。注意,'("howd" "y h" "o") 部分是用于定义列表的语法。首先,单引号必须放在括号之前,然后在括号内定义列表元素。输出如下所示:

COMMON-LISP-USER>
(my_new_lisp_project:first_echo_function '("howd" "y h" "o"))

("howd" "y h" "o")

您将创建一种分别处理每个列表元素的方法,这是 Lisp 的真正强大之处。定义如下:

(defmethod concat2 ((str1 string) (str2 string))
  (concatenate 'string str1 str2))

注意,以上方法实际上定义了一个类型字符串。到现在为止,您一直在使用 Lisp 作为一种大型的无类型语言。虽然双引号隐式地把数据类型定义为字符串,但是以上方法显式地把 concat2 函数的输入和输出类型定义为字符串。此方法还使用内置的 concatenate 函数把两个字符串组合在一起,并将其作为单个字符串返回。

要测试 concat2,请将其导出,然后键入 (my_new_lisp_project:concat2 "howd" "y ho")。输出如下:

清单 7. 连接两个字符串的输出
COMMON-LISP-USER>
(my_new_lisp_project:concat2 "howd" "y ho")

"howdy ho"

完成。字符串 "howd""y ho" 变成 "howdy ho"。现在您将使用两个著名的 Lisp carcdr 函数创建更通用化的 concatenation 函数。

清单 1. 连接列表中的三个元素
(defun concat3 (args_list)
  (concat2 (car args_list)
           (concat2 (car (cdr args_list))
                    (car (cdr (cdr args_list))))))

注,此函数仍使用 concat2 函数,但是使用参数列表作为输入。注意如何从 args_list 检索连接的各个部分。car 将从列表中获取第一个元素。cdr 将返回减去第一个元素的列表。只需对列表调用 car 函数就可以看到如何获得第一个元素。获得第二个元素要求对列表调用 cdr,然后对新列表调用 car。通过对列表两次调用 cdr 并对得到的列表调用 car 获取第三个元素。

导出后以上函数的输出为:

COMMON-LISP-USER>
(my_new_lisp_project:concat3 '("howd" "y h" "o"))

"howdy ho"

就是这样。已正确连接了三个字符串来生成 "howdy ho"。接下来,创建递归函数。

使用 Lisp 递归

将要创建的最后一个函数要执行一些递归操作,这是使用 Lisp 进行列表处理的真正强大之处。迭代是可能实现的(逐个遍历所有条目),但是不同于诸如 Java 语言之类的普通语言,递归是到现在为止 Lisp 中处理列表的最简单方法。在本节的末尾,您将明确了解递归的含义。

首先创建递归的 concat 函数。

清单 2. 递归连接(无限制的参数)
1   (defun concat_recursive (args_list)
2     (if (equal (cdr args_list) nil)
3         (car args_list)
4         (concat2 (car args_list)
5                  (concat_recursive (cdr args_list)))))

递归是十分难于处理的概念,因此让我们一起来查看这个概念:

  • 假定将任意参数列表传递给上面的函数。
  • 如果列表中只有一个元素(第 2 行中的 (cdr args_list) 部分返回 nil),则返回单个元素(第 3 行中的 (car args_list))。
  • 如果列表中有多个元素(意味着第 2 行中的 (cdr args_list) 部分未返回 nil),则返回使用 (cdr args_list) 的结果作为参数(参见第 5 行)连接(使用 concat2)列表的第一个元素(参见第 4 行)与递归调用 concat_recursive 的结果的结果。

当传递列表 '("ho" "wd" "y" "h" "o") 作为参数时,下面是递归输出:

  • 第一次执行到第 2 行时,if 语句为 false,并用 "ho"(concat_recursive '("wd" "y" " h" "o")) 调用 concat2
  • 第二次执行到第 2 行时,if 语句又为 false,并用 "wd"(concat_recursive '("y" " h" "o")) 调用 concat2
  • 第三次执行到第 2 行时,if 语句又为 false,并用 "y"(concat_recursive '(" h" "o")) 调用 concat2
  • 第四次执行到第 2 行时,if 语句又为 false,并用 " h"(concat_recursive '("o")) 调用 concat2
  • 第五次递归结束。这是因为这一次,第 2 行中的 if 语句现在为 true,并且简单地返回了 "o"。递归解开为:
    • 第四次:连接并返回 "h""o"
    • 第三次:连接并返回 "y""ho"
    • 第二次:连接并返回 "wd""y ho"
    • 第一次:连接并返回 "ho""wdy ho" 作为最终结果。

这时就完成了递归 —— "howdy ho" 最终被返回,如下所示:

COMMON-LISP-USER>
(my_new_lisp_project:concat_recursive '("ho" "wd" "y" " h" "o"))

"howdy ho"

已经将递归添加到了 Cusp 开发工具库中。接下来请尝试调试器。

使用 Cusp 进行调试

考虑输入条件可能会导致 concat_recursive 失败,因此调试器可能会派得上用场。一种情况是可以发送一个混有数字的字符串来查看会发生什么情况。记住,使用 concat2 进行连接要求使用两个字符串,因此数字将导致此函数在递归之间中断。

键入以下命令:(my_new_lisp_project:concat_recursive '("ho" "wd" "y" 55 " h" "o"))。注意没有用双引号引起的数字 55 不是字符串并将导致显示调试器,如下所示:

图 8. 触发调试器
触发调试器
触发调试器

注意,触发调试器的主要错误是无法对列表 (55 " ho") 调用 concat2。另请注意,在触发该错误之前已经连接了 "h""o"

在调试器窗口中,您还可以看到 ==Backtrace==,如图 8 所示。调试器下部的每行(本例中为 0 至 19 行)给出了从单击 Send 到发生错误的详细跟踪。在这里,您还可以查看并跟踪在触发了错误的数字 55 之前的递归。

现在做什么?遇到上面的情况,您有三种选择退出调试器并修改和验证函数输入:可以中止命令并返回到正常的 REPL 窗口;可以关闭连接(通过测试发现,如果选择此选项,则需要重新引导 Eclipse 来重新启动 Lisp 处理器);可以简单地中止调试器并返回到正常的 REPL 窗口。退出调试器的最佳选项始终是中止命令并返回到正常的 REPL 窗口。

就是这样。您已经在 Lisp 中实现了递归函数。

结束语

您已经成功地使用 Cusp Eclipse 插件完成了 Lisp 开发。现在应当知道 Lisp 为什么如此强大。通过简单的递归语句,可以轻松地推动处理符号和数据列表。Cusp 为 Lisp 的功能补充了内置 Cusp 调试器、拥有项目管理功能的可靠 GUI、交互式 Lisp 编辑器以及可以输入命令和测试代码的 Lisp 处理器命令行接口。要获得更多信息,请一定要查看 参考资料


下载资源


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Open source
ArticleID=271180
ArticleTitle=使用 Cusp Eclipse 插件开发 Lisp 应用程序
publish-date=11262007