Icon 初探
Linux 用户是新技术的早期采用者,因此许多 Linux 社区的成员希望为给定的应用程序使用最佳编程语言,而不是局限于一种语言,这并不令人意外。本文的目的是向您介绍一种最简单且功能最强大的编程语言。它叫做 Icon,是一种为热爱编程的人设计的语言。本教程是一个“预告片”,旨在激发您的好奇心;1998 年 4 月号的 Linux Gazette 刊登了一篇更长的教程,其中更详细地介绍了此处描述的功能。
语言是宗教战争的主题;通过“证明”一种语言比另一种语言更好的论点几乎毫无收获。Icon 并非完美,也不是“最好”的语言,但它是一种非常不错的语言。Icon 适用于不想处理 C 或 C++ 中的内存管理的人;适用于想要 Perl 的强大功能及更进一步,但更喜欢更简洁的表达式语法和更少特殊情况的人;以及适用于需要丰富的数据结构和算法,但认为他们在学校学到的所有编程构建块都是理所当然的人。Icon 用于儿童游戏、经文分析、CGI 脚本、编译器研究、文学编程、系统管理和可视化。在许多方面,它都是 BASIC 应该成为的样子,以及 Perl 和 Java 本可以成为的样子。(如果您知道任何语言可以为本文给出的三个简短、完整的程序示例提供更简单、更直接的解决方案,请告诉我们。)
Icon 的基本理念是使编程变得容易。它的语法类似于 C 或 Pascal;程序由过程组成,从 main 开始。Icon 内置的列表和表格数据类型优于大多数语言:其他语言具有类似的类型,但运算符和语义似乎没有那么好。这两种类型都使用熟悉的下标表示法,保存任何类型的值,并根据需要增长或缩小。列表代替了数组、堆栈和队列。表格将任何类型的键与相应的值关联起来。这些类型的实现非常巧妙;例如,列表在使用时就像数组,在使用时就像链表。
尽管 Icon 与 C 或 FORTRAN 相比有一些奇特的概念,但在某些方面,Icon 程序更具可读性,而不仅仅是更短。例如,当它们为“真”时,关系运算符返回右操作数的值,并从左到右关联,因此 (12 < x < 20) 测试 x 是否在 12 到 20 之间。
这是一个简单的示例程序,它计算命令行上给出的每个单词的出现次数,并将单词及其相应的计数按字母顺序写出。创建一个表格,所有键都映射到默认值 0。然后,命令行上的每个参数都用作表格中的键来递增计数器。表格被排序,生成一个包含键及其值的两元素列表的列表。这些对一次从列表中删除一个,并将键和值写出。
procedure main(argv) T := table(0) every T[ !argv ] +:= 1 L := sort(T) while pair := pop(L) do write(pair[1], ": ", pair[2]) end
生成器是 Icon 的独特功能;它们是其计算机科学研究贡献。它们为该语言提供了更简单、更直观的表示法,因此值得进行一次思维飞跃。生成器可以产生多个值,表达式求值会尝试来自生成器的每个值,直到找到一个使封闭表达式成功并产生值的值。例如,(2|3|5|7) 是一个简单的表达式,它产生值 2、3、5 和 7;因此表达式 (x = (2|3|5|7)) 测试 x 的值是否是这四个值之一。
在之前的程序示例中,表达式 !argv 从列表 argv 中生成元素。表达式求值尝试获取一个值;every 控制结构导致产生所有值。这段代码
every i := (1 to 10) | (20 to 30) do write(L[i])
打印列表中的前十个值,然后是第 20 到 30 个元素。
生成器是编写计算一系列值的过程的一种非常自然的方式。在像 C 这样的语言中,过程必须使用静态数据来维护其调用之间的状态;在 Icon 中,这是自动完成的。这是您可能编写网络链接检查器的一种方式
every url := get_url(document) do test_url(url)
过程 get_url 扫描文档中的超链接
procedure get_url(filename) f := open(filename) | stop("Couldn't open ", filename) while line := read(f) do { ... url := ... suspend url } end在上面的示例中,get_url 只被调用一次。每次发生 suspend 时,都会为周围的表达式产生一个结果,如果周围的表达式失败,则调用会在它离开的地方恢复,即在 suspend 处。生成器是其他强大语言功能的基础(有关详细信息,请参阅 Linux Gazette 文章)。
Icon 的内置图形大约有 40 个函数,并且只引入了一种新类型,即窗口,它是文件类型的特殊扩展。这与其他语言中的图形 API 形成对比,在其他语言中,学习图形意味着学习 400 多个函数,这些函数操作几十种新的值类型。将字符串和整数传递到几个函数中是编写令人惊叹的图形而无需过多代码的全部所需。
Brad Myers 的“矩形跟随鼠标”测试是 Icon 图形的一个演示,该程序打开一个窗口,其中一个矩形在屏幕上跟随鼠标移动。窗口以 XOR 光栅绘图操作(文件模式“g”)打开,这会导致图形在重绘时自行擦除。在循环中,对于每个用户事件,十像素的正方形都会被擦除并在新的鼠标位置重新绘制。&x 和 &y 是 Icon 关键字,它们保存当前鼠标位置并保存在变量 x 和 y 中。变量 x 和 y 最初为空。如果 x 为空,则表达式 \x 失败,导致第一次循环时跳过对 DrawRectangle 的第一次调用,因为此时,没有矩形可绘制。
procedure main() w := open("win","g", "drawop=reverse") repeat { # get mouse/keyboard event Event(w) # erase old rectangle DrawRectangle(w, \x, y, 10, 10) # draw new rectangle DrawRectangle(w, x := &x, y := &y, 10, 10) } end
简单的图形编程很容易,但复杂的图形也是可能的。Icon 程序库 (IPL) 是 Icon 实用程序和库的集合,提供了一个更广泛的 Motif 风格的用户界面工具包以及一个 WYSIWYG(所见即所得)界面构建器,可让您通过绘制界面来构建界面。IPL 包含几个其他图形游戏和应用程序示例。
Unicon 风格的 Icon 添加了一组优雅的 UNIX 系统级工具。ls 实用程序的超简单版本说明了其中一些功能。此版本在命令行上接受一个目录名称,并生成文件信息列表,包括文件大小和修改时间,按名称排序。(Linux Gazette 文章中包含一个更有趣的版本。)
ls 读取目录并对其找到的每个名称执行 stat 调用。在 Icon 中,打开目录与打开文件进行读取完全相同;每次 read 都返回一个文件名。
$include "posix.icn" procedure main(argv) f := open(argv[1]) | stop("ls: ", sys_errstr(&errno)) names := list() while name := read(f) do push(names, name) every name := !sort(names) do { p := lstat(name) write(p.size, " ", ctime(p.mtime)[5:17], " ", name) } end
lstat 函数返回一个记录,其中包含 lstat(2) 返回的所有信息。在 Icon 版本中,mode 字段以人类可读的字符串形式给出,而不是您必须应用按位魔法的整数。此外,在 Icon 中,字符串操作非常自然。
试用 Icon;无论您是否是程序员,您都会喜欢它。

