Lisp.多值(Multiple values)

来源:互联网 发布:vb如何删除非打印字符 编辑:程序博客网 时间:2024/06/06 05:23

有人曾经说过,为了强调函数式编程语言的重要性,都要说每个Lisp表达式都返回一个值。现在事情没有那么简单了;在Common Lisp中,一个表达式可以返回0个或多个值。返回值的最大个数根据实现的不同而不同。


多值允许函数计算并返回几个东西,并且不需要建立一个结构来保存它们。比如,内置的函数get-decoded-time返回当前的时间,这个时间用9个值来表示:秒,分钟,小时,日期,月,日,还有其它两个东西。


多值也是的我们在写函数的时候可以区分找到nil和找不到一些东西的情况。这也就是为什么gethash返回两个值。因为它使用第二个值来标识是成功或是失败,我们可以在一个哈希表表中存储nil,就像是存储其它值一样。


函数values返回多值。他就是返回了你传递给它的参数:

[30]> (values 'a nil (+ 2 1))A ;NIL ;3

如果一个values表达式是一个函数中最后被求值的,那么它的返回值也就变成这个函数的返回值。多值在多个返回中被完整地传递:
[32]> ((lambda () ((lambda () (values 1 2)))))1 ;2

然而,有时候只需要一个值,除了第一个外其它的都要被舍弃掉:

[33]> (let ((x (values 1 2))) x)1

不给values任何参数,它可能不会返回任何值。这种情况下,如果你想从中获取一个值,你就会获得nil:

[36]> (values)[37]> (let ((x (values))) x)NIL

要想接收到多值,我们使用multiple-value-bind函数:

[39]> (multiple-value-bind (x y z) (values 1 2 3) (list x y z))(1 2 3)[40]> (multiple-value-bind (x y z) (values 1 2) (list x y z))  (1 2 NIL)

如果变量比值多,那么多出来的就是nil了。如果值比变量多,那么多于的值就会被丢弃掉。所以如果我们想只打印时间,我们就可以这样写:

[42]> (multiple-value-bind (s m h) (get-decoded-time) (format nil "~A:~A:~A" h m s))"16:5:4"

你可以通过multiple-value-call将多值应用到第二个函数上:

[43]> (multiple-value-call #'+ (values 1 2 3))6

还有一个函数:multiple-value-list:

[44]> (multiple-value-list (values 'a 'b 'c))(A B C)

其实这和调用multiple-value-call,将其第一个参数设置为#'list是一样的效果。