目录
newLISP — 交互式教程
Hello World!
代码和数据是可以互换的
函数的参数
副作用和 Contexts
表达式序列
可执行文件和动态链接(Executables and Dynamic Linking)
在 OSX, Linux 或其他 UNIX 系统:
在 Windows 系统上目标文件需要 .exe 后缀
绑定(Binding)
List 是一种递归结构
函数(Functions)
高阶函数
lambda 列表
动态范围(Dynamic Scope)
函数参数列表
宏
Contexts
局部作用域(Lexical Scope)
这份文档于 2006 年 5 月被 Rick Hanson (cryptorick@gmail.com) 做了一些修正和更新后被转换成 html 文档。2008 年 12 月被 L.M 更新到 v.10.0 版本. 版权所有 John W. Small 2004。
你可以到 newLISP 官方网站 www.newLISP.org 下载和安装这门语言.
关于这个教程的任何意见和问题请发邮件到 jsmall@atlaol.net 。
中文版翻译时 newLISP 的版本已经到了 10.6 这和当时撰写文档的时候,已经相隔甚远。一些内置函数的名称发生了变化,语言的功能也扩展了很多。我根据实际的情况修改了相应的章节,这样所有的代码就都可以在新的版本上进行测试运行了。
中文翻译:宋志泉(ssqq) QQ: 104359176 电子邮件:perlvim@gmail.com
在你的系统上安装 newLISP 之后, 在 shell 命令行下输入 newlisp 就可以启动 REPL (读取,计算,打印循环).
在 Linux 系统中,你的界面看起来像这样:
如果是在 Windows 平台上,它会是这个样子:
在 REPL 启动后,newLISP 会出现一个响应输入的提示:
在下面的提示中输入如下表达式,就可以在屏幕上打印出 “Hello World!“.
newLISP 打印出输入在 REPL 中提示符后的表达式结果,并等待下一次输入.
为什么会打印出两次呢?
函数 println 的执行结果在屏幕上打印出第一行:
函数 println 然后返回字符串 “Hello World!“. 这是它最后一个参数,会返回给 REPL, REPL 会把它显示在屏幕上,这是第二行的由来。
REPL 会计算任何表达式,不单单计算函数.
如果你输入上面的表达式 "Hello World!", 它只是返回表达式本身,如果输入数字结果也是一样.
现在你可能会想,成对的括号怎么没用到呢?如果你以前使用主流的计算机语言,像下面的函数调用看起来是不是更自然一点:
我相信过段时间你会喜欢下面的写法:
而不是:
因为一些原因,不能详细解释,等到你看到更多的关于处理列表和符号的 newLISP代码后,也许就会明白。
Lisp 的本意是列表处理(List Processor). Lisp 使用 lists 同时表示代码和数据,它们彼此之间是可以互相转换的。
以前的 println 表达式是一个真正的拥有两个元素的列表。
第一个元素是:
第二个元素是:
Lisp 总是会将列表作为函数调用进行执行,除非你引用它,从而表明它只是一个字面形式的符号表达式,也就是 – 数据。
一个符号表达式可以再次被当成代码运行,比如:
Lisp 程序可以在运行时构建数据的字面量,然后执行它们!
通常单引号 ' 是引用 quote 简写形式.
你可以想象引用 quote 将它的参数当成字面量返回, 也就是符号化参数.
符号,例如上面的 x 和 three, 还有符号列表(symbolic lists)在人工智能领域起着举足轻重的角色。这个教程不会探讨人工智能,但是一旦你学会用 Lisp 编程,你将能明白许多人工智能的教科书的 Lisp 的代码含义了。
让我们看看下面的例子:
符号 'Hello 和字符串字面量 "Hello" 不同. 现在你就会明白为什么在 REPL 中使用双引号来标注一个字符串,这样是为了和有着相同字母的符号进行区分。
println 函数可以拥有任意个数的参数。
上面的代码中,参数一个接一个的合并后,输出到屏幕,最后一个参数的值作为函数的返回值进行返回给 REPL。
通常,参数是从左到右进行计算的,然后将结果传递给函数。传递给函数的参数可以说被完全的计算过了,这就是大家所说的应用序求值(applicative-order eva luation).
但是请注意,函数 quote 并不是这样.
如果它的参数是这个:
如果它被完全解释后传递,我们将会在屏幕上看到:
事实并不是这样,函数 quote 是一种特殊的函数,通常被称为特殊形式函数 “special form”.
你可以在 newLISP 中设计自己的特殊形式函数,这种函数叫做宏(macro), 它的参数能以字面量被调用。这就是正则序求值(normal-order eva luation),我们说这种顺序是惰性的。也就是说,一个宏的参数在传递过程中并不会被直接计算(我们将在下面了解具体情况)。
因此,函数 quote 将参数按字面量传递并返回。在某种意义上,引用 quote 代表了典型的惰性计算原则。它并不对参数做任何运算,只是单单的按照字面量返回它。
如果没有特殊形式函数,其他函数中的流程控制,是不能在只有列表语法的语言中实现的。例如,看看下面的 if 函数.
特殊形式函数 if 接受三个参数:
参数 condition 总是被完全的计算,但参数 consequence 和 alternative 的表达式是惰性的。因为参数 alternative 的表达式可能根本不需要计算.
请注意 if 这个表达式. 它返回的值到底是 consequence 还是 alternative, 依赖于 condition 是真还是假. 在以上的例子中,alternative 表达式没有后被计算,因为打印到屏幕 “Goodbye” 的副作用永远都不会出现.
如果一个 if 表达式的条件 condition 表达式测试为假,但又没有 alternative 语句,那么它就会返回 nil. nil 的意思根据不同的环境可能解释为空值(void)或假(false).
注意:在大多数主流计算机语言中,if 只是一个语句,并不会产生返回值。
如果 Lisp 缺乏这个惰性计算特性,它就无法用来实现特殊形式函数或宏(macro)。如果没有惰性计算,大量额外的关键字 and/or 语法就会不得不加入到语言中。
直到现在,你看到几种语法?括号和引用?哦,似乎有点少!
惰性计算带给你的就是,我们自己可以在语言中添加个性化的流程控制方式,来扩展这门语言,订制自己的专用语言。函数和宏的书写将在本教程的后面部分。