探索JVM上的LISP - 编程入门网
仅返回lambda的函数也是有可能的,经典教科书中的例程会这样写:
上面的语句都做些什么事情呢?首先定义了一个名为make-adder函数,它带有一个参数a,返回一个匿名函数,该匿名函数要接收另外一个参数b。当调用发生时,匿名函数会计算a与b的和。 执行(make-adder 2)——或者通俗的说“给我一个函数,可以把2加到传给它的参数上”,REPL将显示一些代码,它实际上是把lambda过程作为一个字符串打印出来,要用这个函数你还可以这样写:
此处最为重要的事情在于lambda作为一个闭包执行。把它“封装”起来,保持它被创建时对作用范围内变量的引用。(make-adder 3)调用后,作为返回结果的lambda保有a的值,当(add-3 2)执行时,它计算3+2的值,并返回预期的5。 探索JVM上的LISP(3)时间:2011-01-27 infoq 译:张凯峰宏(MACROS) 到目前为止所看到的特性都和我们在比较新的动态语言中发现的相类似,例如Ruby,它也允许你使用匿名块处理对象收集,正如我们在前面用lambda和map函数所做的一样。所以,现在让我们来转变一下方向,看看独属于Lisp的特性:宏(macros)。 Scheme和Common Lisp都有宏系统。人们在提到Lisp时总说它是“可编程的程序设计语言”,其实指得就是这个。有了宏,你实际上就可以和编译器建立关联,重新定义语言本身。此时Lisp统一的语法才真正开始挥效用,所有的事情都变得有趣起来。 举个简单的例子,我们可以看一下循环。在Scheme语言中,最初并没有定义循环,典型的对某集合进行迭代的方式是使用map或者递归函数调用。多亏有一个编译器小窍门——尾调用优化递归(tail-call optimizations recursion)——可以采用而不必担心会挤爆栈。下面将介绍一个非常灵活的do命令并应用它来执行一个循环,实现的程序如下:
上面程序中定义了一个索引变量i,初始化为0,设置按照增量1迭代增长。当表达式(= i 5)的值为真时,循环中止,返回#t(它和Java中的布尔值true相当)。在循环里我们只是打印了一个字符串。 如果我们所需要做的只是一个简单的循环,上面这个例子就有很多冗余的公式化代码了。在很多情况下更可取的应当是简单直接的实现方式:
多亏了宏(macros),才有可能适当地使用称为define-syntax函数,把关于dotimes的特殊语法添加进语言:
执行上述命令可以告诉系统,任何对dotimes的调用都要被特别对待。Scheme将用我们定义的语法规则匹配一个模式,并在将结果送到编译器之前将其展开。在这个例子中,模式是(dotimes count command),它被转换为标准的do循环。 在REPL中执行该语句,你会得到如下结果:
上述例子之后必然产生两个问题。第一,为什么我们需要使用宏(macro)?用一个常规的函数不能做这些事情么?答案是“不可以”。任何对函数的调用实际上在开始之前都会触发对它所有参数的求值操作,在上面的例子中就不会发生这种情况。比方说,你怎样处理(do-times 0 (format #t |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |