Lisp.函数参数

将函数看做数据意味着,我们可以将它们作为参数传递给其它函数。这种能力是Lisp自下而上编程非常重要的一部分。


一个允许函数作为数据对象的语言必须提供一些调用它们的方式。在Lisp中,这个函数就是apply。通常,我们向apply传递两个参数来调用它:一个函数,和这个函数所需的一个参数的列表。下面的4个表达式具有相同的效果:

(+ 1 2)

(apply #'+ '(1 2))

(apply (symbol-function '+) '(1 2))

(apply #'(lambda (x y) (+ x y)) '(1 2))


 在Common Lisp中,apply可以接受任意数量的参数,第一个是给出的函数,剩下的参数将加入到最后一个给出的列表中,然后应用到这个函数上。所以下面的表达式

[4]> (apply #'+ 1 '(2))
3

和前面的四个是等价的。如果不方便以列表的形式给出参数,我们可以使用funcall,它和apply也仅仅就是这点不同。这个表达式

[4]> (funcall #'+ 1 2)
3

和上面的有相同的效果。


很多内置的Common Lisp函数接受函数参数。其中最常用的就是映射函数。比如,mapcar接受两个或多个参数,一个函数和一个或者多个列表(一个参数对应一个),在每个列表的的元素上应用这个函数:

[1]> (mapcar #'(lambda (x) (+ x 10)) '(1 2 3))
(11 12 13)
[2]> (mapcar #'+ '(1 2 3) '(10 100 1000))
(11 102 1003)
[3]>

Lisp程序员经常想要对一个列表的每个元素做些事情并返回一个列表的结果。第一个例子反应了通常的做法:做一个函数来做你想做的事情,将它mapcar到列表上。


我们已经看到能够将函数看做数据给我们带来的方便。在许多语言中,即使我们能够将函数作为参数传递给类似于mapcar的东西,它也需要在前面的一些源文件里有一个函数定义。如果只有一段代码需要将列表中的每个元素增加10,我们也需要定义一个函数,叫做plus_ten或者类似于它的东西,仅仅就是为了这点事情。通过lambda表达式,我们可以直接引用函数。


Common  Lisp和它前面的方言们的最大的不同之处之一就是大量的接收函数参数的内置函数。在到处都是的mapcar之后,两个最常用的,就是sort和remove-if。前一个是通用的排序函数。它接收一个列表和一个谓词,并通过将每对元素传递给谓词来返回一个排序的列表。

[4]> (sort '(1 4 2 5 6 7 3) #'<)
(1 2 3 4 5 6 7)

要记住sort是怎样工作的,你可以记住如果你用<排序了一个列表,fran后对这个列表应用<,它将返回真。


如果remove-if不包含在Common Lisp中,这有可能是你写的第一个工具。它接收一个函数和一个列表,返回那些使函数返回假的元素。

[5]> (remove-if #'evenp '(1 2 3 4 5 6 7))
(1 3 5 7)

作为接收函数参数的函数的例子,这里是一个残缺的remove-if的定义:

[5]> (defun our-remove-if (fn lst)
(if (null lst)
nil
(if (funcall fn (car lst))
(our-remove-if fn (cdr lst))
(cons (car lst) (our-remove-if fn (cdr lst))))))
OUR-REMOVE-IF
[5]> (our-remove-if #'evenp '(1 2 3 4 5 6 7))
(1 3 5 7)
[5]>


注意,在这个定义中fn并没有井号-单引号前缀。既然函数是数据对象,一个变量可以将一个函数作为常规值。这就是这里发生的事情。井号-单引号仅仅是饮用一个符号代表的函数——通常是通过使用defun定义的全局函数。


正如第四章将要展现的,写接收函数参数的工具是自下而上编程的一个重要因素。Common Lisp非常可能已经有你需要的工具了,因为它有太多的内置工具了。但是不管你是使用注入sort的内置函数,或者是写你自己的工具,原则是一样的。不要写死函数,而是要把函数作为参数传递。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值